diff options
| author | Johannes Berg <johannes.berg@intel.com> | 2013-11-14 11:14:44 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2013-11-14 17:10:41 -0500 |
| commit | d91824c08fbcb265ec930d863fa905e8daa836a4 (patch) | |
| tree | 2f3c2f27b68f46e1dc5e1fc3139cd52942f818b2 | |
| parent | 3686ec5e84977eddc796903177e7e0a122585c11 (diff) | |
genetlink: register family ops as array
Instead of using a linked list, use an array. This reduces
the data size needed by the users of genetlink, for example
in wireless (net/wireless/nl80211.c) on 64-bit it frees up
over 1K of data space.
Remove the attempted sending of CTRL_CMD_NEWOPS ctrl event
since genl_ctrl_event(CTRL_CMD_NEWOPS, ...) only returns
-EINVAL anyway, therefore no such event could ever be sent.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | include/net/genetlink.h | 7 | ||||
| -rw-r--r-- | net/netlink/genetlink.c | 78 |
2 files changed, 37 insertions, 48 deletions
diff --git a/include/net/genetlink.h b/include/net/genetlink.h index 617d718524b0..d4802af1a8b3 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h | |||
| @@ -39,9 +39,10 @@ struct genl_info; | |||
| 39 | * @post_doit: called after an operation's doit callback, it may | 39 | * @post_doit: called after an operation's doit callback, it may |
| 40 | * undo operations done by pre_doit, for example release locks | 40 | * undo operations done by pre_doit, for example release locks |
| 41 | * @attrbuf: buffer to store parsed attributes | 41 | * @attrbuf: buffer to store parsed attributes |
| 42 | * @ops_list: list of all assigned operations | ||
| 43 | * @family_list: family list | 42 | * @family_list: family list |
| 44 | * @mcast_groups: multicast groups list | 43 | * @mcast_groups: multicast groups list |
| 44 | * @ops: the operations supported by this family (private) | ||
| 45 | * @n_ops: number of operations supported by this family (private) | ||
| 45 | */ | 46 | */ |
| 46 | struct genl_family { | 47 | struct genl_family { |
| 47 | unsigned int id; | 48 | unsigned int id; |
| @@ -58,7 +59,8 @@ struct genl_family { | |||
| 58 | struct sk_buff *skb, | 59 | struct sk_buff *skb, |
| 59 | struct genl_info *info); | 60 | struct genl_info *info); |
| 60 | struct nlattr ** attrbuf; /* private */ | 61 | struct nlattr ** attrbuf; /* private */ |
| 61 | struct list_head ops_list; /* private */ | 62 | struct genl_ops * ops; /* private */ |
| 63 | unsigned int n_ops; /* private */ | ||
| 62 | struct list_head family_list; /* private */ | 64 | struct list_head family_list; /* private */ |
| 63 | struct list_head mcast_groups; /* private */ | 65 | struct list_head mcast_groups; /* private */ |
| 64 | struct module *module; | 66 | struct module *module; |
| @@ -119,7 +121,6 @@ struct genl_ops { | |||
| 119 | int (*dumpit)(struct sk_buff *skb, | 121 | int (*dumpit)(struct sk_buff *skb, |
| 120 | struct netlink_callback *cb); | 122 | struct netlink_callback *cb); |
| 121 | int (*done)(struct netlink_callback *cb); | 123 | int (*done)(struct netlink_callback *cb); |
| 122 | struct list_head ops_list; | ||
| 123 | }; | 124 | }; |
| 124 | 125 | ||
| 125 | int __genl_register_family(struct genl_family *family); | 126 | int __genl_register_family(struct genl_family *family); |
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index fbccb45e8cc1..d8273b057763 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c | |||
| @@ -108,11 +108,11 @@ static struct genl_family *genl_family_find_byname(char *name) | |||
| 108 | 108 | ||
| 109 | static struct genl_ops *genl_get_cmd(u8 cmd, struct genl_family *family) | 109 | static struct genl_ops *genl_get_cmd(u8 cmd, struct genl_family *family) |
| 110 | { | 110 | { |
| 111 | struct genl_ops *ops; | 111 | int i; |
| 112 | 112 | ||
| 113 | list_for_each_entry(ops, &family->ops_list, ops_list) | 113 | for (i = 0; i < family->n_ops; i++) |
| 114 | if (ops->cmd == cmd) | 114 | if (family->ops[i].cmd == cmd) |
| 115 | return ops; | 115 | return &family->ops[i]; |
| 116 | 116 | ||
| 117 | return NULL; | 117 | return NULL; |
| 118 | } | 118 | } |
| @@ -283,33 +283,30 @@ static void genl_unregister_mc_groups(struct genl_family *family) | |||
| 283 | __genl_unregister_mc_group(family, grp); | 283 | __genl_unregister_mc_group(family, grp); |
| 284 | } | 284 | } |
| 285 | 285 | ||
| 286 | static int genl_register_ops(struct genl_family *family, struct genl_ops *ops) | 286 | static int genl_validate_add_ops(struct genl_family *family, struct genl_ops *ops, |
| 287 | unsigned int n_ops) | ||
| 287 | { | 288 | { |
| 288 | int err = -EINVAL; | 289 | int i, j; |
| 289 | 290 | ||
| 290 | if (ops->dumpit == NULL && ops->doit == NULL) | 291 | for (i = 0; i < n_ops; i++) { |
| 291 | goto errout; | 292 | if (ops[i].dumpit == NULL && ops[i].doit == NULL) |
| 292 | 293 | return -EINVAL; | |
| 293 | if (genl_get_cmd(ops->cmd, family)) { | 294 | for (j = i + 1; j < n_ops; j++) |
| 294 | err = -EEXIST; | 295 | if (ops[i].cmd == ops[j].cmd) |
| 295 | goto errout; | 296 | return -EINVAL; |
| 297 | if (ops[i].dumpit) | ||
| 298 | ops[i].flags |= GENL_CMD_CAP_DUMP; | ||
| 299 | if (ops[i].doit) | ||
| 300 | ops[i].flags |= GENL_CMD_CAP_DO; | ||
| 301 | if (ops[i].policy) | ||
| 302 | ops[i].flags |= GENL_CMD_CAP_HASPOL; | ||
| 296 | } | 303 | } |
| 297 | 304 | ||
| 298 | if (ops->dumpit) | 305 | /* family is not registered yet, so no locking needed */ |
| 299 | ops->flags |= GENL_CMD_CAP_DUMP; | 306 | family->ops = ops; |
| 300 | if (ops->doit) | 307 | family->n_ops = n_ops; |
| 301 | ops->flags |= GENL_CMD_CAP_DO; | ||
| 302 | if (ops->policy) | ||
| 303 | ops->flags |= GENL_CMD_CAP_HASPOL; | ||
| 304 | |||
| 305 | genl_lock_all(); | ||
| 306 | list_add_tail(&ops->ops_list, &family->ops_list); | ||
| 307 | genl_unlock_all(); | ||
| 308 | 308 | ||
| 309 | genl_ctrl_event(CTRL_CMD_NEWOPS, ops); | 309 | return 0; |
| 310 | err = 0; | ||
| 311 | errout: | ||
| 312 | return err; | ||
| 313 | } | 310 | } |
| 314 | 311 | ||
| 315 | /** | 312 | /** |
| @@ -333,7 +330,6 @@ int __genl_register_family(struct genl_family *family) | |||
| 333 | if (family->id > GENL_MAX_ID) | 330 | if (family->id > GENL_MAX_ID) |
| 334 | goto errout; | 331 | goto errout; |
| 335 | 332 | ||
| 336 | INIT_LIST_HEAD(&family->ops_list); | ||
| 337 | INIT_LIST_HEAD(&family->mcast_groups); | 333 | INIT_LIST_HEAD(&family->mcast_groups); |
| 338 | 334 | ||
| 339 | genl_lock_all(); | 335 | genl_lock_all(); |
| @@ -405,21 +401,13 @@ EXPORT_SYMBOL(__genl_register_family); | |||
| 405 | int __genl_register_family_with_ops(struct genl_family *family, | 401 | int __genl_register_family_with_ops(struct genl_family *family, |
| 406 | struct genl_ops *ops, size_t n_ops) | 402 | struct genl_ops *ops, size_t n_ops) |
| 407 | { | 403 | { |
| 408 | int err, i; | 404 | int err; |
| 409 | 405 | ||
| 410 | err = __genl_register_family(family); | 406 | err = genl_validate_add_ops(family, ops, n_ops); |
| 411 | if (err) | 407 | if (err) |
| 412 | return err; | 408 | return err; |
| 413 | 409 | ||
| 414 | for (i = 0; i < n_ops; ++i, ++ops) { | 410 | return __genl_register_family(family); |
| 415 | err = genl_register_ops(family, ops); | ||
| 416 | if (err) | ||
| 417 | goto err_out; | ||
| 418 | } | ||
| 419 | return 0; | ||
| 420 | err_out: | ||
| 421 | genl_unregister_family(family); | ||
| 422 | return err; | ||
| 423 | } | 411 | } |
| 424 | EXPORT_SYMBOL(__genl_register_family_with_ops); | 412 | EXPORT_SYMBOL(__genl_register_family_with_ops); |
| 425 | 413 | ||
| @@ -444,7 +432,7 @@ int genl_unregister_family(struct genl_family *family) | |||
| 444 | continue; | 432 | continue; |
| 445 | 433 | ||
| 446 | list_del(&rc->family_list); | 434 | list_del(&rc->family_list); |
| 447 | INIT_LIST_HEAD(&family->ops_list); | 435 | family->n_ops = 0; |
| 448 | genl_unlock_all(); | 436 | genl_unlock_all(); |
| 449 | 437 | ||
| 450 | kfree(family->attrbuf); | 438 | kfree(family->attrbuf); |
| @@ -671,19 +659,19 @@ static int ctrl_fill_info(struct genl_family *family, u32 portid, u32 seq, | |||
| 671 | nla_put_u32(skb, CTRL_ATTR_MAXATTR, family->maxattr)) | 659 | nla_put_u32(skb, CTRL_ATTR_MAXATTR, family->maxattr)) |
| 672 | goto nla_put_failure; | 660 | goto nla_put_failure; |
| 673 | 661 | ||
| 674 | if (!list_empty(&family->ops_list)) { | 662 | if (family->n_ops) { |
| 675 | struct nlattr *nla_ops; | 663 | struct nlattr *nla_ops; |
| 676 | struct genl_ops *ops; | 664 | int i; |
| 677 | int idx = 1; | ||
| 678 | 665 | ||
| 679 | nla_ops = nla_nest_start(skb, CTRL_ATTR_OPS); | 666 | nla_ops = nla_nest_start(skb, CTRL_ATTR_OPS); |
| 680 | if (nla_ops == NULL) | 667 | if (nla_ops == NULL) |
| 681 | goto nla_put_failure; | 668 | goto nla_put_failure; |
| 682 | 669 | ||
| 683 | list_for_each_entry(ops, &family->ops_list, ops_list) { | 670 | for (i = 0; i < family->n_ops; i++) { |
| 684 | struct nlattr *nest; | 671 | struct nlattr *nest; |
| 672 | struct genl_ops *ops = &family->ops[i]; | ||
| 685 | 673 | ||
| 686 | nest = nla_nest_start(skb, idx++); | 674 | nest = nla_nest_start(skb, i + 1); |
| 687 | if (nest == NULL) | 675 | if (nest == NULL) |
| 688 | goto nla_put_failure; | 676 | goto nla_put_failure; |
| 689 | 677 | ||
