@@ -90,21 +90,39 @@ static void free_tcf(struct tc_action *p)
9090 kfree (p );
9191}
9292
93- static void tcf_idr_remove ( struct tcf_idrinfo * idrinfo , struct tc_action * p )
93+ static void tcf_action_cleanup ( struct tc_action * p )
9494{
95- spin_lock ( & idrinfo -> lock );
96- idr_remove ( & idrinfo -> action_idr , p -> tcfa_index );
97- spin_unlock ( & idrinfo -> lock );
95+ if ( p -> ops -> cleanup )
96+ p -> ops -> cleanup ( p );
97+
9898 gen_kill_estimator (& p -> tcfa_rate_est );
9999 free_tcf (p );
100100}
101101
102+ static int __tcf_action_put (struct tc_action * p , bool bind )
103+ {
104+ struct tcf_idrinfo * idrinfo = p -> idrinfo ;
105+
106+ if (refcount_dec_and_lock (& p -> tcfa_refcnt , & idrinfo -> lock )) {
107+ if (bind )
108+ atomic_dec (& p -> tcfa_bindcnt );
109+ idr_remove (& idrinfo -> action_idr , p -> tcfa_index );
110+ spin_unlock (& idrinfo -> lock );
111+
112+ tcf_action_cleanup (p );
113+ return 1 ;
114+ }
115+
116+ if (bind )
117+ atomic_dec (& p -> tcfa_bindcnt );
118+
119+ return 0 ;
120+ }
121+
102122int __tcf_idr_release (struct tc_action * p , bool bind , bool strict )
103123{
104124 int ret = 0 ;
105125
106- ASSERT_RTNL ();
107-
108126 /* Release with strict==1 and bind==0 is only called through act API
109127 * interface (classifiers always bind). Only case when action with
110128 * positive reference count and zero bind count can exist is when it was
@@ -118,18 +136,11 @@ int __tcf_idr_release(struct tc_action *p, bool bind, bool strict)
118136 * are acceptable.
119137 */
120138 if (p ) {
121- if (bind )
122- atomic_dec (& p -> tcfa_bindcnt );
123- else if (strict && atomic_read (& p -> tcfa_bindcnt ) > 0 )
139+ if (!bind && strict && atomic_read (& p -> tcfa_bindcnt ) > 0 )
124140 return - EPERM ;
125141
126- if (atomic_read (& p -> tcfa_bindcnt ) <= 0 &&
127- refcount_dec_and_test (& p -> tcfa_refcnt )) {
128- if (p -> ops -> cleanup )
129- p -> ops -> cleanup (p );
130- tcf_idr_remove (p -> idrinfo , p );
142+ if (__tcf_action_put (p , bind ))
131143 ret = ACT_P_DELETED ;
132- }
133144 }
134145
135146 return ret ;
@@ -340,11 +351,7 @@ int tcf_idr_delete_index(struct tc_action_net *tn, u32 index)
340351 p -> tcfa_index ));
341352 spin_unlock (& idrinfo -> lock );
342353
343- if (p -> ops -> cleanup )
344- p -> ops -> cleanup (p );
345-
346- gen_kill_estimator (& p -> tcfa_rate_est );
347- free_tcf (p );
354+ tcf_action_cleanup (p );
348355 module_put (owner );
349356 return 0 ;
350357 }
@@ -615,6 +622,11 @@ int tcf_action_destroy(struct list_head *actions, int bind)
615622 return ret ;
616623}
617624
625+ static int tcf_action_put (struct tc_action * p )
626+ {
627+ return __tcf_action_put (p , false);
628+ }
629+
618630int
619631tcf_action_dump_old (struct sk_buff * skb , struct tc_action * a , int bind , int ref )
620632{
@@ -1092,6 +1104,35 @@ static int tca_action_flush(struct net *net, struct nlattr *nla,
10921104 return err ;
10931105}
10941106
1107+ static int tcf_action_delete (struct net * net , struct list_head * actions ,
1108+ struct netlink_ext_ack * extack )
1109+ {
1110+ struct tc_action * a , * tmp ;
1111+ u32 act_index ;
1112+ int ret ;
1113+
1114+ list_for_each_entry_safe (a , tmp , actions , list ) {
1115+ const struct tc_action_ops * ops = a -> ops ;
1116+
1117+ /* Actions can be deleted concurrently so we must save their
1118+ * type and id to search again after reference is released.
1119+ */
1120+ act_index = a -> tcfa_index ;
1121+
1122+ list_del (& a -> list );
1123+ if (tcf_action_put (a )) {
1124+ /* last reference, action was deleted concurrently */
1125+ module_put (ops -> owner );
1126+ } else {
1127+ /* now do the delete */
1128+ ret = ops -> delete (net , act_index );
1129+ if (ret < 0 )
1130+ return ret ;
1131+ }
1132+ }
1133+ return 0 ;
1134+ }
1135+
10951136static int
10961137tcf_del_notify (struct net * net , struct nlmsghdr * n , struct list_head * actions ,
10971138 u32 portid , size_t attr_size , struct netlink_ext_ack * extack )
@@ -1112,7 +1153,7 @@ tcf_del_notify(struct net *net, struct nlmsghdr *n, struct list_head *actions,
11121153 }
11131154
11141155 /* now do the delete */
1115- ret = tcf_action_destroy ( actions , 0 );
1156+ ret = tcf_action_delete ( net , actions , extack );
11161157 if (ret < 0 ) {
11171158 NL_SET_ERR_MSG (extack , "Failed to delete TC action" );
11181159 kfree_skb (skb );
@@ -1164,7 +1205,6 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
11641205 if (event == RTM_GETACTION )
11651206 ret = tcf_get_notify (net , portid , n , & actions , event , extack );
11661207 else { /* delete */
1167- cleanup_a (& actions , 1 ); /* lookup took reference */
11681208 ret = tcf_del_notify (net , n , & actions , portid , attr_size , extack );
11691209 if (ret )
11701210 goto err ;
0 commit comments