diff options
author | Johannes Berg <johannes.berg@intel.com> | 2017-10-26 10:22:53 +0200 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2017-10-26 10:22:53 +0200 |
commit | 75fadbc1381e4aef826177591a02968998f5ebe7 (patch) | |
tree | 239ac55d3d6093ef261d76c934b9ad0fa217bc2b /backport | |
parent | 0d4503988a997e6414d1bf074c9a6fc62a7b339c (diff) |
backports: fix the extack backport for dumps
I also never seem to have really tested unload after dumps,
and using the family->attrbuf was causing memory corruption
in the copied family.
Fix this by keeping track of the family copies separately
and actually copying the attrbuf over so the family can use
it from there.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'backport')
-rw-r--r-- | backport/compat/backport-4.12.c | 38 |
1 files changed, 28 insertions, 10 deletions
diff --git a/backport/compat/backport-4.12.c b/backport/compat/backport-4.12.c index 382a3af4..767ecb98 100644 --- a/backport/compat/backport-4.12.c +++ b/backport/compat/backport-4.12.c @@ -19,10 +19,14 @@ enum nlmsgerr_attrs { struct bp_extack_genl_family { struct genl_family family; struct genl_family *real_family; + struct list_head list; struct genl_ops ops[]; }; +static LIST_HEAD(copies_list); +static DEFINE_MUTEX(copies_mutex); + static const struct nla_policy extack_dummy_policy[1] = {}; static struct bp_extack_genl_family *get_copy(__genl_const struct genl_ops *op) @@ -212,25 +216,39 @@ int bp_extack_genl_register_family(struct genl_family *family) copy->family.pre_doit = extack_pre_doit; copy->family.post_doit = extack_post_doit; - /* - * store in attrbuf, so that even if we re-register the family - * the data will be overwritten and we don't overwrite data - * that's used again later... - */ - family->attrbuf = (void *)copy; - err = __real_bp_extack_genl_register_family(©->family); - if (err) + if (err) { kfree(copy); - return err; + return err; + } + + /* copy this since the family might access it directly */ + family->attrbuf = copy->family.attrbuf; + + mutex_lock(&copies_mutex); + list_add_tail(©->list, &copies_list); + mutex_unlock(&copies_mutex); + + return 0; } EXPORT_SYMBOL_GPL(bp_extack_genl_register_family); int bp_extack_genl_unregister_family(struct genl_family *family) { - struct bp_extack_genl_family *copy = (void *)family->attrbuf; + struct bp_extack_genl_family *tmp, *copy = NULL; int err; + mutex_lock(&copies_mutex); + list_for_each_entry(tmp, &copies_list, list) { + if (tmp->real_family == family) { + copy = tmp; + break; + } + } + if (copy) + list_del(©->list); + mutex_unlock(&copies_mutex); + if (!copy) return -ENOENT; |