Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Johannes Berg and committed by
David S. Miller
2ae0f17d 489111e5

+123 -181
+15 -16
include/net/genetlink.h
··· 40 40 * generic netlink family is removed while there are still open 41 41 * sockets. 42 42 * @attrbuf: buffer to store parsed attributes (private) 43 - * @family_list: family list (private) 44 43 * @mcgrps: multicast groups used by this family 45 44 * @n_mcgrps: number of multicast groups 46 45 * @mcgrp_offset: starting number of multicast group IDs in this family ··· 69 70 unsigned int n_ops; 70 71 unsigned int n_mcgrps; 71 72 unsigned int mcgrp_offset; /* private */ 72 - struct list_head family_list; /* private */ 73 73 struct module *module; 74 74 }; 75 75 76 - struct nlattr **genl_family_attrbuf(struct genl_family *family); 76 + struct nlattr **genl_family_attrbuf(const struct genl_family *family); 77 77 78 78 /** 79 79 * struct genl_info - receiving information ··· 132 134 }; 133 135 134 136 int genl_register_family(struct genl_family *family); 135 - int genl_unregister_family(struct genl_family *family); 136 - void genl_notify(struct genl_family *family, struct sk_buff *skb, 137 + int genl_unregister_family(const struct genl_family *family); 138 + void genl_notify(const struct genl_family *family, struct sk_buff *skb, 137 139 struct genl_info *info, u32 group, gfp_t flags); 138 140 139 141 void *genlmsg_put(struct sk_buff *skb, u32 portid, u32 seq, 140 - struct genl_family *family, int flags, u8 cmd); 142 + const struct genl_family *family, int flags, u8 cmd); 141 143 142 144 /** 143 145 * genlmsg_nlhdr - Obtain netlink header from user specified header ··· 146 148 * 147 149 * Returns pointer to netlink header. 148 150 */ 149 - static inline struct nlmsghdr *genlmsg_nlhdr(void *user_hdr, 150 - struct genl_family *family) 151 + static inline struct nlmsghdr * 152 + genlmsg_nlhdr(void *user_hdr, const struct genl_family *family) 151 153 { 152 154 return (struct nlmsghdr *)((char *)user_hdr - 153 155 family->hdrsize - ··· 183 185 */ 184 186 static inline void genl_dump_check_consistent(struct netlink_callback *cb, 185 187 void *user_hdr, 186 - struct genl_family *family) 188 + const struct genl_family *family) 187 189 { 188 190 nl_dump_check_consistent(cb, genlmsg_nlhdr(user_hdr, family)); 189 191 } ··· 200 202 */ 201 203 static inline void *genlmsg_put_reply(struct sk_buff *skb, 202 204 struct genl_info *info, 203 - struct genl_family *family, 205 + const struct genl_family *family, 204 206 int flags, u8 cmd) 205 207 { 206 208 return genlmsg_put(skb, info->snd_portid, info->snd_seq, family, ··· 237 239 * @group: offset of multicast group in groups array 238 240 * @flags: allocation flags 239 241 */ 240 - static inline int genlmsg_multicast_netns(struct genl_family *family, 242 + static inline int genlmsg_multicast_netns(const struct genl_family *family, 241 243 struct net *net, struct sk_buff *skb, 242 244 u32 portid, unsigned int group, gfp_t flags) 243 245 { ··· 255 257 * @group: offset of multicast group in groups array 256 258 * @flags: allocation flags 257 259 */ 258 - static inline int genlmsg_multicast(struct genl_family *family, 260 + static inline int genlmsg_multicast(const struct genl_family *family, 259 261 struct sk_buff *skb, u32 portid, 260 262 unsigned int group, gfp_t flags) 261 263 { ··· 273 275 * 274 276 * This function must hold the RTNL or rcu_read_lock(). 275 277 */ 276 - int genlmsg_multicast_allns(struct genl_family *family, 278 + int genlmsg_multicast_allns(const struct genl_family *family, 277 279 struct sk_buff *skb, u32 portid, 278 280 unsigned int group, gfp_t flags); 279 281 ··· 357 359 * This function returns the number of broadcast listeners that have set the 358 360 * NETLINK_RECV_NO_ENOBUFS socket option. 359 361 */ 360 - static inline int genl_set_err(struct genl_family *family, struct net *net, 361 - u32 portid, u32 group, int code) 362 + static inline int genl_set_err(const struct genl_family *family, 363 + struct net *net, u32 portid, 364 + u32 group, int code) 362 365 { 363 366 if (WARN_ON_ONCE(group >= family->n_mcgrps)) 364 367 return -EINVAL; ··· 367 368 return netlink_set_err(net->genl_sock, portid, group, code); 368 369 } 369 370 370 - static inline int genl_has_listeners(struct genl_family *family, 371 + static inline int genl_has_listeners(const struct genl_family *family, 371 372 struct net *net, unsigned int group) 372 373 { 373 374 if (WARN_ON_ONCE(group >= family->n_mcgrps))
+2
include/uapi/linux/genetlink.h
··· 29 29 #define GENL_ID_CTRL NLMSG_MIN_TYPE 30 30 #define GENL_ID_VFS_DQUOT (NLMSG_MIN_TYPE + 1) 31 31 #define GENL_ID_PMCRAID (NLMSG_MIN_TYPE + 2) 32 + /* must be last reserved + 1 */ 33 + #define GENL_START_ALLOC (NLMSG_MIN_TYPE + 3) 32 34 33 35 /************************************************************************** 34 36 * Controller
+106 -165
net/netlink/genetlink.c
··· 17 17 #include <linux/mutex.h> 18 18 #include <linux/bitmap.h> 19 19 #include <linux/rwsem.h> 20 + #include <linux/idr.h> 20 21 #include <net/sock.h> 21 22 #include <net/genetlink.h> 22 23 ··· 59 58 up_write(&cb_lock); 60 59 } 61 60 62 - #define GENL_FAM_TAB_SIZE 16 63 - #define GENL_FAM_TAB_MASK (GENL_FAM_TAB_SIZE - 1) 61 + static DEFINE_IDR(genl_fam_idr); 64 62 65 - static struct list_head family_ht[GENL_FAM_TAB_SIZE]; 66 63 /* 67 64 * Bitmap of multicast groups that are currently in use. 68 65 * ··· 85 86 static unsigned long *mc_groups = &mc_group_start; 86 87 static unsigned long mc_groups_longs = 1; 87 88 88 - static int genl_ctrl_event(int event, struct genl_family *family, 89 + static int genl_ctrl_event(int event, const struct genl_family *family, 89 90 const struct genl_multicast_group *grp, 90 91 int grp_id); 91 92 92 - static inline unsigned int genl_family_hash(unsigned int id) 93 + static const struct genl_family *genl_family_find_byid(unsigned int id) 93 94 { 94 - return id & GENL_FAM_TAB_MASK; 95 + return idr_find(&genl_fam_idr, id); 95 96 } 96 97 97 - static inline struct list_head *genl_family_chain(unsigned int id) 98 + static const struct genl_family *genl_family_find_byname(char *name) 98 99 { 99 - return &family_ht[genl_family_hash(id)]; 100 - } 100 + const struct genl_family *family; 101 + unsigned int id; 101 102 102 - static struct genl_family *genl_family_find_byid(unsigned int id) 103 - { 104 - struct genl_family *f; 105 - 106 - list_for_each_entry(f, genl_family_chain(id), family_list) 107 - if (f->id == id) 108 - return f; 103 + idr_for_each_entry(&genl_fam_idr, family, id) 104 + if (strcmp(family->name, name) == 0) 105 + return family; 109 106 110 107 return NULL; 111 108 } 112 109 113 - static struct genl_family *genl_family_find_byname(char *name) 114 - { 115 - struct genl_family *f; 116 - int i; 117 - 118 - for (i = 0; i < GENL_FAM_TAB_SIZE; i++) 119 - list_for_each_entry(f, genl_family_chain(i), family_list) 120 - if (strcmp(f->name, name) == 0) 121 - return f; 122 - 123 - return NULL; 124 - } 125 - 126 - static const struct genl_ops *genl_get_cmd(u8 cmd, struct genl_family *family) 110 + static const struct genl_ops *genl_get_cmd(u8 cmd, 111 + const struct genl_family *family) 127 112 { 128 113 int i; 129 114 ··· 116 133 return &family->ops[i]; 117 134 118 135 return NULL; 119 - } 120 - 121 - /* Of course we are going to have problems once we hit 122 - * 2^16 alive types, but that can only happen by year 2K 123 - */ 124 - static u16 genl_generate_id(void) 125 - { 126 - static u16 id_gen_idx = GENL_MIN_ID; 127 - int i; 128 - 129 - for (i = 0; i <= GENL_MAX_ID - GENL_MIN_ID; i++) { 130 - if (id_gen_idx != GENL_ID_VFS_DQUOT && 131 - id_gen_idx != GENL_ID_PMCRAID && 132 - !genl_family_find_byid(id_gen_idx)) 133 - return id_gen_idx; 134 - if (++id_gen_idx > GENL_MAX_ID) 135 - id_gen_idx = GENL_MIN_ID; 136 - } 137 - 138 - return 0; 139 136 } 140 137 141 138 static int genl_allocate_reserve_groups(int n_groups, int *first_id) ··· 258 295 return err; 259 296 } 260 297 261 - static void genl_unregister_mc_groups(struct genl_family *family) 298 + static void genl_unregister_mc_groups(const struct genl_family *family) 262 299 { 263 300 struct net *net; 264 301 int i; ··· 321 358 int genl_register_family(struct genl_family *family) 322 359 { 323 360 int err, i; 361 + int start = GENL_START_ALLOC, end = GENL_MAX_ID; 324 362 325 363 err = genl_validate_ops(family); 326 364 if (err) ··· 334 370 goto errout_locked; 335 371 } 336 372 373 + /* 374 + * Sadly, a few cases need to be special-cased 375 + * due to them having previously abused the API 376 + * and having used their family ID also as their 377 + * multicast group ID, so we use reserved IDs 378 + * for both to be sure we can do that mapping. 379 + */ 337 380 if (family == &genl_ctrl) { 338 - family->id = GENL_ID_CTRL; 339 - } else { 340 - u16 newid; 341 - 342 - /* this should be left zero in the struct */ 343 - WARN_ON(family->id); 344 - 345 - /* 346 - * Sadly, a few cases need to be special-cased 347 - * due to them having previously abused the API 348 - * and having used their family ID also as their 349 - * multicast group ID, so we use reserved IDs 350 - * for both to be sure we can do that mapping. 351 - */ 352 - if (strcmp(family->name, "pmcraid") == 0) 353 - newid = GENL_ID_PMCRAID; 354 - else if (strcmp(family->name, "VFS_DQUOT") == 0) 355 - newid = GENL_ID_VFS_DQUOT; 356 - else 357 - newid = genl_generate_id(); 358 - 359 - if (!newid) { 360 - err = -ENOMEM; 361 - goto errout_locked; 362 - } 363 - 364 - family->id = newid; 381 + /* and this needs to be special for initial family lookups */ 382 + start = end = GENL_ID_CTRL; 383 + } else if (strcmp(family->name, "pmcraid") == 0) { 384 + start = end = GENL_ID_PMCRAID; 385 + } else if (strcmp(family->name, "VFS_DQUOT") == 0) { 386 + start = end = GENL_ID_VFS_DQUOT; 365 387 } 366 388 367 389 if (family->maxattr && !family->parallel_ops) { ··· 360 410 } else 361 411 family->attrbuf = NULL; 362 412 363 - err = genl_validate_assign_mc_groups(family); 364 - if (err) 413 + family->id = idr_alloc(&genl_fam_idr, family, 414 + start, end + 1, GFP_KERNEL); 415 + if (!family->id) 365 416 goto errout_locked; 366 417 367 - list_add_tail(&family->family_list, genl_family_chain(family->id)); 418 + err = genl_validate_assign_mc_groups(family); 419 + if (err) 420 + goto errout_remove; 421 + 368 422 genl_unlock_all(); 369 423 370 424 /* send all events */ ··· 379 425 380 426 return 0; 381 427 428 + errout_remove: 429 + idr_remove(&genl_fam_idr, family->id); 382 430 errout_locked: 383 431 genl_unlock_all(); 384 432 return err; ··· 395 439 * 396 440 * Returns 0 on success or a negative error code. 397 441 */ 398 - int genl_unregister_family(struct genl_family *family) 442 + int genl_unregister_family(const struct genl_family *family) 399 443 { 400 - struct genl_family *rc; 401 - 402 444 genl_lock_all(); 403 445 404 - list_for_each_entry(rc, genl_family_chain(family->id), family_list) { 405 - if (family->id != rc->id || strcmp(rc->name, family->name)) 406 - continue; 407 - 408 - genl_unregister_mc_groups(family); 409 - 410 - list_del(&rc->family_list); 411 - up_write(&cb_lock); 412 - wait_event(genl_sk_destructing_waitq, 413 - atomic_read(&genl_sk_destructing_cnt) == 0); 414 - genl_unlock(); 415 - 416 - kfree(family->attrbuf); 417 - genl_ctrl_event(CTRL_CMD_DELFAMILY, family, NULL, 0); 418 - return 0; 446 + if (genl_family_find_byid(family->id)) { 447 + genl_unlock_all(); 448 + return -ENOENT; 419 449 } 420 450 421 - genl_unlock_all(); 451 + genl_unregister_mc_groups(family); 422 452 423 - return -ENOENT; 453 + idr_remove(&genl_fam_idr, family->id); 454 + 455 + up_write(&cb_lock); 456 + wait_event(genl_sk_destructing_waitq, 457 + atomic_read(&genl_sk_destructing_cnt) == 0); 458 + genl_unlock(); 459 + 460 + kfree(family->attrbuf); 461 + 462 + genl_ctrl_event(CTRL_CMD_DELFAMILY, family, NULL, 0); 463 + 464 + return 0; 424 465 } 425 466 EXPORT_SYMBOL(genl_unregister_family); 426 467 ··· 433 480 * Returns pointer to user specific header 434 481 */ 435 482 void *genlmsg_put(struct sk_buff *skb, u32 portid, u32 seq, 436 - struct genl_family *family, int flags, u8 cmd) 483 + const struct genl_family *family, int flags, u8 cmd) 437 484 { 438 485 struct nlmsghdr *nlh; 439 486 struct genlmsghdr *hdr; ··· 492 539 return rc; 493 540 } 494 541 495 - static int genl_family_rcv_msg(struct genl_family *family, 542 + static int genl_family_rcv_msg(const struct genl_family *family, 496 543 struct sk_buff *skb, 497 544 struct nlmsghdr *nlh) 498 545 { ··· 604 651 605 652 static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) 606 653 { 607 - struct genl_family *family; 654 + const struct genl_family *family; 608 655 int err; 609 656 610 657 family = genl_family_find_byid(nlh->nlmsg_type); ··· 635 682 636 683 static struct genl_family genl_ctrl; 637 684 638 - static int ctrl_fill_info(struct genl_family *family, u32 portid, u32 seq, 685 + static int ctrl_fill_info(const struct genl_family *family, u32 portid, u32 seq, 639 686 u32 flags, struct sk_buff *skb, u8 cmd) 640 687 { 641 688 void *hdr; ··· 722 769 return -EMSGSIZE; 723 770 } 724 771 725 - static int ctrl_fill_mcgrp_info(struct genl_family *family, 772 + static int ctrl_fill_mcgrp_info(const struct genl_family *family, 726 773 const struct genl_multicast_group *grp, 727 774 int grp_id, u32 portid, u32 seq, u32 flags, 728 775 struct sk_buff *skb, u8 cmd) ··· 765 812 766 813 static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb) 767 814 { 768 - 769 - int i, n = 0; 815 + int n = 0; 770 816 struct genl_family *rt; 771 817 struct net *net = sock_net(skb->sk); 772 - int chains_to_skip = cb->args[0]; 773 - int fams_to_skip = cb->args[1]; 818 + int fams_to_skip = cb->args[0]; 819 + unsigned int id; 774 820 775 - for (i = chains_to_skip; i < GENL_FAM_TAB_SIZE; i++) { 776 - n = 0; 777 - list_for_each_entry(rt, genl_family_chain(i), family_list) { 778 - if (!rt->netnsok && !net_eq(net, &init_net)) 779 - continue; 780 - if (++n < fams_to_skip) 781 - continue; 782 - if (ctrl_fill_info(rt, NETLINK_CB(cb->skb).portid, 783 - cb->nlh->nlmsg_seq, NLM_F_MULTI, 784 - skb, CTRL_CMD_NEWFAMILY) < 0) 785 - goto errout; 786 - } 821 + idr_for_each_entry(&genl_fam_idr, rt, id) { 822 + if (!rt->netnsok && !net_eq(net, &init_net)) 823 + continue; 787 824 788 - fams_to_skip = 0; 825 + if (n++ < fams_to_skip) 826 + continue; 827 + 828 + if (ctrl_fill_info(rt, NETLINK_CB(cb->skb).portid, 829 + cb->nlh->nlmsg_seq, NLM_F_MULTI, 830 + skb, CTRL_CMD_NEWFAMILY) < 0) 831 + break; 789 832 } 790 833 791 - errout: 792 - cb->args[0] = i; 793 - cb->args[1] = n; 794 - 834 + cb->args[0] = n; 795 835 return skb->len; 796 836 } 797 837 798 - static struct sk_buff *ctrl_build_family_msg(struct genl_family *family, 838 + static struct sk_buff *ctrl_build_family_msg(const struct genl_family *family, 799 839 u32 portid, int seq, u8 cmd) 800 840 { 801 841 struct sk_buff *skb; ··· 808 862 } 809 863 810 864 static struct sk_buff * 811 - ctrl_build_mcgrp_msg(struct genl_family *family, 865 + ctrl_build_mcgrp_msg(const struct genl_family *family, 812 866 const struct genl_multicast_group *grp, 813 867 int grp_id, u32 portid, int seq, u8 cmd) 814 868 { ··· 838 892 static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info) 839 893 { 840 894 struct sk_buff *msg; 841 - struct genl_family *res = NULL; 895 + const struct genl_family *res = NULL; 842 896 int err = -EINVAL; 843 897 844 898 if (info->attrs[CTRL_ATTR_FAMILY_ID]) { ··· 882 936 return genlmsg_reply(msg, info); 883 937 } 884 938 885 - static int genl_ctrl_event(int event, struct genl_family *family, 939 + static int genl_ctrl_event(int event, const struct genl_family *family, 886 940 const struct genl_multicast_group *grp, 887 941 int grp_id) 888 942 { ··· 951 1005 952 1006 static int genl_bind(struct net *net, int group) 953 1007 { 954 - int i, err = -ENOENT; 1008 + struct genl_family *f; 1009 + int err = -ENOENT; 1010 + unsigned int id; 955 1011 956 1012 down_read(&cb_lock); 957 - for (i = 0; i < GENL_FAM_TAB_SIZE; i++) { 958 - struct genl_family *f; 959 1013 960 - list_for_each_entry(f, genl_family_chain(i), family_list) { 961 - if (group >= f->mcgrp_offset && 962 - group < f->mcgrp_offset + f->n_mcgrps) { 963 - int fam_grp = group - f->mcgrp_offset; 1014 + idr_for_each_entry(&genl_fam_idr, f, id) { 1015 + if (group >= f->mcgrp_offset && 1016 + group < f->mcgrp_offset + f->n_mcgrps) { 1017 + int fam_grp = group - f->mcgrp_offset; 964 1018 965 - if (!f->netnsok && net != &init_net) 966 - err = -ENOENT; 967 - else if (f->mcast_bind) 968 - err = f->mcast_bind(net, fam_grp); 969 - else 970 - err = 0; 971 - break; 972 - } 1019 + if (!f->netnsok && net != &init_net) 1020 + err = -ENOENT; 1021 + else if (f->mcast_bind) 1022 + err = f->mcast_bind(net, fam_grp); 1023 + else 1024 + err = 0; 1025 + break; 973 1026 } 974 1027 } 975 1028 up_read(&cb_lock); ··· 978 1033 979 1034 static void genl_unbind(struct net *net, int group) 980 1035 { 981 - int i; 1036 + struct genl_family *f; 1037 + unsigned int id; 982 1038 983 1039 down_read(&cb_lock); 984 - for (i = 0; i < GENL_FAM_TAB_SIZE; i++) { 985 - struct genl_family *f; 986 1040 987 - list_for_each_entry(f, genl_family_chain(i), family_list) { 988 - if (group >= f->mcgrp_offset && 989 - group < f->mcgrp_offset + f->n_mcgrps) { 990 - int fam_grp = group - f->mcgrp_offset; 1041 + idr_for_each_entry(&genl_fam_idr, f, id) { 1042 + if (group >= f->mcgrp_offset && 1043 + group < f->mcgrp_offset + f->n_mcgrps) { 1044 + int fam_grp = group - f->mcgrp_offset; 991 1045 992 - if (f->mcast_unbind) 993 - f->mcast_unbind(net, fam_grp); 994 - break; 995 - } 1046 + if (f->mcast_unbind) 1047 + f->mcast_unbind(net, fam_grp); 1048 + break; 996 1049 } 997 1050 } 998 1051 up_read(&cb_lock); ··· 1030 1087 1031 1088 static int __init genl_init(void) 1032 1089 { 1033 - int i, err; 1034 - 1035 - for (i = 0; i < GENL_FAM_TAB_SIZE; i++) 1036 - INIT_LIST_HEAD(&family_ht[i]); 1090 + int err; 1037 1091 1038 1092 err = genl_register_family(&genl_ctrl); 1039 1093 if (err < 0) ··· 1058 1118 * You cannot use this function with a family that has parallel_ops 1059 1119 * and you can only use it within (pre/post) doit/dumpit callbacks. 1060 1120 */ 1061 - struct nlattr **genl_family_attrbuf(struct genl_family *family) 1121 + struct nlattr **genl_family_attrbuf(const struct genl_family *family) 1062 1122 { 1063 1123 if (!WARN_ON(family->parallel_ops)) 1064 1124 lockdep_assert_held(&genl_mutex); ··· 1096 1156 return err; 1097 1157 } 1098 1158 1099 - int genlmsg_multicast_allns(struct genl_family *family, struct sk_buff *skb, 1100 - u32 portid, unsigned int group, gfp_t flags) 1159 + int genlmsg_multicast_allns(const struct genl_family *family, 1160 + struct sk_buff *skb, u32 portid, 1161 + unsigned int group, gfp_t flags) 1101 1162 { 1102 1163 if (WARN_ON_ONCE(group >= family->n_mcgrps)) 1103 1164 return -EINVAL; ··· 1107 1166 } 1108 1167 EXPORT_SYMBOL(genlmsg_multicast_allns); 1109 1168 1110 - void genl_notify(struct genl_family *family, struct sk_buff *skb, 1169 + void genl_notify(const struct genl_family *family, struct sk_buff *skb, 1111 1170 struct genl_info *info, u32 group, gfp_t flags) 1112 1171 { 1113 1172 struct net *net = genl_info_net(info);