INIT_LIST_HEAD(&fnew->hw_list);
        refcount_set(&fnew->refcnt, 1);
 
-       err = tcf_exts_init(&fnew->exts, net, TCA_FLOWER_ACT, 0);
-       if (err < 0)
-               goto errout;
-
        if (tb[TCA_FLOWER_FLAGS]) {
                fnew->flags = nla_get_u32(tb[TCA_FLOWER_FLAGS]);
 
                }
        }
 
+       if (!fold) {
+               spin_lock(&tp->lock);
+               if (!handle) {
+                       handle = 1;
+                       err = idr_alloc_u32(&head->handle_idr, fnew, &handle,
+                                           INT_MAX, GFP_ATOMIC);
+               } else {
+                       err = idr_alloc_u32(&head->handle_idr, fnew, &handle,
+                                           handle, GFP_ATOMIC);
+
+                       /* Filter with specified handle was concurrently
+                        * inserted after initial check in cls_api. This is not
+                        * necessarily an error if NLM_F_EXCL is not set in
+                        * message flags. Returning EAGAIN will cause cls_api to
+                        * try to update concurrently inserted rule.
+                        */
+                       if (err == -ENOSPC)
+                               err = -EAGAIN;
+               }
+               spin_unlock(&tp->lock);
+
+               if (err)
+                       goto errout;
+       }
+       fnew->handle = handle;
+
+       err = tcf_exts_init(&fnew->exts, net, TCA_FLOWER_ACT, 0);
+       if (err < 0)
+               goto errout_idr;
+
        err = fl_set_parms(net, tp, fnew, mask, base, tb, tca[TCA_RATE],
                           tp->chain->tmplt_priv, flags, fnew->flags,
                           extack);
        if (err)
-               goto errout;
+               goto errout_idr;
 
        err = fl_check_assign_mask(head, fnew, fold, mask);
        if (err)
-               goto errout;
+               goto errout_idr;
 
        err = fl_ht_insert_unique(fnew, fold, &in_ht);
        if (err)
                refcount_dec(&fold->refcnt);
                __fl_put(fold);
        } else {
-               if (handle) {
-                       /* user specifies a handle and it doesn't exist */
-                       err = idr_alloc_u32(&head->handle_idr, fnew, &handle,
-                                           handle, GFP_ATOMIC);
-
-                       /* Filter with specified handle was concurrently
-                        * inserted after initial check in cls_api. This is not
-                        * necessarily an error if NLM_F_EXCL is not set in
-                        * message flags. Returning EAGAIN will cause cls_api to
-                        * try to update concurrently inserted rule.
-                        */
-                       if (err == -ENOSPC)
-                               err = -EAGAIN;
-               } else {
-                       handle = 1;
-                       err = idr_alloc_u32(&head->handle_idr, fnew, &handle,
-                                           INT_MAX, GFP_ATOMIC);
-               }
-               if (err)
-                       goto errout_hw;
+               idr_replace(&head->handle_idr, fnew, fnew->handle);
 
                refcount_inc(&fnew->refcnt);
-               fnew->handle = handle;
                list_add_tail_rcu(&fnew->list, &fnew->mask->filters);
                spin_unlock(&tp->lock);
        }
                                       fnew->mask->filter_ht_params);
 errout_mask:
        fl_mask_put(head, fnew->mask);
+errout_idr:
+       idr_remove(&head->handle_idr, fnew->handle);
 errout:
        __fl_put(fnew);
 errout_tb: