@@ -90,21 +90,39 @@ static void free_tcf(struct tc_action *p)
90
90
kfree (p );
91
91
}
92
92
93
- static void tcf_idr_remove ( struct tcf_idrinfo * idrinfo , struct tc_action * p )
93
+ static void tcf_action_cleanup ( struct tc_action * p )
94
94
{
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
+
98
98
gen_kill_estimator (& p -> tcfa_rate_est );
99
99
free_tcf (p );
100
100
}
101
101
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
+
102
122
int __tcf_idr_release (struct tc_action * p , bool bind , bool strict )
103
123
{
104
124
int ret = 0 ;
105
125
106
- ASSERT_RTNL ();
107
-
108
126
/* Release with strict==1 and bind==0 is only called through act API
109
127
* interface (classifiers always bind). Only case when action with
110
128
* 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)
118
136
* are acceptable.
119
137
*/
120
138
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 )
124
140
return - EPERM ;
125
141
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 ))
131
143
ret = ACT_P_DELETED ;
132
- }
133
144
}
134
145
135
146
return ret ;
@@ -340,11 +351,7 @@ int tcf_idr_delete_index(struct tc_action_net *tn, u32 index)
340
351
p -> tcfa_index ));
341
352
spin_unlock (& idrinfo -> lock );
342
353
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 );
348
355
module_put (owner );
349
356
return 0 ;
350
357
}
@@ -615,6 +622,11 @@ int tcf_action_destroy(struct list_head *actions, int bind)
615
622
return ret ;
616
623
}
617
624
625
+ static int tcf_action_put (struct tc_action * p )
626
+ {
627
+ return __tcf_action_put (p , false);
628
+ }
629
+
618
630
int
619
631
tcf_action_dump_old (struct sk_buff * skb , struct tc_action * a , int bind , int ref )
620
632
{
@@ -1092,6 +1104,35 @@ static int tca_action_flush(struct net *net, struct nlattr *nla,
1092
1104
return err ;
1093
1105
}
1094
1106
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
+
1095
1136
static int
1096
1137
tcf_del_notify (struct net * net , struct nlmsghdr * n , struct list_head * actions ,
1097
1138
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,
1112
1153
}
1113
1154
1114
1155
/* now do the delete */
1115
- ret = tcf_action_destroy ( actions , 0 );
1156
+ ret = tcf_action_delete ( net , actions , extack );
1116
1157
if (ret < 0 ) {
1117
1158
NL_SET_ERR_MSG (extack , "Failed to delete TC action" );
1118
1159
kfree_skb (skb );
@@ -1164,7 +1205,6 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
1164
1205
if (event == RTM_GETACTION )
1165
1206
ret = tcf_get_notify (net , portid , n , & actions , event , extack );
1166
1207
else { /* delete */
1167
- cleanup_a (& actions , 1 ); /* lookup took reference */
1168
1208
ret = tcf_del_notify (net , n , & actions , portid , attr_size , extack );
1169
1209
if (ret )
1170
1210
goto err ;
0 commit comments