Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F175230751
D60491.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
5 KB
Referenced Files
None
Subscribers
None
D60491.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D60491: netlink: Wait for running handlers before a generic family is freed
Attached
Detach File
Event Timeline
Log In to Comment