This patch does this for target extensions' destroy functions.
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
Signed-off-by: Patrick McHardy <kaber@trash.net>
        unsigned int hook_mask;
 };
 
+/* Target destructor parameters */
+struct xt_tgdtor_param {
+       const struct xt_target *target;
+       void *targinfo;
+};
+
 struct xt_match
 {
        struct list_head list;
        bool (*checkentry)(const struct xt_tgchk_param *);
 
        /* Called when entry of this type deleted. */
-       void (*destroy)(const struct xt_target *target, void *targinfo);
+       void (*destroy)(const struct xt_tgdtor_param *);
 
        /* Called when userspace align differs from kernel space one */
        void (*compat_from_user)(void *dst, void *src);
 
 static inline int
 ebt_cleanup_watcher(struct ebt_entry_watcher *w, unsigned int *i)
 {
+       struct xt_tgdtor_param par;
+
        if (i && (*i)-- == 0)
                return 1;
-       if (w->u.watcher->destroy)
-               w->u.watcher->destroy(w->u.watcher, w->data);
-       module_put(w->u.watcher->me);
 
+       par.target   = w->u.watcher;
+       par.targinfo = w->data;
+       if (par.target->destroy != NULL)
+               par.target->destroy(&par);
+       module_put(par.target->me);
        return 0;
 }
 
 static inline int
 ebt_cleanup_entry(struct ebt_entry *e, unsigned int *cnt)
 {
+       struct xt_tgdtor_param par;
        struct ebt_entry_target *t;
 
        if (e->bitmask == 0)
        EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, NULL);
        EBT_MATCH_ITERATE(e, ebt_cleanup_match, NULL);
        t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
-       if (t->u.target->destroy)
-               t->u.target->destroy(t->u.target, t->data);
-       module_put(t->u.target->me);
 
+       par.target   = t->u.target;
+       par.targinfo = t->data;
+       if (par.target->destroy != NULL)
+               par.target->destroy(&par);
+       module_put(par.target->me);
        return 0;
 }
 
 
 
 static inline int cleanup_entry(struct arpt_entry *e, unsigned int *i)
 {
+       struct xt_tgdtor_param par;
        struct arpt_entry_target *t;
 
        if (i && (*i)-- == 0)
                return 1;
 
        t = arpt_get_target(e);
-       if (t->u.kernel.target->destroy)
-               t->u.kernel.target->destroy(t->u.kernel.target, t->data);
-       module_put(t->u.kernel.target->me);
+       par.target   = t->u.kernel.target;
+       par.targinfo = t->data;
+       if (par.target->destroy != NULL)
+               par.target->destroy(&par);
+       module_put(par.target->me);
        return 0;
 }
 
 
 static int
 cleanup_entry(struct ipt_entry *e, unsigned int *i)
 {
+       struct xt_tgdtor_param par;
        struct ipt_entry_target *t;
 
        if (i && (*i)-- == 0)
        /* Cleanup all matches */
        IPT_MATCH_ITERATE(e, cleanup_match, NULL);
        t = ipt_get_target(e);
-       if (t->u.kernel.target->destroy)
-               t->u.kernel.target->destroy(t->u.kernel.target, t->data);
-       module_put(t->u.kernel.target->me);
+
+       par.target   = t->u.kernel.target;
+       par.targinfo = t->data;
+       if (par.target->destroy != NULL)
+               par.target->destroy(&par);
+       module_put(par.target->me);
        return 0;
 }
 
 
 }
 
 /* drop reference count of cluster config when rule is deleted */
-static void clusterip_tg_destroy(const struct xt_target *target, void *targinfo)
+static void clusterip_tg_destroy(const struct xt_tgdtor_param *par)
 {
-       const struct ipt_clusterip_tgt_info *cipinfo = targinfo;
+       const struct ipt_clusterip_tgt_info *cipinfo = par->targinfo;
 
        /* if no more entries are referencing the config, remove it
         * from the list and destroy the proc entry */
 
        clusterip_config_put(cipinfo->config);
 
-       nf_ct_l3proto_module_put(target->family);
+       nf_ct_l3proto_module_put(par->target->family);
 }
 
 #ifdef CONFIG_COMPAT
 
 static int
 cleanup_entry(struct ip6t_entry *e, unsigned int *i)
 {
+       struct xt_tgdtor_param par;
        struct ip6t_entry_target *t;
 
        if (i && (*i)-- == 0)
        /* Cleanup all matches */
        IP6T_MATCH_ITERATE(e, cleanup_match, NULL);
        t = ip6t_get_target(e);
-       if (t->u.kernel.target->destroy)
-               t->u.kernel.target->destroy(t->u.kernel.target, t->data);
-       module_put(t->u.kernel.target->me);
+
+       par.target   = t->u.kernel.target;
+       par.targinfo = t->data;
+       if (par.target->destroy != NULL)
+               par.target->destroy(&par);
+       module_put(par.target->me);
        return 0;
 }
 
 
        return true;
 }
 
-static void
-connmark_tg_destroy(const struct xt_target *target, void *targinfo)
+static void connmark_tg_destroy(const struct xt_tgdtor_param *par)
 {
-       nf_ct_l3proto_module_put(target->family);
+       nf_ct_l3proto_module_put(par->target->family);
 }
 
 #ifdef CONFIG_COMPAT
 
        return true;
 }
 
-static void
-connsecmark_tg_destroy(const struct xt_target *target, void *targinfo)
+static void connsecmark_tg_destroy(const struct xt_tgdtor_param *par)
 {
-       nf_ct_l3proto_module_put(target->family);
+       nf_ct_l3proto_module_put(par->target->family);
 }
 
 static struct xt_target connsecmark_tg_reg[] __read_mostly = {
 
        return false;
 }
 
-static void xt_rateest_tg_destroy(const struct xt_target *target,
-                                 void *targinfo)
+static void xt_rateest_tg_destroy(const struct xt_tgdtor_param *par)
 {
-       struct xt_rateest_target_info *info = targinfo;
+       struct xt_rateest_target_info *info = par->targinfo;
 
        xt_rateest_put(info->est);
 }
 
        return true;
 }
 
-static void secmark_tg_destroy(const struct xt_target *target, void *targinfo)
+static void secmark_tg_destroy(const struct xt_tgdtor_param *par)
 {
        switch (mode) {
        case SECMARK_MODE_SEL:
 
 
 static void ipt_destroy_target(struct ipt_entry_target *t)
 {
-       if (t->u.kernel.target->destroy)
-               t->u.kernel.target->destroy(t->u.kernel.target, t->data);
-       module_put(t->u.kernel.target->me);
+       struct xt_tgdtor_param par = {
+               .target   = t->u.kernel.target,
+               .targinfo = t->data,
+       };
+       if (par.target->destroy != NULL)
+               par.target->destroy(&par);
+       module_put(par.target->me);
 }
 
 static int tcf_ipt_release(struct tcf_ipt *ipt, int bind)