mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-04-07 23:14:21 +00:00
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>
This commit is contained in:
parent
3686ec5e84
commit
d91824c08f
2 changed files with 36 additions and 47 deletions
|
@ -39,9 +39,10 @@ struct genl_info;
|
||||||
* @post_doit: called after an operation's doit callback, it may
|
* @post_doit: called after an operation's doit callback, it may
|
||||||
* undo operations done by pre_doit, for example release locks
|
* undo operations done by pre_doit, for example release locks
|
||||||
* @attrbuf: buffer to store parsed attributes
|
* @attrbuf: buffer to store parsed attributes
|
||||||
* @ops_list: list of all assigned operations
|
|
||||||
* @family_list: family list
|
* @family_list: family list
|
||||||
* @mcast_groups: multicast groups list
|
* @mcast_groups: multicast groups list
|
||||||
|
* @ops: the operations supported by this family (private)
|
||||||
|
* @n_ops: number of operations supported by this family (private)
|
||||||
*/
|
*/
|
||||||
struct genl_family {
|
struct genl_family {
|
||||||
unsigned int id;
|
unsigned int id;
|
||||||
|
@ -58,7 +59,8 @@ struct genl_family {
|
||||||
struct sk_buff *skb,
|
struct sk_buff *skb,
|
||||||
struct genl_info *info);
|
struct genl_info *info);
|
||||||
struct nlattr ** attrbuf; /* private */
|
struct nlattr ** attrbuf; /* private */
|
||||||
struct list_head ops_list; /* private */
|
struct genl_ops * ops; /* private */
|
||||||
|
unsigned int n_ops; /* private */
|
||||||
struct list_head family_list; /* private */
|
struct list_head family_list; /* private */
|
||||||
struct list_head mcast_groups; /* private */
|
struct list_head mcast_groups; /* private */
|
||||||
struct module *module;
|
struct module *module;
|
||||||
|
@ -119,7 +121,6 @@ struct genl_ops {
|
||||||
int (*dumpit)(struct sk_buff *skb,
|
int (*dumpit)(struct sk_buff *skb,
|
||||||
struct netlink_callback *cb);
|
struct netlink_callback *cb);
|
||||||
int (*done)(struct netlink_callback *cb);
|
int (*done)(struct netlink_callback *cb);
|
||||||
struct list_head ops_list;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int __genl_register_family(struct genl_family *family);
|
int __genl_register_family(struct genl_family *family);
|
||||||
|
|
|
@ -108,11 +108,11 @@ static struct genl_family *genl_family_find_byname(char *name)
|
||||||
|
|
||||||
static struct genl_ops *genl_get_cmd(u8 cmd, struct genl_family *family)
|
static struct genl_ops *genl_get_cmd(u8 cmd, struct genl_family *family)
|
||||||
{
|
{
|
||||||
struct genl_ops *ops;
|
int i;
|
||||||
|
|
||||||
list_for_each_entry(ops, &family->ops_list, ops_list)
|
for (i = 0; i < family->n_ops; i++)
|
||||||
if (ops->cmd == cmd)
|
if (family->ops[i].cmd == cmd)
|
||||||
return ops;
|
return &family->ops[i];
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -283,33 +283,30 @@ static void genl_unregister_mc_groups(struct genl_family *family)
|
||||||
__genl_unregister_mc_group(family, grp);
|
__genl_unregister_mc_group(family, grp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int genl_register_ops(struct genl_family *family, struct genl_ops *ops)
|
static int genl_validate_add_ops(struct genl_family *family, struct genl_ops *ops,
|
||||||
|
unsigned int n_ops)
|
||||||
{
|
{
|
||||||
int err = -EINVAL;
|
int i, j;
|
||||||
|
|
||||||
if (ops->dumpit == NULL && ops->doit == NULL)
|
for (i = 0; i < n_ops; i++) {
|
||||||
goto errout;
|
if (ops[i].dumpit == NULL && ops[i].doit == NULL)
|
||||||
|
return -EINVAL;
|
||||||
if (genl_get_cmd(ops->cmd, family)) {
|
for (j = i + 1; j < n_ops; j++)
|
||||||
err = -EEXIST;
|
if (ops[i].cmd == ops[j].cmd)
|
||||||
goto errout;
|
return -EINVAL;
|
||||||
|
if (ops[i].dumpit)
|
||||||
|
ops[i].flags |= GENL_CMD_CAP_DUMP;
|
||||||
|
if (ops[i].doit)
|
||||||
|
ops[i].flags |= GENL_CMD_CAP_DO;
|
||||||
|
if (ops[i].policy)
|
||||||
|
ops[i].flags |= GENL_CMD_CAP_HASPOL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ops->dumpit)
|
/* family is not registered yet, so no locking needed */
|
||||||
ops->flags |= GENL_CMD_CAP_DUMP;
|
family->ops = ops;
|
||||||
if (ops->doit)
|
family->n_ops = n_ops;
|
||||||
ops->flags |= GENL_CMD_CAP_DO;
|
|
||||||
if (ops->policy)
|
|
||||||
ops->flags |= GENL_CMD_CAP_HASPOL;
|
|
||||||
|
|
||||||
genl_lock_all();
|
return 0;
|
||||||
list_add_tail(&ops->ops_list, &family->ops_list);
|
|
||||||
genl_unlock_all();
|
|
||||||
|
|
||||||
genl_ctrl_event(CTRL_CMD_NEWOPS, ops);
|
|
||||||
err = 0;
|
|
||||||
errout:
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -333,7 +330,6 @@ int __genl_register_family(struct genl_family *family)
|
||||||
if (family->id > GENL_MAX_ID)
|
if (family->id > GENL_MAX_ID)
|
||||||
goto errout;
|
goto errout;
|
||||||
|
|
||||||
INIT_LIST_HEAD(&family->ops_list);
|
|
||||||
INIT_LIST_HEAD(&family->mcast_groups);
|
INIT_LIST_HEAD(&family->mcast_groups);
|
||||||
|
|
||||||
genl_lock_all();
|
genl_lock_all();
|
||||||
|
@ -405,21 +401,13 @@ EXPORT_SYMBOL(__genl_register_family);
|
||||||
int __genl_register_family_with_ops(struct genl_family *family,
|
int __genl_register_family_with_ops(struct genl_family *family,
|
||||||
struct genl_ops *ops, size_t n_ops)
|
struct genl_ops *ops, size_t n_ops)
|
||||||
{
|
{
|
||||||
int err, i;
|
int err;
|
||||||
|
|
||||||
err = __genl_register_family(family);
|
err = genl_validate_add_ops(family, ops, n_ops);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
for (i = 0; i < n_ops; ++i, ++ops) {
|
return __genl_register_family(family);
|
||||||
err = genl_register_ops(family, ops);
|
|
||||||
if (err)
|
|
||||||
goto err_out;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
err_out:
|
|
||||||
genl_unregister_family(family);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(__genl_register_family_with_ops);
|
EXPORT_SYMBOL(__genl_register_family_with_ops);
|
||||||
|
|
||||||
|
@ -444,7 +432,7 @@ int genl_unregister_family(struct genl_family *family)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
list_del(&rc->family_list);
|
list_del(&rc->family_list);
|
||||||
INIT_LIST_HEAD(&family->ops_list);
|
family->n_ops = 0;
|
||||||
genl_unlock_all();
|
genl_unlock_all();
|
||||||
|
|
||||||
kfree(family->attrbuf);
|
kfree(family->attrbuf);
|
||||||
|
@ -671,19 +659,19 @@ static int ctrl_fill_info(struct genl_family *family, u32 portid, u32 seq,
|
||||||
nla_put_u32(skb, CTRL_ATTR_MAXATTR, family->maxattr))
|
nla_put_u32(skb, CTRL_ATTR_MAXATTR, family->maxattr))
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
|
|
||||||
if (!list_empty(&family->ops_list)) {
|
if (family->n_ops) {
|
||||||
struct nlattr *nla_ops;
|
struct nlattr *nla_ops;
|
||||||
struct genl_ops *ops;
|
int i;
|
||||||
int idx = 1;
|
|
||||||
|
|
||||||
nla_ops = nla_nest_start(skb, CTRL_ATTR_OPS);
|
nla_ops = nla_nest_start(skb, CTRL_ATTR_OPS);
|
||||||
if (nla_ops == NULL)
|
if (nla_ops == NULL)
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
|
|
||||||
list_for_each_entry(ops, &family->ops_list, ops_list) {
|
for (i = 0; i < family->n_ops; i++) {
|
||||||
struct nlattr *nest;
|
struct nlattr *nest;
|
||||||
|
struct genl_ops *ops = &family->ops[i];
|
||||||
|
|
||||||
nest = nla_nest_start(skb, idx++);
|
nest = nla_nest_start(skb, i + 1);
|
||||||
if (nest == NULL)
|
if (nest == NULL)
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue