Thomas Graf wrote: > Please provide a new overall patch which is not based on your > initial patch so I can review your idea properly.
Here it goes (merging two previous patches). I have diffed against v2.6.22, which I am using currently as my base: include/net/genetlink.h | 1 + net/netlink/genetlink.c | 106 +++++++++++++++++++++++++++++++++++------------ 2 files changed, 80 insertions(+), 27 deletions(-) diff --git a/include/net/genetlink.h b/include/net/genetlink.h index b6eaca1..681ad13 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -25,6 +25,7 @@ struct genl_family struct nlattr ** attrbuf; /* private */ struct list_head ops_list; /* private */ struct list_head family_list; /* private */ + struct mutex lock; /* private */ }; /** diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index b9ab62f..0104267 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -38,6 +38,32 @@ static void genl_unlock(void) genl_sock->sk_data_ready(genl_sock, 0); } +static DEFINE_MUTEX(genl_fam_mutex); /* serialization for family list management */ + +static inline void genl_fam_lock(struct genl_family *family) +{ + mutex_lock(&genl_fam_mutex); + if (family) + mutex_lock(&family->lock); +} + +static inline void genl_fam_unlock(struct genl_family *family) +{ + if (family) + mutex_unlock(&family->lock); + mutex_unlock(&genl_fam_mutex); +} + +static inline void genl_onefam_lock(struct genl_family *family) +{ + mutex_lock(&family->lock); +} + +static inline void genl_onefam_unlock(struct genl_family *family) +{ + mutex_unlock(&family->lock); +} + #define GENL_FAM_TAB_SIZE 16 #define GENL_FAM_TAB_MASK (GENL_FAM_TAB_SIZE - 1) @@ -150,9 +176,9 @@ int genl_register_ops(struct genl_family *family, struct genl_ops *ops) if (ops->policy) ops->flags |= GENL_CMD_CAP_HASPOL; - genl_lock(); + genl_fam_lock(family); list_add_tail(&ops->ops_list, &family->ops_list); - genl_unlock(); + genl_fam_unlock(family); genl_ctrl_event(CTRL_CMD_NEWOPS, ops); err = 0; @@ -180,16 +206,16 @@ int genl_unregister_ops(struct genl_family *family, struct genl_ops *ops) { struct genl_ops *rc; - genl_lock(); + genl_fam_lock(family); list_for_each_entry(rc, &family->ops_list, ops_list) { if (rc == ops) { list_del(&ops->ops_list); - genl_unlock(); + genl_fam_unlock(family); genl_ctrl_event(CTRL_CMD_DELOPS, ops); return 0; } } - genl_unlock(); + genl_fam_unlock(family); return -ENOENT; } @@ -216,8 +242,9 @@ int genl_register_family(struct genl_family *family) goto errout; INIT_LIST_HEAD(&family->ops_list); + mutex_init(&family->lock); - genl_lock(); + genl_fam_lock(family); if (genl_family_find_byname(family->name)) { err = -EEXIST; @@ -251,14 +278,14 @@ int genl_register_family(struct genl_family *family) family->attrbuf = NULL; list_add_tail(&family->family_list, genl_family_chain(family->id)); - genl_unlock(); + genl_fam_unlock(family); genl_ctrl_event(CTRL_CMD_NEWFAMILY, family); return 0; errout_locked: - genl_unlock(); + genl_fam_unlock(family); errout: return err; } @@ -275,7 +302,7 @@ int genl_unregister_family(struct genl_family *family) { struct genl_family *rc; - genl_lock(); + genl_fam_lock(family); list_for_each_entry(rc, genl_family_chain(family->id), family_list) { if (family->id != rc->id || strcmp(rc->name, family->name)) @@ -283,14 +310,16 @@ int genl_unregister_family(struct genl_family *family) list_del(&rc->family_list); INIT_LIST_HEAD(&family->ops_list); - genl_unlock(); + + genl_fam_unlock(family); + mutex_destroy(&family->lock); kfree(family->attrbuf); genl_ctrl_event(CTRL_CMD_DELFAMILY, family); return 0; } - genl_unlock(); + genl_fam_unlock(family); return -ENOENT; } @@ -303,38 +332,57 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) struct genlmsghdr *hdr = nlmsg_data(nlh); int hdrlen, err; + genl_fam_lock(NULL); family = genl_family_find_byid(nlh->nlmsg_type); - if (family == NULL) + if (family == NULL) { + genl_fam_unlock(NULL); return -ENOENT; + } + + /* get particular family lock, but release global family lock + * so registering operations for other families are possible */ + genl_onefam_lock(family); + genl_fam_unlock(NULL); hdrlen = GENL_HDRLEN + family->hdrsize; - if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen)) - return -EINVAL; + if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen)) { + err = -EINVAL; + goto unlock_out; + } ops = genl_get_cmd(hdr->cmd, family); - if (ops == NULL) - return -EOPNOTSUPP; + if (ops == NULL) { + err = -EOPNOTSUPP; + goto unlock_out; + } if ((ops->flags & GENL_ADMIN_PERM) && - security_netlink_recv(skb, CAP_NET_ADMIN)) - return -EPERM; + security_netlink_recv(skb, CAP_NET_ADMIN)) { + err = -EPERM; + goto unlock_out; + } if (nlh->nlmsg_flags & NLM_F_DUMP) { - if (ops->dumpit == NULL) - return -EOPNOTSUPP; + if (ops->dumpit == NULL) { + err = -EOPNOTSUPP; + goto unlock_out; + } - return netlink_dump_start(genl_sock, skb, nlh, + err = netlink_dump_start(genl_sock, skb, nlh, ops->dumpit, ops->done); + goto unlock_out; } - if (ops->doit == NULL) - return -EOPNOTSUPP; + if (ops->doit == NULL) { + err = -EOPNOTSUPP; + goto unlock_out; + } if (family->attrbuf) { err = nlmsg_parse(nlh, hdrlen, family->attrbuf, family->maxattr, ops->policy); if (err < 0) - return err; + goto unlock_out; } info.snd_seq = nlh->nlmsg_seq; @@ -344,7 +392,11 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) info.userhdr = nlmsg_data(nlh) + GENL_HDRLEN; info.attrs = family->attrbuf; - return ops->doit(skb, &info); + err = ops->doit(skb, &info); + +unlock_out: + genl_onefam_unlock(family); + return err; } static void genl_rcv(struct sock *sk, int len) @@ -425,7 +477,7 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb) int fams_to_skip = cb->args[1]; if (chains_to_skip != 0) - genl_lock(); + genl_fam_lock(NULL); for (i = 0; i < GENL_FAM_TAB_SIZE; i++) { if (i < chains_to_skip) @@ -445,7 +497,7 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb) errout: if (chains_to_skip != 0) - genl_unlock(); + genl_fam_unlock(NULL); cb->args[0] = i; cb->args[1] = n; - To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html