Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F175288443
D60521.id189231.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
D60521.id189231.diff
View Options
diff --git a/sys/netlink/netlink_ctl.h b/sys/netlink/netlink_ctl.h
--- a/sys/netlink/netlink_ctl.h
+++ b/sys/netlink/netlink_ctl.h
@@ -102,6 +102,17 @@
uint32_t genl_register_group(uint16_t family, const char *group_name);
void genl_unregister_group(uint16_t family, uint32_t group);
+/*
+ * Per-socket storage of a family, allocated zeroed on first use by a handler
+ * of the family, which may use it until it returns. It is destroyed when
+ * the socket closes or the family is unregistered, with the generic netlink
+ * lock held: destroy() must not register or unregister anything.
+ */
+typedef void (*genl_sock_priv_destroy_t)(void *priv);
+void genl_register_sock_priv(uint16_t family, size_t size,
+ genl_sock_priv_destroy_t destroy);
+void *genl_sock_priv(uint16_t family, struct nlpcb *nlp);
+
typedef void (*genl_family_event_handler_t)(void *arg, const char *family_name,
uint16_t family_id, u_int action);
EVENTHANDLER_DECLARE(genl_family_event, genl_family_event_handler_t);
diff --git a/sys/netlink/netlink_domain.c b/sys/netlink/netlink_domain.c
--- a/sys/netlink/netlink_domain.c
+++ b/sys/netlink/netlink_domain.c
@@ -497,6 +497,7 @@
/* Wait till all scheduled work has been completed */
taskqueue_drain_all(nlp->nl_taskqueue);
taskqueue_free(nlp->nl_taskqueue);
+ genl_sock_close(nlp);
NLCTL_WLOCK();
NLP_LOCK(nlp);
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
@@ -36,6 +36,7 @@
#include <sys/malloc.h>
#include <sys/priv.h>
#include <sys/proc.h>
+#include <sys/queue.h>
#include <sys/socket.h>
#include <sys/sx.h>
@@ -61,6 +62,12 @@
},
};
+struct genl_sock_priv {
+ LIST_ENTRY(genl_sock_priv) entry;
+ const struct nlpcb *nlp;
+ void *data;
+};
+
static struct genl_family {
const char *family_name;
uint16_t family_hdrsize;
@@ -70,6 +77,9 @@
uint16_t family_num_groups;
struct genl_cmd *family_cmds;
blockcount_t family_busy; /* running handlers */
+ size_t family_priv_size;
+ genl_sock_priv_destroy_t family_priv_destroy;
+ LIST_HEAD(, genl_sock_priv) family_privs;
} families[MAX_FAMILIES] = {
[CTRL_FAMILY_ID] = {
.family_name = CTRL_FAMILY_NAME,
@@ -93,9 +103,9 @@
};
/*
- * 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.
+ * Families, commands, groups and the per-socket storage 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");
@@ -106,6 +116,8 @@
#define GENL_ASSERT_LOCKED() sx_assert(&sx_lock, SA_LOCKED)
#define GENL_ASSERT_XLOCKED() sx_assert(&sx_lock, SA_XLOCKED)
+static void genl_sock_priv_free(struct genl_family *, struct genl_sock_priv *);
+
static inline struct genl_family *
genl_family(uint16_t family_id)
{
@@ -428,6 +440,7 @@
genl_unregister_family(uint16_t family_id)
{
struct genl_family *gf;
+ struct genl_sock_priv *sp;
struct genl_cmd *cmds;
GENL_LOCK();
@@ -452,10 +465,107 @@
free(cmds, M_NETLINK);
GENL_LOCK();
+ while ((sp = LIST_FIRST(&gf->family_privs)) != NULL) {
+ LIST_REMOVE(sp, entry);
+ genl_sock_priv_free(gf, sp);
+ }
bzero(gf, sizeof(*gf));
GENL_UNLOCK();
}
+void
+genl_register_sock_priv(uint16_t family_id, size_t size,
+ genl_sock_priv_destroy_t destroy)
+{
+ struct genl_family *gf;
+
+ MPASS(size > 0);
+
+ GENL_LOCK();
+ gf = genl_family(family_id);
+ MPASS(LIST_EMPTY(&gf->family_privs));
+ gf->family_priv_size = size;
+ gf->family_priv_destroy = destroy;
+ GENL_UNLOCK();
+}
+
+static struct genl_sock_priv *
+genl_sock_priv_find(struct genl_family *gf, const struct nlpcb *nlp)
+{
+ struct genl_sock_priv *sp;
+
+ GENL_ASSERT_LOCKED();
+
+ LIST_FOREACH(sp, &gf->family_privs, entry)
+ if (sp->nlp == nlp)
+ return (sp);
+ return (NULL);
+}
+
+static void
+genl_sock_priv_free(struct genl_family *gf, struct genl_sock_priv *sp)
+{
+ GENL_ASSERT_XLOCKED();
+
+ if (gf->family_priv_destroy != NULL)
+ gf->family_priv_destroy(sp->data);
+ free(sp->data, M_NETLINK);
+ free(sp, M_NETLINK);
+}
+
+/*
+ * Called by a handler of the family, on the socket's own thread: nothing
+ * else creates the socket's storage, the socket does not close while the
+ * handler runs and the family waits for it before it is unregistered.
+ */
+void *
+genl_sock_priv(uint16_t family_id, struct nlpcb *nlp)
+{
+ struct genl_family *gf;
+ struct genl_sock_priv *sp;
+
+ GENL_SLOCK();
+ gf = genl_family(family_id);
+ MPASS(gf->family_priv_size > 0);
+ sp = genl_sock_priv_find(gf, nlp);
+ GENL_SUNLOCK();
+ if (sp != NULL)
+ return (sp->data);
+
+ sp = malloc(sizeof(*sp), M_NETLINK, M_WAITOK);
+ sp->nlp = nlp;
+ sp->data = malloc(gf->family_priv_size, M_NETLINK, M_WAITOK | M_ZERO);
+ GENL_LOCK();
+ LIST_INSERT_HEAD(&gf->family_privs, sp, entry);
+ GENL_UNLOCK();
+
+ return (sp->data);
+}
+
+/* Called when a socket closes, once no handler runs for it. */
+void
+genl_sock_close(struct nlpcb *nlp)
+{
+ struct genl_sock_priv *sp;
+
+ if (nlp->nl_proto != NETLINK_GENERIC)
+ return;
+
+ GENL_LOCK();
+ for (u_int i = 0; i < MAX_FAMILIES; i++) {
+ struct genl_family *gf = &families[i];
+
+ if (LIST_EMPTY(&gf->family_privs))
+ continue;
+ sp = genl_sock_priv_find(gf, nlp);
+ if (sp != NULL) {
+ LIST_REMOVE(sp, entry);
+ genl_sock_priv_free(gf, sp);
+ }
+ }
+ GENL_UNLOCK();
+}
+
bool
genl_register_cmds(uint16_t family_id, const struct genl_cmd *cmds,
u_int count)
diff --git a/sys/netlink/netlink_var.h b/sys/netlink/netlink_var.h
--- a/sys/netlink/netlink_var.h
+++ b/sys/netlink/netlink_var.h
@@ -139,6 +139,9 @@
struct nl_buf *nl_buf_alloc(size_t len, int mflag);
void nl_buf_free(struct nl_buf *nb);
+/* netlink_generic.c */
+void genl_sock_close(struct nlpcb *nlp);
+
#define MAX_FAMILIES 20
#define MAX_GROUPS 64
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Oct 10, 5:05 PM (16 h, 52 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
40554724
Default Alt Text
D60521.id189231.diff (5 KB)
Attached To
Mode
D60521: netlink: Let a generic netlink family keep state per socket
Attached
Detach File
Event Timeline
Log In to Comment