| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* Local endpoint object management |
|---|
| 2 | 3 | * |
|---|
| 3 | 4 | * Copyright (C) 2016 Red Hat, Inc. All Rights Reserved. |
|---|
| 4 | 5 | * Written by David Howells (dhowells@redhat.com) |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or |
|---|
| 7 | | - * modify it under the terms of the GNU General Public Licence |
|---|
| 8 | | - * as published by the Free Software Foundation; either version |
|---|
| 9 | | - * 2 of the Licence, or (at your option) any later version. |
|---|
| 10 | 6 | */ |
|---|
| 11 | 7 | |
|---|
| 12 | 8 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
|---|
| .. | .. |
|---|
| 82 | 78 | |
|---|
| 83 | 79 | local = kzalloc(sizeof(struct rxrpc_local), GFP_KERNEL); |
|---|
| 84 | 80 | if (local) { |
|---|
| 85 | | - atomic_set(&local->usage, 1); |
|---|
| 81 | + refcount_set(&local->ref, 1); |
|---|
| 86 | 82 | atomic_set(&local->active_users, 1); |
|---|
| 87 | 83 | local->rxnet = rxnet; |
|---|
| 88 | | - INIT_LIST_HEAD(&local->link); |
|---|
| 84 | + INIT_HLIST_NODE(&local->link); |
|---|
| 89 | 85 | INIT_WORK(&local->processor, rxrpc_local_processor); |
|---|
| 90 | 86 | init_rwsem(&local->defrag_sem); |
|---|
| 91 | 87 | skb_queue_head_init(&local->reject_queue); |
|---|
| 92 | 88 | skb_queue_head_init(&local->event_queue); |
|---|
| 93 | | - local->client_conns = RB_ROOT; |
|---|
| 94 | | - spin_lock_init(&local->client_conns_lock); |
|---|
| 89 | + local->client_bundles = RB_ROOT; |
|---|
| 90 | + spin_lock_init(&local->client_bundles_lock); |
|---|
| 95 | 91 | spin_lock_init(&local->lock); |
|---|
| 96 | 92 | rwlock_init(&local->services_lock); |
|---|
| 97 | 93 | local->debug_id = atomic_inc_return(&rxrpc_debug_id); |
|---|
| .. | .. |
|---|
| 111 | 107 | static int rxrpc_open_socket(struct rxrpc_local *local, struct net *net) |
|---|
| 112 | 108 | { |
|---|
| 113 | 109 | struct sock *usk; |
|---|
| 114 | | - int ret, opt; |
|---|
| 110 | + int ret; |
|---|
| 115 | 111 | |
|---|
| 116 | 112 | _enter("%p{%d,%d}", |
|---|
| 117 | 113 | local, local->srx.transport_type, local->srx.transport.family); |
|---|
| .. | .. |
|---|
| 161 | 157 | switch (local->srx.transport.family) { |
|---|
| 162 | 158 | case AF_INET6: |
|---|
| 163 | 159 | /* we want to receive ICMPv6 errors */ |
|---|
| 164 | | - opt = 1; |
|---|
| 165 | | - ret = kernel_setsockopt(local->socket, SOL_IPV6, IPV6_RECVERR, |
|---|
| 166 | | - (char *) &opt, sizeof(opt)); |
|---|
| 167 | | - if (ret < 0) { |
|---|
| 168 | | - _debug("setsockopt failed"); |
|---|
| 169 | | - goto error; |
|---|
| 170 | | - } |
|---|
| 160 | + ip6_sock_set_recverr(local->socket->sk); |
|---|
| 171 | 161 | |
|---|
| 172 | 162 | /* Fall through and set IPv4 options too otherwise we don't get |
|---|
| 173 | 163 | * errors from IPv4 packets sent through the IPv6 socket. |
|---|
| 174 | 164 | */ |
|---|
| 175 | | - |
|---|
| 165 | + fallthrough; |
|---|
| 176 | 166 | case AF_INET: |
|---|
| 177 | 167 | /* we want to receive ICMP errors */ |
|---|
| 178 | | - opt = 1; |
|---|
| 179 | | - ret = kernel_setsockopt(local->socket, SOL_IP, IP_RECVERR, |
|---|
| 180 | | - (char *) &opt, sizeof(opt)); |
|---|
| 181 | | - if (ret < 0) { |
|---|
| 182 | | - _debug("setsockopt failed"); |
|---|
| 183 | | - goto error; |
|---|
| 184 | | - } |
|---|
| 168 | + ip_sock_set_recverr(local->socket->sk); |
|---|
| 185 | 169 | |
|---|
| 186 | 170 | /* we want to set the don't fragment bit */ |
|---|
| 187 | | - opt = IP_PMTUDISC_DO; |
|---|
| 188 | | - ret = kernel_setsockopt(local->socket, SOL_IP, IP_MTU_DISCOVER, |
|---|
| 189 | | - (char *) &opt, sizeof(opt)); |
|---|
| 190 | | - if (ret < 0) { |
|---|
| 191 | | - _debug("setsockopt failed"); |
|---|
| 192 | | - goto error; |
|---|
| 193 | | - } |
|---|
| 171 | + ip_sock_set_mtu_discover(local->socket->sk, IP_PMTUDISC_DO); |
|---|
| 194 | 172 | |
|---|
| 195 | 173 | /* We want receive timestamps. */ |
|---|
| 196 | | - opt = 1; |
|---|
| 197 | | - ret = kernel_setsockopt(local->socket, SOL_SOCKET, SO_TIMESTAMPNS, |
|---|
| 198 | | - (char *)&opt, sizeof(opt)); |
|---|
| 199 | | - if (ret < 0) { |
|---|
| 200 | | - _debug("setsockopt failed"); |
|---|
| 201 | | - goto error; |
|---|
| 202 | | - } |
|---|
| 174 | + sock_enable_timestamps(local->socket->sk); |
|---|
| 203 | 175 | break; |
|---|
| 204 | 176 | |
|---|
| 205 | 177 | default: |
|---|
| .. | .. |
|---|
| 227 | 199 | { |
|---|
| 228 | 200 | struct rxrpc_local *local; |
|---|
| 229 | 201 | struct rxrpc_net *rxnet = rxrpc_net(net); |
|---|
| 230 | | - struct list_head *cursor; |
|---|
| 202 | + struct hlist_node *cursor; |
|---|
| 231 | 203 | const char *age; |
|---|
| 232 | 204 | long diff; |
|---|
| 233 | 205 | int ret; |
|---|
| .. | .. |
|---|
| 237 | 209 | |
|---|
| 238 | 210 | mutex_lock(&rxnet->local_mutex); |
|---|
| 239 | 211 | |
|---|
| 240 | | - for (cursor = rxnet->local_endpoints.next; |
|---|
| 241 | | - cursor != &rxnet->local_endpoints; |
|---|
| 242 | | - cursor = cursor->next) { |
|---|
| 243 | | - local = list_entry(cursor, struct rxrpc_local, link); |
|---|
| 212 | + hlist_for_each(cursor, &rxnet->local_endpoints) { |
|---|
| 213 | + local = hlist_entry(cursor, struct rxrpc_local, link); |
|---|
| 244 | 214 | |
|---|
| 245 | 215 | diff = rxrpc_local_cmp_key(local, srx); |
|---|
| 246 | | - if (diff < 0) |
|---|
| 216 | + if (diff != 0) |
|---|
| 247 | 217 | continue; |
|---|
| 248 | | - if (diff > 0) |
|---|
| 249 | | - break; |
|---|
| 250 | 218 | |
|---|
| 251 | 219 | /* Services aren't allowed to share transport sockets, so |
|---|
| 252 | 220 | * reject that here. It is possible that the object is dying - |
|---|
| .. | .. |
|---|
| 258 | 226 | goto addr_in_use; |
|---|
| 259 | 227 | } |
|---|
| 260 | 228 | |
|---|
| 261 | | - /* Found a match. We replace a dying object. Attempting to |
|---|
| 262 | | - * bind the transport socket may still fail if we're attempting |
|---|
| 263 | | - * to use a local address that the dying object is still using. |
|---|
| 229 | + /* Found a match. We want to replace a dying object. |
|---|
| 230 | + * Attempting to bind the transport socket may still fail if |
|---|
| 231 | + * we're attempting to use a local address that the dying |
|---|
| 232 | + * object is still using. |
|---|
| 264 | 233 | */ |
|---|
| 265 | 234 | if (!rxrpc_use_local(local)) |
|---|
| 266 | 235 | break; |
|---|
| .. | .. |
|---|
| 277 | 246 | if (ret < 0) |
|---|
| 278 | 247 | goto sock_error; |
|---|
| 279 | 248 | |
|---|
| 280 | | - if (cursor != &rxnet->local_endpoints) |
|---|
| 281 | | - list_replace_init(cursor, &local->link); |
|---|
| 282 | | - else |
|---|
| 283 | | - list_add_tail(&local->link, cursor); |
|---|
| 249 | + if (cursor) { |
|---|
| 250 | + hlist_replace_rcu(cursor, &local->link); |
|---|
| 251 | + cursor->pprev = NULL; |
|---|
| 252 | + } else { |
|---|
| 253 | + hlist_add_head_rcu(&local->link, &rxnet->local_endpoints); |
|---|
| 254 | + } |
|---|
| 284 | 255 | age = "new"; |
|---|
| 285 | 256 | |
|---|
| 286 | 257 | found: |
|---|
| .. | .. |
|---|
| 313 | 284 | struct rxrpc_local *rxrpc_get_local(struct rxrpc_local *local) |
|---|
| 314 | 285 | { |
|---|
| 315 | 286 | const void *here = __builtin_return_address(0); |
|---|
| 316 | | - int n; |
|---|
| 287 | + int r; |
|---|
| 317 | 288 | |
|---|
| 318 | | - n = atomic_inc_return(&local->usage); |
|---|
| 319 | | - trace_rxrpc_local(local->debug_id, rxrpc_local_got, n, here); |
|---|
| 289 | + __refcount_inc(&local->ref, &r); |
|---|
| 290 | + trace_rxrpc_local(local->debug_id, rxrpc_local_got, r + 1, here); |
|---|
| 320 | 291 | return local; |
|---|
| 321 | 292 | } |
|---|
| 322 | 293 | |
|---|
| .. | .. |
|---|
| 326 | 297 | struct rxrpc_local *rxrpc_get_local_maybe(struct rxrpc_local *local) |
|---|
| 327 | 298 | { |
|---|
| 328 | 299 | const void *here = __builtin_return_address(0); |
|---|
| 300 | + int r; |
|---|
| 329 | 301 | |
|---|
| 330 | 302 | if (local) { |
|---|
| 331 | | - int n = atomic_fetch_add_unless(&local->usage, 1, 0); |
|---|
| 332 | | - if (n > 0) |
|---|
| 303 | + if (__refcount_inc_not_zero(&local->ref, &r)) |
|---|
| 333 | 304 | trace_rxrpc_local(local->debug_id, rxrpc_local_got, |
|---|
| 334 | | - n + 1, here); |
|---|
| 305 | + r + 1, here); |
|---|
| 335 | 306 | else |
|---|
| 336 | 307 | local = NULL; |
|---|
| 337 | 308 | } |
|---|
| .. | .. |
|---|
| 345 | 316 | { |
|---|
| 346 | 317 | const void *here = __builtin_return_address(0); |
|---|
| 347 | 318 | unsigned int debug_id = local->debug_id; |
|---|
| 348 | | - int n = atomic_read(&local->usage); |
|---|
| 319 | + int r = refcount_read(&local->ref); |
|---|
| 349 | 320 | |
|---|
| 350 | 321 | if (rxrpc_queue_work(&local->processor)) |
|---|
| 351 | | - trace_rxrpc_local(debug_id, rxrpc_local_queued, n, here); |
|---|
| 322 | + trace_rxrpc_local(debug_id, rxrpc_local_queued, r + 1, here); |
|---|
| 352 | 323 | else |
|---|
| 353 | 324 | rxrpc_put_local(local); |
|---|
| 354 | 325 | } |
|---|
| .. | .. |
|---|
| 360 | 331 | { |
|---|
| 361 | 332 | const void *here = __builtin_return_address(0); |
|---|
| 362 | 333 | unsigned int debug_id; |
|---|
| 363 | | - int n; |
|---|
| 334 | + bool dead; |
|---|
| 335 | + int r; |
|---|
| 364 | 336 | |
|---|
| 365 | 337 | if (local) { |
|---|
| 366 | 338 | debug_id = local->debug_id; |
|---|
| 367 | 339 | |
|---|
| 368 | | - n = atomic_dec_return(&local->usage); |
|---|
| 369 | | - trace_rxrpc_local(debug_id, rxrpc_local_put, n, here); |
|---|
| 340 | + dead = __refcount_dec_and_test(&local->ref, &r); |
|---|
| 341 | + trace_rxrpc_local(debug_id, rxrpc_local_put, r, here); |
|---|
| 370 | 342 | |
|---|
| 371 | | - if (n == 0) |
|---|
| 343 | + if (dead) |
|---|
| 372 | 344 | call_rcu(&local->rcu, rxrpc_local_rcu); |
|---|
| 373 | 345 | } |
|---|
| 374 | 346 | } |
|---|
| .. | .. |
|---|
| 421 | 393 | local->dead = true; |
|---|
| 422 | 394 | |
|---|
| 423 | 395 | mutex_lock(&rxnet->local_mutex); |
|---|
| 424 | | - list_del_init(&local->link); |
|---|
| 396 | + hlist_del_init_rcu(&local->link); |
|---|
| 425 | 397 | mutex_unlock(&rxnet->local_mutex); |
|---|
| 426 | 398 | |
|---|
| 427 | 399 | rxrpc_clean_up_local_conns(local); |
|---|
| .. | .. |
|---|
| 452 | 424 | container_of(work, struct rxrpc_local, processor); |
|---|
| 453 | 425 | bool again; |
|---|
| 454 | 426 | |
|---|
| 427 | + if (local->dead) |
|---|
| 428 | + return; |
|---|
| 429 | + |
|---|
| 455 | 430 | trace_rxrpc_local(local->debug_id, rxrpc_local_processing, |
|---|
| 456 | | - atomic_read(&local->usage), NULL); |
|---|
| 431 | + refcount_read(&local->ref), NULL); |
|---|
| 457 | 432 | |
|---|
| 458 | 433 | do { |
|---|
| 459 | 434 | again = false; |
|---|
| .. | .. |
|---|
| 505 | 480 | |
|---|
| 506 | 481 | flush_workqueue(rxrpc_workqueue); |
|---|
| 507 | 482 | |
|---|
| 508 | | - if (!list_empty(&rxnet->local_endpoints)) { |
|---|
| 483 | + if (!hlist_empty(&rxnet->local_endpoints)) { |
|---|
| 509 | 484 | mutex_lock(&rxnet->local_mutex); |
|---|
| 510 | | - list_for_each_entry(local, &rxnet->local_endpoints, link) { |
|---|
| 485 | + hlist_for_each_entry(local, &rxnet->local_endpoints, link) { |
|---|
| 511 | 486 | pr_err("AF_RXRPC: Leaked local %p {%d}\n", |
|---|
| 512 | | - local, atomic_read(&local->usage)); |
|---|
| 487 | + local, refcount_read(&local->ref)); |
|---|
| 513 | 488 | } |
|---|
| 514 | 489 | mutex_unlock(&rxnet->local_mutex); |
|---|
| 515 | 490 | BUG(); |
|---|