aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp_metrics.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/tcp_metrics.c')
-rw-r--r--net/ipv4/tcp_metrics.c239
1 files changed, 160 insertions, 79 deletions
diff --git a/net/ipv4/tcp_metrics.c b/net/ipv4/tcp_metrics.c
index 06493736fbc8..d547075d8300 100644
--- a/net/ipv4/tcp_metrics.c
+++ b/net/ipv4/tcp_metrics.c
@@ -22,6 +22,10 @@
22 22
23int sysctl_tcp_nometrics_save __read_mostly; 23int sysctl_tcp_nometrics_save __read_mostly;
24 24
25static struct tcp_metrics_block *__tcp_get_metrics(const struct inetpeer_addr *saddr,
26 const struct inetpeer_addr *daddr,
27 struct net *net, unsigned int hash);
28
25struct tcp_fastopen_metrics { 29struct tcp_fastopen_metrics {
26 u16 mss; 30 u16 mss;
27 u16 syn_loss:10; /* Recurring Fast Open SYN losses */ 31 u16 syn_loss:10; /* Recurring Fast Open SYN losses */
@@ -31,7 +35,8 @@ struct tcp_fastopen_metrics {
31 35
32struct tcp_metrics_block { 36struct tcp_metrics_block {
33 struct tcp_metrics_block __rcu *tcpm_next; 37 struct tcp_metrics_block __rcu *tcpm_next;
34 struct inetpeer_addr tcpm_addr; 38 struct inetpeer_addr tcpm_saddr;
39 struct inetpeer_addr tcpm_daddr;
35 unsigned long tcpm_stamp; 40 unsigned long tcpm_stamp;
36 u32 tcpm_ts; 41 u32 tcpm_ts;
37 u32 tcpm_ts_stamp; 42 u32 tcpm_ts_stamp;
@@ -130,16 +135,42 @@ static void tcpm_suck_dst(struct tcp_metrics_block *tm, struct dst_entry *dst,
130 } 135 }
131} 136}
132 137
138#define TCP_METRICS_TIMEOUT (60 * 60 * HZ)
139
140static void tcpm_check_stamp(struct tcp_metrics_block *tm, struct dst_entry *dst)
141{
142 if (tm && unlikely(time_after(jiffies, tm->tcpm_stamp + TCP_METRICS_TIMEOUT)))
143 tcpm_suck_dst(tm, dst, false);
144}
145
146#define TCP_METRICS_RECLAIM_DEPTH 5
147#define TCP_METRICS_RECLAIM_PTR (struct tcp_metrics_block *) 0x1UL
148
133static struct tcp_metrics_block *tcpm_new(struct dst_entry *dst, 149static struct tcp_metrics_block *tcpm_new(struct dst_entry *dst,
134 struct inetpeer_addr *addr, 150 struct inetpeer_addr *saddr,
135 unsigned int hash, 151 struct inetpeer_addr *daddr,
136 bool reclaim) 152 unsigned int hash)
137{ 153{
138 struct tcp_metrics_block *tm; 154 struct tcp_metrics_block *tm;
139 struct net *net; 155 struct net *net;
156 bool reclaim = false;
140 157
141 spin_lock_bh(&tcp_metrics_lock); 158 spin_lock_bh(&tcp_metrics_lock);
142 net = dev_net(dst->dev); 159 net = dev_net(dst->dev);
160
161 /* While waiting for the spin-lock the cache might have been populated
162 * with this entry and so we have to check again.
163 */
164 tm = __tcp_get_metrics(saddr, daddr, net, hash);
165 if (tm == TCP_METRICS_RECLAIM_PTR) {
166 reclaim = true;
167 tm = NULL;
168 }
169 if (tm) {
170 tcpm_check_stamp(tm, dst);
171 goto out_unlock;
172 }
173
143 if (unlikely(reclaim)) { 174 if (unlikely(reclaim)) {
144 struct tcp_metrics_block *oldest; 175 struct tcp_metrics_block *oldest;
145 176
@@ -155,7 +186,8 @@ static struct tcp_metrics_block *tcpm_new(struct dst_entry *dst,
155 if (!tm) 186 if (!tm)
156 goto out_unlock; 187 goto out_unlock;
157 } 188 }
158 tm->tcpm_addr = *addr; 189 tm->tcpm_saddr = *saddr;
190 tm->tcpm_daddr = *daddr;
159 191
160 tcpm_suck_dst(tm, dst, true); 192 tcpm_suck_dst(tm, dst, true);
161 193
@@ -169,17 +201,6 @@ out_unlock:
169 return tm; 201 return tm;
170} 202}
171 203
172#define TCP_METRICS_TIMEOUT (60 * 60 * HZ)
173
174static void tcpm_check_stamp(struct tcp_metrics_block *tm, struct dst_entry *dst)
175{
176 if (tm && unlikely(time_after(jiffies, tm->tcpm_stamp + TCP_METRICS_TIMEOUT)))
177 tcpm_suck_dst(tm, dst, false);
178}
179
180#define TCP_METRICS_RECLAIM_DEPTH 5
181#define TCP_METRICS_RECLAIM_PTR (struct tcp_metrics_block *) 0x1UL
182
183static struct tcp_metrics_block *tcp_get_encode(struct tcp_metrics_block *tm, int depth) 204static struct tcp_metrics_block *tcp_get_encode(struct tcp_metrics_block *tm, int depth)
184{ 205{
185 if (tm) 206 if (tm)
@@ -189,7 +210,8 @@ static struct tcp_metrics_block *tcp_get_encode(struct tcp_metrics_block *tm, in
189 return NULL; 210 return NULL;
190} 211}
191 212
192static struct tcp_metrics_block *__tcp_get_metrics(const struct inetpeer_addr *addr, 213static struct tcp_metrics_block *__tcp_get_metrics(const struct inetpeer_addr *saddr,
214 const struct inetpeer_addr *daddr,
193 struct net *net, unsigned int hash) 215 struct net *net, unsigned int hash)
194{ 216{
195 struct tcp_metrics_block *tm; 217 struct tcp_metrics_block *tm;
@@ -197,7 +219,8 @@ static struct tcp_metrics_block *__tcp_get_metrics(const struct inetpeer_addr *a
197 219
198 for (tm = rcu_dereference(net->ipv4.tcp_metrics_hash[hash].chain); tm; 220 for (tm = rcu_dereference(net->ipv4.tcp_metrics_hash[hash].chain); tm;
199 tm = rcu_dereference(tm->tcpm_next)) { 221 tm = rcu_dereference(tm->tcpm_next)) {
200 if (addr_same(&tm->tcpm_addr, addr)) 222 if (addr_same(&tm->tcpm_saddr, saddr) &&
223 addr_same(&tm->tcpm_daddr, daddr))
201 break; 224 break;
202 depth++; 225 depth++;
203 } 226 }
@@ -208,19 +231,22 @@ static struct tcp_metrics_block *__tcp_get_metrics_req(struct request_sock *req,
208 struct dst_entry *dst) 231 struct dst_entry *dst)
209{ 232{
210 struct tcp_metrics_block *tm; 233 struct tcp_metrics_block *tm;
211 struct inetpeer_addr addr; 234 struct inetpeer_addr saddr, daddr;
212 unsigned int hash; 235 unsigned int hash;
213 struct net *net; 236 struct net *net;
214 237
215 addr.family = req->rsk_ops->family; 238 saddr.family = req->rsk_ops->family;
216 switch (addr.family) { 239 daddr.family = req->rsk_ops->family;
240 switch (daddr.family) {
217 case AF_INET: 241 case AF_INET:
218 addr.addr.a4 = inet_rsk(req)->ir_rmt_addr; 242 saddr.addr.a4 = inet_rsk(req)->ir_loc_addr;
219 hash = (__force unsigned int) addr.addr.a4; 243 daddr.addr.a4 = inet_rsk(req)->ir_rmt_addr;
244 hash = (__force unsigned int) daddr.addr.a4;
220 break; 245 break;
221#if IS_ENABLED(CONFIG_IPV6) 246#if IS_ENABLED(CONFIG_IPV6)
222 case AF_INET6: 247 case AF_INET6:
223 *(struct in6_addr *)addr.addr.a6 = inet_rsk(req)->ir_v6_rmt_addr; 248 *(struct in6_addr *)saddr.addr.a6 = inet_rsk(req)->ir_v6_loc_addr;
249 *(struct in6_addr *)daddr.addr.a6 = inet_rsk(req)->ir_v6_rmt_addr;
224 hash = ipv6_addr_hash(&inet_rsk(req)->ir_v6_rmt_addr); 250 hash = ipv6_addr_hash(&inet_rsk(req)->ir_v6_rmt_addr);
225 break; 251 break;
226#endif 252#endif
@@ -233,7 +259,8 @@ static struct tcp_metrics_block *__tcp_get_metrics_req(struct request_sock *req,
233 259
234 for (tm = rcu_dereference(net->ipv4.tcp_metrics_hash[hash].chain); tm; 260 for (tm = rcu_dereference(net->ipv4.tcp_metrics_hash[hash].chain); tm;
235 tm = rcu_dereference(tm->tcpm_next)) { 261 tm = rcu_dereference(tm->tcpm_next)) {
236 if (addr_same(&tm->tcpm_addr, &addr)) 262 if (addr_same(&tm->tcpm_saddr, &saddr) &&
263 addr_same(&tm->tcpm_daddr, &daddr))
237 break; 264 break;
238 } 265 }
239 tcpm_check_stamp(tm, dst); 266 tcpm_check_stamp(tm, dst);
@@ -243,32 +270,44 @@ static struct tcp_metrics_block *__tcp_get_metrics_req(struct request_sock *req,
243static struct tcp_metrics_block *__tcp_get_metrics_tw(struct inet_timewait_sock *tw) 270static struct tcp_metrics_block *__tcp_get_metrics_tw(struct inet_timewait_sock *tw)
244{ 271{
245 struct tcp_metrics_block *tm; 272 struct tcp_metrics_block *tm;
246 struct inetpeer_addr addr; 273 struct inetpeer_addr saddr, daddr;
247 unsigned int hash; 274 unsigned int hash;
248 struct net *net; 275 struct net *net;
249 276
250 addr.family = tw->tw_family; 277 if (tw->tw_family == AF_INET) {
251 switch (addr.family) { 278 saddr.family = AF_INET;
252 case AF_INET: 279 saddr.addr.a4 = tw->tw_rcv_saddr;
253 addr.addr.a4 = tw->tw_daddr; 280 daddr.family = AF_INET;
254 hash = (__force unsigned int) addr.addr.a4; 281 daddr.addr.a4 = tw->tw_daddr;
255 break; 282 hash = (__force unsigned int) daddr.addr.a4;
283 }
256#if IS_ENABLED(CONFIG_IPV6) 284#if IS_ENABLED(CONFIG_IPV6)
257 case AF_INET6: 285 else if (tw->tw_family == AF_INET6) {
258 *(struct in6_addr *)addr.addr.a6 = tw->tw_v6_daddr; 286 if (ipv6_addr_v4mapped(&tw->tw_v6_daddr)) {
259 hash = ipv6_addr_hash(&tw->tw_v6_daddr); 287 saddr.family = AF_INET;
260 break; 288 saddr.addr.a4 = tw->tw_rcv_saddr;
289 daddr.family = AF_INET;
290 daddr.addr.a4 = tw->tw_daddr;
291 hash = (__force unsigned int) daddr.addr.a4;
292 } else {
293 saddr.family = AF_INET6;
294 *(struct in6_addr *)saddr.addr.a6 = tw->tw_v6_rcv_saddr;
295 daddr.family = AF_INET6;
296 *(struct in6_addr *)daddr.addr.a6 = tw->tw_v6_daddr;
297 hash = ipv6_addr_hash(&tw->tw_v6_daddr);
298 }
299 }
261#endif 300#endif
262 default: 301 else
263 return NULL; 302 return NULL;
264 }
265 303
266 net = twsk_net(tw); 304 net = twsk_net(tw);
267 hash = hash_32(hash, net->ipv4.tcp_metrics_hash_log); 305 hash = hash_32(hash, net->ipv4.tcp_metrics_hash_log);
268 306
269 for (tm = rcu_dereference(net->ipv4.tcp_metrics_hash[hash].chain); tm; 307 for (tm = rcu_dereference(net->ipv4.tcp_metrics_hash[hash].chain); tm;
270 tm = rcu_dereference(tm->tcpm_next)) { 308 tm = rcu_dereference(tm->tcpm_next)) {
271 if (addr_same(&tm->tcpm_addr, &addr)) 309 if (addr_same(&tm->tcpm_saddr, &saddr) &&
310 addr_same(&tm->tcpm_daddr, &daddr))
272 break; 311 break;
273 } 312 }
274 return tm; 313 return tm;
@@ -279,38 +318,45 @@ static struct tcp_metrics_block *tcp_get_metrics(struct sock *sk,
279 bool create) 318 bool create)
280{ 319{
281 struct tcp_metrics_block *tm; 320 struct tcp_metrics_block *tm;
282 struct inetpeer_addr addr; 321 struct inetpeer_addr saddr, daddr;
283 unsigned int hash; 322 unsigned int hash;
284 struct net *net; 323 struct net *net;
285 bool reclaim;
286 324
287 addr.family = sk->sk_family; 325 if (sk->sk_family == AF_INET) {
288 switch (addr.family) { 326 saddr.family = AF_INET;
289 case AF_INET: 327 saddr.addr.a4 = inet_sk(sk)->inet_saddr;
290 addr.addr.a4 = inet_sk(sk)->inet_daddr; 328 daddr.family = AF_INET;
291 hash = (__force unsigned int) addr.addr.a4; 329 daddr.addr.a4 = inet_sk(sk)->inet_daddr;
292 break; 330 hash = (__force unsigned int) daddr.addr.a4;
331 }
293#if IS_ENABLED(CONFIG_IPV6) 332#if IS_ENABLED(CONFIG_IPV6)
294 case AF_INET6: 333 else if (sk->sk_family == AF_INET6) {
295 *(struct in6_addr *)addr.addr.a6 = sk->sk_v6_daddr; 334 if (ipv6_addr_v4mapped(&sk->sk_v6_daddr)) {
296 hash = ipv6_addr_hash(&sk->sk_v6_daddr); 335 saddr.family = AF_INET;
297 break; 336 saddr.addr.a4 = inet_sk(sk)->inet_saddr;
337 daddr.family = AF_INET;
338 daddr.addr.a4 = inet_sk(sk)->inet_daddr;
339 hash = (__force unsigned int) daddr.addr.a4;
340 } else {
341 saddr.family = AF_INET6;
342 *(struct in6_addr *)saddr.addr.a6 = sk->sk_v6_rcv_saddr;
343 daddr.family = AF_INET6;
344 *(struct in6_addr *)daddr.addr.a6 = sk->sk_v6_daddr;
345 hash = ipv6_addr_hash(&sk->sk_v6_daddr);
346 }
347 }
298#endif 348#endif
299 default: 349 else
300 return NULL; 350 return NULL;
301 }
302 351
303 net = dev_net(dst->dev); 352 net = dev_net(dst->dev);
304 hash = hash_32(hash, net->ipv4.tcp_metrics_hash_log); 353 hash = hash_32(hash, net->ipv4.tcp_metrics_hash_log);
305 354
306 tm = __tcp_get_metrics(&addr, net, hash); 355 tm = __tcp_get_metrics(&saddr, &daddr, net, hash);
307 reclaim = false; 356 if (tm == TCP_METRICS_RECLAIM_PTR)
308 if (tm == TCP_METRICS_RECLAIM_PTR) {
309 reclaim = true;
310 tm = NULL; 357 tm = NULL;
311 }
312 if (!tm && create) 358 if (!tm && create)
313 tm = tcpm_new(dst, &addr, hash, reclaim); 359 tm = tcpm_new(dst, &saddr, &daddr, hash);
314 else 360 else
315 tcpm_check_stamp(tm, dst); 361 tcpm_check_stamp(tm, dst);
316 362
@@ -724,15 +770,21 @@ static int tcp_metrics_fill_info(struct sk_buff *msg,
724 struct nlattr *nest; 770 struct nlattr *nest;
725 int i; 771 int i;
726 772
727 switch (tm->tcpm_addr.family) { 773 switch (tm->tcpm_daddr.family) {
728 case AF_INET: 774 case AF_INET:
729 if (nla_put_be32(msg, TCP_METRICS_ATTR_ADDR_IPV4, 775 if (nla_put_be32(msg, TCP_METRICS_ATTR_ADDR_IPV4,
730 tm->tcpm_addr.addr.a4) < 0) 776 tm->tcpm_daddr.addr.a4) < 0)
777 goto nla_put_failure;
778 if (nla_put_be32(msg, TCP_METRICS_ATTR_SADDR_IPV4,
779 tm->tcpm_saddr.addr.a4) < 0)
731 goto nla_put_failure; 780 goto nla_put_failure;
732 break; 781 break;
733 case AF_INET6: 782 case AF_INET6:
734 if (nla_put(msg, TCP_METRICS_ATTR_ADDR_IPV6, 16, 783 if (nla_put(msg, TCP_METRICS_ATTR_ADDR_IPV6, 16,
735 tm->tcpm_addr.addr.a6) < 0) 784 tm->tcpm_daddr.addr.a6) < 0)
785 goto nla_put_failure;
786 if (nla_put(msg, TCP_METRICS_ATTR_SADDR_IPV6, 16,
787 tm->tcpm_saddr.addr.a6) < 0)
736 goto nla_put_failure; 788 goto nla_put_failure;
737 break; 789 break;
738 default: 790 default:
@@ -855,44 +907,66 @@ done:
855 return skb->len; 907 return skb->len;
856} 908}
857 909
858static int parse_nl_addr(struct genl_info *info, struct inetpeer_addr *addr, 910static int __parse_nl_addr(struct genl_info *info, struct inetpeer_addr *addr,
859 unsigned int *hash, int optional) 911 unsigned int *hash, int optional, int v4, int v6)
860{ 912{
861 struct nlattr *a; 913 struct nlattr *a;
862 914
863 a = info->attrs[TCP_METRICS_ATTR_ADDR_IPV4]; 915 a = info->attrs[v4];
864 if (a) { 916 if (a) {
865 addr->family = AF_INET; 917 addr->family = AF_INET;
866 addr->addr.a4 = nla_get_be32(a); 918 addr->addr.a4 = nla_get_be32(a);
867 *hash = (__force unsigned int) addr->addr.a4; 919 if (hash)
920 *hash = (__force unsigned int) addr->addr.a4;
868 return 0; 921 return 0;
869 } 922 }
870 a = info->attrs[TCP_METRICS_ATTR_ADDR_IPV6]; 923 a = info->attrs[v6];
871 if (a) { 924 if (a) {
872 if (nla_len(a) != sizeof(struct in6_addr)) 925 if (nla_len(a) != sizeof(struct in6_addr))
873 return -EINVAL; 926 return -EINVAL;
874 addr->family = AF_INET6; 927 addr->family = AF_INET6;
875 memcpy(addr->addr.a6, nla_data(a), sizeof(addr->addr.a6)); 928 memcpy(addr->addr.a6, nla_data(a), sizeof(addr->addr.a6));
876 *hash = ipv6_addr_hash((struct in6_addr *) addr->addr.a6); 929 if (hash)
930 *hash = ipv6_addr_hash((struct in6_addr *) addr->addr.a6);
877 return 0; 931 return 0;
878 } 932 }
879 return optional ? 1 : -EAFNOSUPPORT; 933 return optional ? 1 : -EAFNOSUPPORT;
880} 934}
881 935
936static int parse_nl_addr(struct genl_info *info, struct inetpeer_addr *addr,
937 unsigned int *hash, int optional)
938{
939 return __parse_nl_addr(info, addr, hash, optional,
940 TCP_METRICS_ATTR_ADDR_IPV4,
941 TCP_METRICS_ATTR_ADDR_IPV6);
942}
943
944static int parse_nl_saddr(struct genl_info *info, struct inetpeer_addr *addr)
945{
946 return __parse_nl_addr(info, addr, NULL, 0,
947 TCP_METRICS_ATTR_SADDR_IPV4,
948 TCP_METRICS_ATTR_SADDR_IPV6);
949}
950
882static int tcp_metrics_nl_cmd_get(struct sk_buff *skb, struct genl_info *info) 951static int tcp_metrics_nl_cmd_get(struct sk_buff *skb, struct genl_info *info)
883{ 952{
884 struct tcp_metrics_block *tm; 953 struct tcp_metrics_block *tm;
885 struct inetpeer_addr addr; 954 struct inetpeer_addr saddr, daddr;
886 unsigned int hash; 955 unsigned int hash;
887 struct sk_buff *msg; 956 struct sk_buff *msg;
888 struct net *net = genl_info_net(info); 957 struct net *net = genl_info_net(info);
889 void *reply; 958 void *reply;
890 int ret; 959 int ret;
960 bool src = true;
891 961
892 ret = parse_nl_addr(info, &addr, &hash, 0); 962 ret = parse_nl_addr(info, &daddr, &hash, 0);
893 if (ret < 0) 963 if (ret < 0)
894 return ret; 964 return ret;
895 965
966 ret = parse_nl_saddr(info, &saddr);
967 if (ret < 0)
968 src = false;
969
896 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 970 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
897 if (!msg) 971 if (!msg)
898 return -ENOMEM; 972 return -ENOMEM;
@@ -907,7 +981,8 @@ static int tcp_metrics_nl_cmd_get(struct sk_buff *skb, struct genl_info *info)
907 rcu_read_lock(); 981 rcu_read_lock();
908 for (tm = rcu_dereference(net->ipv4.tcp_metrics_hash[hash].chain); tm; 982 for (tm = rcu_dereference(net->ipv4.tcp_metrics_hash[hash].chain); tm;
909 tm = rcu_dereference(tm->tcpm_next)) { 983 tm = rcu_dereference(tm->tcpm_next)) {
910 if (addr_same(&tm->tcpm_addr, &addr)) { 984 if (addr_same(&tm->tcpm_daddr, &daddr) &&
985 (!src || addr_same(&tm->tcpm_saddr, &saddr))) {
911 ret = tcp_metrics_fill_info(msg, tm); 986 ret = tcp_metrics_fill_info(msg, tm);
912 break; 987 break;
913 } 988 }
@@ -962,32 +1037,38 @@ static int tcp_metrics_nl_cmd_del(struct sk_buff *skb, struct genl_info *info)
962 struct tcpm_hash_bucket *hb; 1037 struct tcpm_hash_bucket *hb;
963 struct tcp_metrics_block *tm; 1038 struct tcp_metrics_block *tm;
964 struct tcp_metrics_block __rcu **pp; 1039 struct tcp_metrics_block __rcu **pp;
965 struct inetpeer_addr addr; 1040 struct inetpeer_addr saddr, daddr;
966 unsigned int hash; 1041 unsigned int hash;
967 struct net *net = genl_info_net(info); 1042 struct net *net = genl_info_net(info);
968 int ret; 1043 int ret;
1044 bool src = true, found = false;
969 1045
970 ret = parse_nl_addr(info, &addr, &hash, 1); 1046 ret = parse_nl_addr(info, &daddr, &hash, 1);
971 if (ret < 0) 1047 if (ret < 0)
972 return ret; 1048 return ret;
973 if (ret > 0) 1049 if (ret > 0)
974 return tcp_metrics_flush_all(net); 1050 return tcp_metrics_flush_all(net);
1051 ret = parse_nl_saddr(info, &saddr);
1052 if (ret < 0)
1053 src = false;
975 1054
976 hash = hash_32(hash, net->ipv4.tcp_metrics_hash_log); 1055 hash = hash_32(hash, net->ipv4.tcp_metrics_hash_log);
977 hb = net->ipv4.tcp_metrics_hash + hash; 1056 hb = net->ipv4.tcp_metrics_hash + hash;
978 pp = &hb->chain; 1057 pp = &hb->chain;
979 spin_lock_bh(&tcp_metrics_lock); 1058 spin_lock_bh(&tcp_metrics_lock);
980 for (tm = deref_locked_genl(*pp); tm; 1059 for (tm = deref_locked_genl(*pp); tm; tm = deref_locked_genl(*pp)) {
981 pp = &tm->tcpm_next, tm = deref_locked_genl(*pp)) { 1060 if (addr_same(&tm->tcpm_daddr, &daddr) &&
982 if (addr_same(&tm->tcpm_addr, &addr)) { 1061 (!src || addr_same(&tm->tcpm_saddr, &saddr))) {
983 *pp = tm->tcpm_next; 1062 *pp = tm->tcpm_next;
984 break; 1063 kfree_rcu(tm, rcu_head);
1064 found = true;
1065 } else {
1066 pp = &tm->tcpm_next;
985 } 1067 }
986 } 1068 }
987 spin_unlock_bh(&tcp_metrics_lock); 1069 spin_unlock_bh(&tcp_metrics_lock);
988 if (!tm) 1070 if (!found)
989 return -ESRCH; 1071 return -ESRCH;
990 kfree_rcu(tm, rcu_head);
991 return 0; 1072 return 0;
992} 1073}
993 1074