Page MenuHomeFreeBSD

D60491.diff
No OneTemporary

D60491.diff

diff --git a/sys/netlink/netlink_generic.c b/sys/netlink/netlink_generic.c
--- a/sys/netlink/netlink_generic.c
+++ b/sys/netlink/netlink_generic.c
@@ -26,6 +26,7 @@
*/
#include <sys/types.h>
+#include <sys/blockcount.h>
#include <sys/ck.h>
#include <sys/epoch.h>
#include <sys/eventhandler.h>
@@ -68,6 +69,7 @@
uint16_t family_cmd_size;
uint16_t family_num_groups;
struct genl_cmd *family_cmds;
+ blockcount_t family_busy; /* running handlers */
} families[MAX_FAMILIES] = {
[CTRL_FAMILY_ID] = {
.family_name = CTRL_FAMILY_NAME,
@@ -90,6 +92,20 @@
},
};
+/*
+ * Families, commands and groups change under the exclusive lock. Handlers
+ * run without it; family_busy counts them so that a family is not freed
+ * under a running handler.
+ */
+static struct sx sx_lock;
+SX_SYSINIT(genl_lock, &sx_lock, "genetlink lock");
+#define GENL_LOCK() sx_xlock(&sx_lock)
+#define GENL_UNLOCK() sx_xunlock(&sx_lock)
+#define GENL_SLOCK() sx_slock(&sx_lock)
+#define GENL_SUNLOCK() sx_sunlock(&sx_lock)
+#define GENL_ASSERT_LOCKED() sx_assert(&sx_lock, SA_LOCKED)
+#define GENL_ASSERT_XLOCKED() sx_assert(&sx_lock, SA_XLOCKED)
+
static inline struct genl_family *
genl_family(uint16_t family_id)
{
@@ -114,6 +130,7 @@
{
struct nlpcb *nlp = npt->nlp;
struct genl_family *gf;
+ struct genl_cmd cmd;
uint16_t family_id;
int error = 0;
@@ -125,8 +142,10 @@
}
family_id = hdr->nlmsg_type - GENL_MIN_ID;
+ GENL_SLOCK();
if (__predict_false(family_id >= MAX_FAMILIES ||
families[family_id].family_name == NULL)) {
+ GENL_SUNLOCK();
NLP_LOG(LOG_DEBUG, nlp, "invalid message type: %d",
hdr->nlmsg_type);
return (ENOTSUP);
@@ -138,28 +157,29 @@
if (ghdr->cmd >= gf->family_cmd_size || gf->family_cmds[ghdr->cmd].cmd_cb == NULL) {
NLP_LOG(LOG_DEBUG, nlp, "family %s: invalid cmd %d",
gf->family_name, ghdr->cmd);
+ GENL_SUNLOCK();
return (ENOTSUP);
}
- struct genl_cmd *cmd = &gf->family_cmds[ghdr->cmd];
+ cmd = gf->family_cmds[ghdr->cmd];
+ blockcount_acquire(&gf->family_busy, 1);
+ GENL_SUNLOCK();
- if (cmd->cmd_priv != 0 && !nlp_has_priv(nlp, cmd->cmd_priv)) {
+ if (cmd.cmd_priv != 0 && !nlp_has_priv(nlp, cmd.cmd_priv)) {
NLP_LOG(LOG_DEBUG, nlp, "family %s: cmd %d priv_check() failed",
gf->family_name, ghdr->cmd);
- return (EPERM);
- }
-
- if (cmd->cmd_securelevel > 0 &&
- securelevel_ge(nlp_get_cred(nlp), cmd->cmd_securelevel)) {
+ error = EPERM;
+ } else if (cmd.cmd_securelevel > 0 &&
+ securelevel_ge(nlp_get_cred(nlp), cmd.cmd_securelevel)) {
NLP_LOG(LOG_DEBUG, nlp, "family %s: cmd %d securelevel_gt() failed",
gf->family_name, ghdr->cmd);
- return (EPERM);
+ error = EPERM;
+ } else {
+ NLP_LOG(LOG_DEBUG2, nlp, "received family %s cmd %s(%d) len %d",
+ gf->family_name, cmd.cmd_name, ghdr->cmd, hdr->nlmsg_len);
+ error = cmd.cmd_cb(hdr, npt);
}
-
- NLP_LOG(LOG_DEBUG2, nlp, "received family %s cmd %s(%d) len %d",
- gf->family_name, cmd->cmd_name, ghdr->cmd, hdr->nlmsg_len);
-
- error = cmd->cmd_cb(hdr, npt);
+ blockcount_release(&gf->family_busy, 1);
return (error);
}
@@ -271,6 +291,8 @@
};
if (attrs.family_id != 0 || attrs.family_name != NULL) {
+ error = ENOENT;
+ GENL_SLOCK();
for (u_int i = 0; i < MAX_FAMILIES; i++) {
struct genl_family *gf = &families[i];
@@ -282,12 +304,15 @@
if (attrs.family_name != NULL &&
strcmp(attrs.family_name, gf->family_name) != 0)
continue;
- return (dump_family(hdr, &ghdr, gf, npt->nw));
+ error = dump_family(hdr, &ghdr, gf, npt->nw);
+ break;
}
- return (ENOENT);
+ GENL_SUNLOCK();
+ return (error);
}
hdr->nlmsg_flags = hdr->nlmsg_flags | NLM_F_MULTI;
+ GENL_SLOCK();
for (u_int i = 0; i < MAX_FAMILIES; i++) {
struct genl_family *gf = &families[i];
@@ -297,6 +322,7 @@
break;
}
}
+ GENL_SUNLOCK();
if (!nlmsg_end_dump(npt->nw, error, hdr)) {
NL_LOG(LOG_DEBUG, "Unable to finalize the dump");
@@ -353,13 +379,6 @@
* Public KPI for NETLINK_GENERIC families/groups registration logic below.
*/
-static struct sx sx_lock;
-SX_SYSINIT(genl_lock, &sx_lock, "genetlink lock");
-#define GENL_LOCK() sx_xlock(&sx_lock)
-#define GENL_UNLOCK() sx_xunlock(&sx_lock)
-#define GENL_ASSERT_LOCKED() sx_assert(&sx_lock, SA_LOCKED)
-#define GENL_ASSERT_XLOCKED() sx_assert(&sx_lock, SA_XLOCKED)
-
uint16_t
genl_register_family(const char *family_name, size_t hdrsize,
uint16_t family_version, uint16_t max_attr_idx)
@@ -393,6 +412,7 @@
.family_hdrsize = hdrsize,
.family_attr_max = max_attr_idx,
};
+ blockcount_init(&gf->family_busy);
family_id = genl_family_id(gf);
GENL_UNLOCK();
@@ -408,6 +428,7 @@
genl_unregister_family(uint16_t family_id)
{
struct genl_family *gf;
+ struct genl_cmd *cmds;
GENL_LOCK();
gf = genl_family(family_id);
@@ -421,8 +442,16 @@
gg->group_name = NULL;
}
}
- if (gf->family_cmds != NULL)
- free(gf->family_cmds, M_NETLINK);
+ /* Detach the commands, then wait for the handlers still running. */
+ cmds = gf->family_cmds;
+ gf->family_cmds = NULL;
+ gf->family_cmd_size = 0;
+ GENL_UNLOCK();
+
+ blockcount_wait(&gf->family_busy, NULL, "genlun", 0);
+ free(cmds, M_NETLINK);
+
+ GENL_LOCK();
bzero(gf, sizeof(*gf));
GENL_UNLOCK();
}

File Metadata

Mime Type
text/plain
Expires
Sat, Oct 10, 7:04 AM (12 h, 42 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
40520290
Default Alt Text
D60491.diff (5 KB)

Event Timeline