Commit 2ae0f17d authored by Johannes Berg's avatar Johannes Berg Committed by David S. Miller

genetlink: use idr to track families

Since generic netlink family IDs are small integers, allocated
densely, IDR is an ideal match for lookups. Replace the existing
hand-written hash-table with IDR for allocation and lookup.

This lets the families only be written to once, during register,
since the list_head can be removed and removal of a family won't
cause any writes.

It also slightly reduces the code size (by about 1.3k on x86-64).
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 489111e5
...@@ -40,7 +40,6 @@ struct genl_info; ...@@ -40,7 +40,6 @@ struct genl_info;
* generic netlink family is removed while there are still open * generic netlink family is removed while there are still open
* sockets. * sockets.
* @attrbuf: buffer to store parsed attributes (private) * @attrbuf: buffer to store parsed attributes (private)
* @family_list: family list (private)
* @mcgrps: multicast groups used by this family * @mcgrps: multicast groups used by this family
* @n_mcgrps: number of multicast groups * @n_mcgrps: number of multicast groups
* @mcgrp_offset: starting number of multicast group IDs in this family * @mcgrp_offset: starting number of multicast group IDs in this family
...@@ -70,11 +69,10 @@ struct genl_family { ...@@ -70,11 +69,10 @@ struct genl_family {
unsigned int n_ops; unsigned int n_ops;
unsigned int n_mcgrps; unsigned int n_mcgrps;
unsigned int mcgrp_offset; /* private */ unsigned int mcgrp_offset; /* private */
struct list_head family_list; /* private */
struct module *module; struct module *module;
}; };
struct nlattr **genl_family_attrbuf(struct genl_family *family); struct nlattr **genl_family_attrbuf(const struct genl_family *family);
/** /**
* struct genl_info - receiving information * struct genl_info - receiving information
...@@ -134,12 +132,12 @@ struct genl_ops { ...@@ -134,12 +132,12 @@ struct genl_ops {
}; };
int genl_register_family(struct genl_family *family); int genl_register_family(struct genl_family *family);
int genl_unregister_family(struct genl_family *family); int genl_unregister_family(const struct genl_family *family);
void genl_notify(struct genl_family *family, struct sk_buff *skb, void genl_notify(const struct genl_family *family, struct sk_buff *skb,
struct genl_info *info, u32 group, gfp_t flags); struct genl_info *info, u32 group, gfp_t flags);
void *genlmsg_put(struct sk_buff *skb, u32 portid, u32 seq, void *genlmsg_put(struct sk_buff *skb, u32 portid, u32 seq,
struct genl_family *family, int flags, u8 cmd); const struct genl_family *family, int flags, u8 cmd);
/** /**
* genlmsg_nlhdr - Obtain netlink header from user specified header * genlmsg_nlhdr - Obtain netlink header from user specified header
...@@ -148,8 +146,8 @@ void *genlmsg_put(struct sk_buff *skb, u32 portid, u32 seq, ...@@ -148,8 +146,8 @@ void *genlmsg_put(struct sk_buff *skb, u32 portid, u32 seq,
* *
* Returns pointer to netlink header. * Returns pointer to netlink header.
*/ */
static inline struct nlmsghdr *genlmsg_nlhdr(void *user_hdr, static inline struct nlmsghdr *
struct genl_family *family) genlmsg_nlhdr(void *user_hdr, const struct genl_family *family)
{ {
return (struct nlmsghdr *)((char *)user_hdr - return (struct nlmsghdr *)((char *)user_hdr -
family->hdrsize - family->hdrsize -
...@@ -185,7 +183,7 @@ static inline int genlmsg_parse(const struct nlmsghdr *nlh, ...@@ -185,7 +183,7 @@ static inline int genlmsg_parse(const struct nlmsghdr *nlh,
*/ */
static inline void genl_dump_check_consistent(struct netlink_callback *cb, static inline void genl_dump_check_consistent(struct netlink_callback *cb,
void *user_hdr, void *user_hdr,
struct genl_family *family) const struct genl_family *family)
{ {
nl_dump_check_consistent(cb, genlmsg_nlhdr(user_hdr, family)); nl_dump_check_consistent(cb, genlmsg_nlhdr(user_hdr, family));
} }
...@@ -202,7 +200,7 @@ static inline void genl_dump_check_consistent(struct netlink_callback *cb, ...@@ -202,7 +200,7 @@ static inline void genl_dump_check_consistent(struct netlink_callback *cb,
*/ */
static inline void *genlmsg_put_reply(struct sk_buff *skb, static inline void *genlmsg_put_reply(struct sk_buff *skb,
struct genl_info *info, struct genl_info *info,
struct genl_family *family, const struct genl_family *family,
int flags, u8 cmd) int flags, u8 cmd)
{ {
return genlmsg_put(skb, info->snd_portid, info->snd_seq, family, return genlmsg_put(skb, info->snd_portid, info->snd_seq, family,
...@@ -239,7 +237,7 @@ static inline void genlmsg_cancel(struct sk_buff *skb, void *hdr) ...@@ -239,7 +237,7 @@ static inline void genlmsg_cancel(struct sk_buff *skb, void *hdr)
* @group: offset of multicast group in groups array * @group: offset of multicast group in groups array
* @flags: allocation flags * @flags: allocation flags
*/ */
static inline int genlmsg_multicast_netns(struct genl_family *family, static inline int genlmsg_multicast_netns(const struct genl_family *family,
struct net *net, struct sk_buff *skb, struct net *net, struct sk_buff *skb,
u32 portid, unsigned int group, gfp_t flags) u32 portid, unsigned int group, gfp_t flags)
{ {
...@@ -257,7 +255,7 @@ static inline int genlmsg_multicast_netns(struct genl_family *family, ...@@ -257,7 +255,7 @@ static inline int genlmsg_multicast_netns(struct genl_family *family,
* @group: offset of multicast group in groups array * @group: offset of multicast group in groups array
* @flags: allocation flags * @flags: allocation flags
*/ */
static inline int genlmsg_multicast(struct genl_family *family, static inline int genlmsg_multicast(const struct genl_family *family,
struct sk_buff *skb, u32 portid, struct sk_buff *skb, u32 portid,
unsigned int group, gfp_t flags) unsigned int group, gfp_t flags)
{ {
...@@ -275,7 +273,7 @@ static inline int genlmsg_multicast(struct genl_family *family, ...@@ -275,7 +273,7 @@ static inline int genlmsg_multicast(struct genl_family *family,
* *
* This function must hold the RTNL or rcu_read_lock(). * This function must hold the RTNL or rcu_read_lock().
*/ */
int genlmsg_multicast_allns(struct genl_family *family, int genlmsg_multicast_allns(const struct genl_family *family,
struct sk_buff *skb, u32 portid, struct sk_buff *skb, u32 portid,
unsigned int group, gfp_t flags); unsigned int group, gfp_t flags);
...@@ -359,8 +357,9 @@ static inline struct sk_buff *genlmsg_new(size_t payload, gfp_t flags) ...@@ -359,8 +357,9 @@ static inline struct sk_buff *genlmsg_new(size_t payload, gfp_t flags)
* This function returns the number of broadcast listeners that have set the * This function returns the number of broadcast listeners that have set the
* NETLINK_RECV_NO_ENOBUFS socket option. * NETLINK_RECV_NO_ENOBUFS socket option.
*/ */
static inline int genl_set_err(struct genl_family *family, struct net *net, static inline int genl_set_err(const struct genl_family *family,
u32 portid, u32 group, int code) struct net *net, u32 portid,
u32 group, int code)
{ {
if (WARN_ON_ONCE(group >= family->n_mcgrps)) if (WARN_ON_ONCE(group >= family->n_mcgrps))
return -EINVAL; return -EINVAL;
...@@ -368,7 +367,7 @@ static inline int genl_set_err(struct genl_family *family, struct net *net, ...@@ -368,7 +367,7 @@ static inline int genl_set_err(struct genl_family *family, struct net *net,
return netlink_set_err(net->genl_sock, portid, group, code); return netlink_set_err(net->genl_sock, portid, group, code);
} }
static inline int genl_has_listeners(struct genl_family *family, static inline int genl_has_listeners(const struct genl_family *family,
struct net *net, unsigned int group) struct net *net, unsigned int group)
{ {
if (WARN_ON_ONCE(group >= family->n_mcgrps)) if (WARN_ON_ONCE(group >= family->n_mcgrps))
......
...@@ -29,6 +29,8 @@ struct genlmsghdr { ...@@ -29,6 +29,8 @@ struct genlmsghdr {
#define GENL_ID_CTRL NLMSG_MIN_TYPE #define GENL_ID_CTRL NLMSG_MIN_TYPE
#define GENL_ID_VFS_DQUOT (NLMSG_MIN_TYPE + 1) #define GENL_ID_VFS_DQUOT (NLMSG_MIN_TYPE + 1)
#define GENL_ID_PMCRAID (NLMSG_MIN_TYPE + 2) #define GENL_ID_PMCRAID (NLMSG_MIN_TYPE + 2)
/* must be last reserved + 1 */
#define GENL_START_ALLOC (NLMSG_MIN_TYPE + 3)
/************************************************************************** /**************************************************************************
* Controller * Controller
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/bitmap.h> #include <linux/bitmap.h>
#include <linux/rwsem.h> #include <linux/rwsem.h>
#include <linux/idr.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/genetlink.h> #include <net/genetlink.h>
...@@ -58,10 +59,8 @@ static void genl_unlock_all(void) ...@@ -58,10 +59,8 @@ static void genl_unlock_all(void)
up_write(&cb_lock); up_write(&cb_lock);
} }
#define GENL_FAM_TAB_SIZE 16 static DEFINE_IDR(genl_fam_idr);
#define GENL_FAM_TAB_MASK (GENL_FAM_TAB_SIZE - 1)
static struct list_head family_ht[GENL_FAM_TAB_SIZE];
/* /*
* Bitmap of multicast groups that are currently in use. * Bitmap of multicast groups that are currently in use.
* *
...@@ -86,45 +85,29 @@ static unsigned long mc_group_start = 0x3 | BIT(GENL_ID_CTRL) | ...@@ -86,45 +85,29 @@ static unsigned long mc_group_start = 0x3 | BIT(GENL_ID_CTRL) |
static unsigned long *mc_groups = &mc_group_start; static unsigned long *mc_groups = &mc_group_start;
static unsigned long mc_groups_longs = 1; static unsigned long mc_groups_longs = 1;
static int genl_ctrl_event(int event, struct genl_family *family, static int genl_ctrl_event(int event, const struct genl_family *family,
const struct genl_multicast_group *grp, const struct genl_multicast_group *grp,
int grp_id); int grp_id);
static inline unsigned int genl_family_hash(unsigned int id) static const struct genl_family *genl_family_find_byid(unsigned int id)
{ {
return id & GENL_FAM_TAB_MASK; return idr_find(&genl_fam_idr, id);
} }
static inline struct list_head *genl_family_chain(unsigned int id) static const struct genl_family *genl_family_find_byname(char *name)
{ {
return &family_ht[genl_family_hash(id)]; const struct genl_family *family;
} unsigned int id;
static struct genl_family *genl_family_find_byid(unsigned int id)
{
struct genl_family *f;
list_for_each_entry(f, genl_family_chain(id), family_list)
if (f->id == id)
return f;
return NULL;
}
static struct genl_family *genl_family_find_byname(char *name) idr_for_each_entry(&genl_fam_idr, family, id)
{ if (strcmp(family->name, name) == 0)
struct genl_family *f; return family;
int i;
for (i = 0; i < GENL_FAM_TAB_SIZE; i++)
list_for_each_entry(f, genl_family_chain(i), family_list)
if (strcmp(f->name, name) == 0)
return f;
return NULL; return NULL;
} }
static const struct genl_ops *genl_get_cmd(u8 cmd, struct genl_family *family) static const struct genl_ops *genl_get_cmd(u8 cmd,
const struct genl_family *family)
{ {
int i; int i;
...@@ -135,26 +118,6 @@ static const struct genl_ops *genl_get_cmd(u8 cmd, struct genl_family *family) ...@@ -135,26 +118,6 @@ static const struct genl_ops *genl_get_cmd(u8 cmd, struct genl_family *family)
return NULL; return NULL;
} }
/* Of course we are going to have problems once we hit
* 2^16 alive types, but that can only happen by year 2K
*/
static u16 genl_generate_id(void)
{
static u16 id_gen_idx = GENL_MIN_ID;
int i;
for (i = 0; i <= GENL_MAX_ID - GENL_MIN_ID; i++) {
if (id_gen_idx != GENL_ID_VFS_DQUOT &&
id_gen_idx != GENL_ID_PMCRAID &&
!genl_family_find_byid(id_gen_idx))
return id_gen_idx;
if (++id_gen_idx > GENL_MAX_ID)
id_gen_idx = GENL_MIN_ID;
}
return 0;
}
static int genl_allocate_reserve_groups(int n_groups, int *first_id) static int genl_allocate_reserve_groups(int n_groups, int *first_id)
{ {
unsigned long *new_groups; unsigned long *new_groups;
...@@ -295,7 +258,7 @@ static int genl_validate_assign_mc_groups(struct genl_family *family) ...@@ -295,7 +258,7 @@ static int genl_validate_assign_mc_groups(struct genl_family *family)
return err; return err;
} }
static void genl_unregister_mc_groups(struct genl_family *family) static void genl_unregister_mc_groups(const struct genl_family *family)
{ {
struct net *net; struct net *net;
int i; int i;
...@@ -358,6 +321,7 @@ static int genl_validate_ops(const struct genl_family *family) ...@@ -358,6 +321,7 @@ static int genl_validate_ops(const struct genl_family *family)
int genl_register_family(struct genl_family *family) int genl_register_family(struct genl_family *family)
{ {
int err, i; int err, i;
int start = GENL_START_ALLOC, end = GENL_MAX_ID;
err = genl_validate_ops(family); err = genl_validate_ops(family);
if (err) if (err)
...@@ -370,14 +334,6 @@ int genl_register_family(struct genl_family *family) ...@@ -370,14 +334,6 @@ int genl_register_family(struct genl_family *family)
goto errout_locked; goto errout_locked;
} }
if (family == &genl_ctrl) {
family->id = GENL_ID_CTRL;
} else {
u16 newid;
/* this should be left zero in the struct */
WARN_ON(family->id);
/* /*
* Sadly, a few cases need to be special-cased * Sadly, a few cases need to be special-cased
* due to them having previously abused the API * due to them having previously abused the API
...@@ -385,19 +341,13 @@ int genl_register_family(struct genl_family *family) ...@@ -385,19 +341,13 @@ int genl_register_family(struct genl_family *family)
* multicast group ID, so we use reserved IDs * multicast group ID, so we use reserved IDs
* for both to be sure we can do that mapping. * for both to be sure we can do that mapping.
*/ */
if (strcmp(family->name, "pmcraid") == 0) if (family == &genl_ctrl) {
newid = GENL_ID_PMCRAID; /* and this needs to be special for initial family lookups */
else if (strcmp(family->name, "VFS_DQUOT") == 0) start = end = GENL_ID_CTRL;
newid = GENL_ID_VFS_DQUOT; } else if (strcmp(family->name, "pmcraid") == 0) {
else start = end = GENL_ID_PMCRAID;
newid = genl_generate_id(); } else if (strcmp(family->name, "VFS_DQUOT") == 0) {
start = end = GENL_ID_VFS_DQUOT;
if (!newid) {
err = -ENOMEM;
goto errout_locked;
}
family->id = newid;
} }
if (family->maxattr && !family->parallel_ops) { if (family->maxattr && !family->parallel_ops) {
...@@ -410,11 +360,15 @@ int genl_register_family(struct genl_family *family) ...@@ -410,11 +360,15 @@ int genl_register_family(struct genl_family *family)
} else } else
family->attrbuf = NULL; family->attrbuf = NULL;
family->id = idr_alloc(&genl_fam_idr, family,
start, end + 1, GFP_KERNEL);
if (!family->id)
goto errout_locked;
err = genl_validate_assign_mc_groups(family); err = genl_validate_assign_mc_groups(family);
if (err) if (err)
goto errout_locked; goto errout_remove;
list_add_tail(&family->family_list, genl_family_chain(family->id));
genl_unlock_all(); genl_unlock_all();
/* send all events */ /* send all events */
...@@ -425,6 +379,8 @@ int genl_register_family(struct genl_family *family) ...@@ -425,6 +379,8 @@ int genl_register_family(struct genl_family *family)
return 0; return 0;
errout_remove:
idr_remove(&genl_fam_idr, family->id);
errout_locked: errout_locked:
genl_unlock_all(); genl_unlock_all();
return err; return err;
...@@ -439,32 +395,29 @@ EXPORT_SYMBOL(genl_register_family); ...@@ -439,32 +395,29 @@ EXPORT_SYMBOL(genl_register_family);
* *
* Returns 0 on success or a negative error code. * Returns 0 on success or a negative error code.
*/ */
int genl_unregister_family(struct genl_family *family) int genl_unregister_family(const struct genl_family *family)
{ {
struct genl_family *rc;
genl_lock_all(); genl_lock_all();
list_for_each_entry(rc, genl_family_chain(family->id), family_list) { if (genl_family_find_byid(family->id)) {
if (family->id != rc->id || strcmp(rc->name, family->name)) genl_unlock_all();
continue; return -ENOENT;
}
genl_unregister_mc_groups(family); genl_unregister_mc_groups(family);
list_del(&rc->family_list); idr_remove(&genl_fam_idr, family->id);
up_write(&cb_lock); up_write(&cb_lock);
wait_event(genl_sk_destructing_waitq, wait_event(genl_sk_destructing_waitq,
atomic_read(&genl_sk_destructing_cnt) == 0); atomic_read(&genl_sk_destructing_cnt) == 0);
genl_unlock(); genl_unlock();
kfree(family->attrbuf); kfree(family->attrbuf);
genl_ctrl_event(CTRL_CMD_DELFAMILY, family, NULL, 0);
return 0;
}
genl_unlock_all(); genl_ctrl_event(CTRL_CMD_DELFAMILY, family, NULL, 0);
return -ENOENT; return 0;
} }
EXPORT_SYMBOL(genl_unregister_family); EXPORT_SYMBOL(genl_unregister_family);
...@@ -480,7 +433,7 @@ EXPORT_SYMBOL(genl_unregister_family); ...@@ -480,7 +433,7 @@ EXPORT_SYMBOL(genl_unregister_family);
* Returns pointer to user specific header * Returns pointer to user specific header
*/ */
void *genlmsg_put(struct sk_buff *skb, u32 portid, u32 seq, void *genlmsg_put(struct sk_buff *skb, u32 portid, u32 seq,
struct genl_family *family, int flags, u8 cmd) const struct genl_family *family, int flags, u8 cmd)
{ {
struct nlmsghdr *nlh; struct nlmsghdr *nlh;
struct genlmsghdr *hdr; struct genlmsghdr *hdr;
...@@ -539,7 +492,7 @@ static int genl_lock_done(struct netlink_callback *cb) ...@@ -539,7 +492,7 @@ static int genl_lock_done(struct netlink_callback *cb)
return rc; return rc;
} }
static int genl_family_rcv_msg(struct genl_family *family, static int genl_family_rcv_msg(const struct genl_family *family,
struct sk_buff *skb, struct sk_buff *skb,
struct nlmsghdr *nlh) struct nlmsghdr *nlh)
{ {
...@@ -651,7 +604,7 @@ static int genl_family_rcv_msg(struct genl_family *family, ...@@ -651,7 +604,7 @@ static int genl_family_rcv_msg(struct genl_family *family,
static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
{ {
struct genl_family *family; const struct genl_family *family;
int err; int err;
family = genl_family_find_byid(nlh->nlmsg_type); family = genl_family_find_byid(nlh->nlmsg_type);
...@@ -682,7 +635,7 @@ static void genl_rcv(struct sk_buff *skb) ...@@ -682,7 +635,7 @@ static void genl_rcv(struct sk_buff *skb)
static struct genl_family genl_ctrl; static struct genl_family genl_ctrl;
static int ctrl_fill_info(struct genl_family *family, u32 portid, u32 seq, static int ctrl_fill_info(const struct genl_family *family, u32 portid, u32 seq,
u32 flags, struct sk_buff *skb, u8 cmd) u32 flags, struct sk_buff *skb, u8 cmd)
{ {
void *hdr; void *hdr;
...@@ -769,7 +722,7 @@ static int ctrl_fill_info(struct genl_family *family, u32 portid, u32 seq, ...@@ -769,7 +722,7 @@ static int ctrl_fill_info(struct genl_family *family, u32 portid, u32 seq,
return -EMSGSIZE; return -EMSGSIZE;
} }
static int ctrl_fill_mcgrp_info(struct genl_family *family, static int ctrl_fill_mcgrp_info(const struct genl_family *family,
const struct genl_multicast_group *grp, const struct genl_multicast_group *grp,
int grp_id, u32 portid, u32 seq, u32 flags, int grp_id, u32 portid, u32 seq, u32 flags,
struct sk_buff *skb, u8 cmd) struct sk_buff *skb, u8 cmd)
...@@ -812,37 +765,30 @@ static int ctrl_fill_mcgrp_info(struct genl_family *family, ...@@ -812,37 +765,30 @@ static int ctrl_fill_mcgrp_info(struct genl_family *family,
static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb) static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb)
{ {
int n = 0;
int i, n = 0;
struct genl_family *rt; struct genl_family *rt;
struct net *net = sock_net(skb->sk); struct net *net = sock_net(skb->sk);
int chains_to_skip = cb->args[0]; int fams_to_skip = cb->args[0];
int fams_to_skip = cb->args[1]; unsigned int id;
for (i = chains_to_skip; i < GENL_FAM_TAB_SIZE; i++) { idr_for_each_entry(&genl_fam_idr, rt, id) {
n = 0;
list_for_each_entry(rt, genl_family_chain(i), family_list) {
if (!rt->netnsok && !net_eq(net, &init_net)) if (!rt->netnsok && !net_eq(net, &init_net))
continue; continue;
if (++n < fams_to_skip)
if (n++ < fams_to_skip)
continue; continue;
if (ctrl_fill_info(rt, NETLINK_CB(cb->skb).portid, if (ctrl_fill_info(rt, NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh->nlmsg_seq, NLM_F_MULTI,
skb, CTRL_CMD_NEWFAMILY) < 0) skb, CTRL_CMD_NEWFAMILY) < 0)
goto errout; break;
}
fams_to_skip = 0;
} }
errout: cb->args[0] = n;
cb->args[0] = i;
cb->args[1] = n;
return skb->len; return skb->len;
} }
static struct sk_buff *ctrl_build_family_msg(struct genl_family *family, static struct sk_buff *ctrl_build_family_msg(const struct genl_family *family,
u32 portid, int seq, u8 cmd) u32 portid, int seq, u8 cmd)
{ {
struct sk_buff *skb; struct sk_buff *skb;
...@@ -862,7 +808,7 @@ static struct sk_buff *ctrl_build_family_msg(struct genl_family *family, ...@@ -862,7 +808,7 @@ static struct sk_buff *ctrl_build_family_msg(struct genl_family *family,
} }
static struct sk_buff * static struct sk_buff *
ctrl_build_mcgrp_msg(struct genl_family *family, ctrl_build_mcgrp_msg(const struct genl_family *family,
const struct genl_multicast_group *grp, const struct genl_multicast_group *grp,
int grp_id, u32 portid, int seq, u8 cmd) int grp_id, u32 portid, int seq, u8 cmd)
{ {
...@@ -892,7 +838,7 @@ static const struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] = { ...@@ -892,7 +838,7 @@ static const struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] = {
static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info) static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info)
{ {
struct sk_buff *msg; struct sk_buff *msg;
struct genl_family *res = NULL; const struct genl_family *res = NULL;
int err = -EINVAL; int err = -EINVAL;
if (info->attrs[CTRL_ATTR_FAMILY_ID]) { if (info->attrs[CTRL_ATTR_FAMILY_ID]) {
...@@ -936,7 +882,7 @@ static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info) ...@@ -936,7 +882,7 @@ static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info)
return genlmsg_reply(msg, info); return genlmsg_reply(msg, info);
} }
static int genl_ctrl_event(int event, struct genl_family *family, static int genl_ctrl_event(int event, const struct genl_family *family,
const struct genl_multicast_group *grp, const struct genl_multicast_group *grp,
int grp_id) int grp_id)
{ {
...@@ -1005,13 +951,13 @@ static struct genl_family genl_ctrl = { ...@@ -1005,13 +951,13 @@ static struct genl_family genl_ctrl = {
static int genl_bind(struct net *net, int group) static int genl_bind(struct net *net, int group)
{ {
int i, err = -ENOENT; struct genl_family *f;
int err = -ENOENT;
unsigned int id;
down_read(&cb_lock); down_read(&cb_lock);
for (i = 0; i < GENL_FAM_TAB_SIZE; i++) {
struct genl_family *f;
list_for_each_entry(f, genl_family_chain(i), family_list) { idr_for_each_entry(&genl_fam_idr, f, id) {
if (group >= f->mcgrp_offset && if (group >= f->mcgrp_offset &&
group < f->mcgrp_offset + f->n_mcgrps) { group < f->mcgrp_offset + f->n_mcgrps) {
int fam_grp = group - f->mcgrp_offset; int fam_grp = group - f->mcgrp_offset;
...@@ -1025,7 +971,6 @@ static int genl_bind(struct net *net, int group) ...@@ -1025,7 +971,6 @@ static int genl_bind(struct net *net, int group)
break; break;
} }
} }
}
up_read(&cb_lock); up_read(&cb_lock);
return err; return err;
...@@ -1033,13 +978,12 @@ static int genl_bind(struct net *net, int group) ...@@ -1033,13 +978,12 @@ static int genl_bind(struct net *net, int group)
static void genl_unbind(struct net *net, int group) static void genl_unbind(struct net *net, int group)
{ {
int i; struct genl_family *f;
unsigned int id;
down_read(&cb_lock); down_read(&cb_lock);
for (i = 0; i < GENL_FAM_TAB_SIZE; i++) {
struct genl_family *f;
list_for_each_entry(f, genl_family_chain(i), family_list) { idr_for_each_entry(&genl_fam_idr, f, id) {
if (group >= f->mcgrp_offset && if (group >= f->mcgrp_offset &&
group < f->mcgrp_offset + f->n_mcgrps) { group < f->mcgrp_offset + f->n_mcgrps) {
int fam_grp = group - f->mcgrp_offset; int fam_grp = group - f->mcgrp_offset;
...@@ -1049,7 +993,6 @@ static void genl_unbind(struct net *net, int group) ...@@ -1049,7 +993,6 @@ static void genl_unbind(struct net *net, int group)
break; break;
} }
} }
}
up_read(&cb_lock); up_read(&cb_lock);
} }
...@@ -1087,10 +1030,7 @@ static struct pernet_operations genl_pernet_ops = { ...@@ -1087,10 +1030,7 @@ static struct pernet_operations genl_pernet_ops = {
static int __init genl_init(void) static int __init genl_init(void)
{ {
int i, err; int err;
for (i = 0; i < GENL_FAM_TAB_SIZE; i++)
INIT_LIST_HEAD(&family_ht[i]);
err = genl_register_family(&genl_ctrl); err = genl_register_family(&genl_ctrl);
if (err < 0) if (err < 0)
...@@ -1118,7 +1058,7 @@ subsys_initcall(genl_init); ...@@ -1118,7 +1058,7 @@ subsys_initcall(genl_init);
* You cannot use this function with a family that has parallel_ops * You cannot use this function with a family that has parallel_ops
* and you can only use it within (pre/post) doit/dumpit callbacks. * and you can only use it within (pre/post) doit/dumpit callbacks.
*/ */
struct nlattr **genl_family_attrbuf(struct genl_family *family) struct nlattr **genl_family_attrbuf(const struct genl_family *family)
{ {
if (!WARN_ON(family->parallel_ops)) if (!WARN_ON(family->parallel_ops))
lockdep_assert_held(&genl_mutex); lockdep_assert_held(&genl_mutex);
...@@ -1156,8 +1096,9 @@ static int genlmsg_mcast(struct sk_buff *skb, u32 portid, unsigned long group, ...@@ -1156,8 +1096,9 @@ static int genlmsg_mcast(struct sk_buff *skb, u32 portid, unsigned long group,
return err; return err;
} }
int genlmsg_multicast_allns(struct genl_family *family, struct sk_buff *skb, int genlmsg_multicast_allns(const struct genl_family *family,
u32 portid, unsigned int group, gfp_t flags) struct sk_buff *skb, u32 portid,
unsigned int group, gfp_t flags)
{ {
if (WARN_ON_ONCE(group >= family->n_mcgrps)) if (WARN_ON_ONCE(group >= family->n_mcgrps))
return -EINVAL; return -EINVAL;
...@@ -1166,7 +1107,7 @@ int genlmsg_multicast_allns(struct genl_family *family, struct sk_buff *skb, ...@@ -1166,7 +1107,7 @@ int genlmsg_multicast_allns(struct genl_family *family, struct sk_buff *skb,
} }
EXPORT_SYMBOL(genlmsg_multicast_allns); EXPORT_SYMBOL(genlmsg_multicast_allns);
void genl_notify(struct genl_family *family, struct sk_buff *skb, void genl_notify(const struct genl_family *family, struct sk_buff *skb,
struct genl_info *info, u32 group, gfp_t flags) struct genl_info *info, u32 group, gfp_t flags)
{ {
struct net *net = genl_info_net(info); struct net *net = genl_info_net(info);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment