#define ACT_P_CREATED 1
 #define ACT_P_DELETED 1
 
+typedef void (*tc_action_priv_destructor)(void *priv);
+
 struct tc_action_ops {
        struct list_head head;
        char    kind[IFNAMSIZ];
        size_t  (*get_fill_size)(const struct tc_action *act);
        struct net_device *(*get_dev)(const struct tc_action *a);
        void    (*put_dev)(struct net_device *dev);
+       struct psample_group *
+       (*get_psample_group)(const struct tc_action *a,
+                            tc_action_priv_destructor *destructor);
 };
 
 struct tc_action_net {
 
 };
 
 struct psample_group *psample_group_get(struct net *net, u32 group_num);
+void psample_group_take(struct psample_group *group);
 void psample_group_put(struct psample_group *group);
 
 #if IS_ENABLED(CONFIG_PSAMPLE)
 
        return to_sample(a)->trunc_size;
 }
 
-static inline struct psample_group *
-tcf_sample_psample_group(const struct tc_action *a)
-{
-       return rcu_dereference_rtnl(to_sample(a)->psample_group);
-}
-
 #endif /* __NET_TC_SAMPLE_H */
 
        int idx = 0;
        int err;
 
-       spin_lock(&psample_groups_lock);
+       spin_lock_bh(&psample_groups_lock);
        list_for_each_entry(group, &psample_groups_list, list) {
                if (!net_eq(group->net, sock_net(msg->sk)))
                        continue;
                idx++;
        }
 
-       spin_unlock(&psample_groups_lock);
+       spin_unlock_bh(&psample_groups_lock);
        cb->args[0] = idx;
        return msg->len;
 }
 {
        struct psample_group *group;
 
-       spin_lock(&psample_groups_lock);
+       spin_lock_bh(&psample_groups_lock);
 
        group = psample_group_lookup(net, group_num);
        if (!group) {
        group->refcount++;
 
 out:
-       spin_unlock(&psample_groups_lock);
+       spin_unlock_bh(&psample_groups_lock);
        return group;
 }
 EXPORT_SYMBOL_GPL(psample_group_get);
 
+void psample_group_take(struct psample_group *group)
+{
+       spin_lock_bh(&psample_groups_lock);
+       group->refcount++;
+       spin_unlock_bh(&psample_groups_lock);
+}
+EXPORT_SYMBOL_GPL(psample_group_take);
+
 void psample_group_put(struct psample_group *group)
 {
-       spin_lock(&psample_groups_lock);
+       spin_lock_bh(&psample_groups_lock);
 
        if (--group->refcount == 0)
                psample_group_destroy(group);
 
-       spin_unlock(&psample_groups_lock);
+       spin_unlock_bh(&psample_groups_lock);
 }
 EXPORT_SYMBOL_GPL(psample_group_put);
 
 
        return tcf_idr_search(tn, a, index);
 }
 
+static void tcf_psample_group_put(void *priv)
+{
+       struct psample_group *group = priv;
+
+       psample_group_put(group);
+}
+
+static struct psample_group *
+tcf_sample_get_group(const struct tc_action *a,
+                    tc_action_priv_destructor *destructor)
+{
+       struct tcf_sample *s = to_sample(a);
+       struct psample_group *group;
+
+       spin_lock_bh(&s->tcf_lock);
+       group = rcu_dereference_protected(s->psample_group,
+                                         lockdep_is_held(&s->tcf_lock));
+       if (group) {
+               psample_group_take(group);
+               *destructor = tcf_psample_group_put;
+       }
+       spin_unlock_bh(&s->tcf_lock);
+
+       return group;
+}
+
 static struct tc_action_ops act_sample_ops = {
        .kind     = "sample",
        .id       = TCA_ID_SAMPLE,
        .cleanup  = tcf_sample_cleanup,
        .walk     = tcf_sample_walker,
        .lookup   = tcf_sample_search,
+       .get_psample_group = tcf_sample_get_group,
        .size     = sizeof(struct tcf_sample),
 };
 
 
        return 0;
 }
 
+static void tcf_sample_get_group(struct flow_action_entry *entry,
+                                const struct tc_action *act)
+{
+#ifdef CONFIG_NET_CLS_ACT
+       entry->sample.psample_group =
+               act->ops->get_psample_group(act, &entry->destructor);
+       entry->destructor_priv = entry->sample.psample_group;
+#endif
+}
+
 int tc_setup_flow_action(struct flow_action *flow_action,
                         const struct tcf_exts *exts, bool rtnl_held)
 {
                        entry->mark = tcf_skbedit_mark(act);
                } else if (is_tcf_sample(act)) {
                        entry->id = FLOW_ACTION_SAMPLE;
-                       entry->sample.psample_group =
-                               tcf_sample_psample_group(act);
                        entry->sample.trunc_size = tcf_sample_trunc_size(act);
                        entry->sample.truncate = tcf_sample_truncate(act);
                        entry->sample.rate = tcf_sample_rate(act);
+                       tcf_sample_get_group(entry, act);
                } else if (is_tcf_police(act)) {
                        entry->id = FLOW_ACTION_POLICE;
                        entry->police.burst = tcf_police_tcfp_burst(act);