715 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/* AFS server record management3 *4 * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved.5 * Written by David Howells (dhowells@redhat.com)6 */7 8#include <linux/sched.h>9#include <linux/slab.h>10#include "afs_fs.h"11#include "internal.h"12#include "protocol_yfs.h"13 14static unsigned afs_server_gc_delay = 10; /* Server record timeout in seconds */15static atomic_t afs_server_debug_id;16 17static struct afs_server *afs_maybe_use_server(struct afs_server *,18 enum afs_server_trace);19static void __afs_put_server(struct afs_net *, struct afs_server *);20 21/*22 * Find a server by one of its addresses.23 */24struct afs_server *afs_find_server(struct afs_net *net, const struct rxrpc_peer *peer)25{26 const struct afs_endpoint_state *estate;27 const struct afs_addr_list *alist;28 struct afs_server *server = NULL;29 unsigned int i;30 int seq = 1;31 32 rcu_read_lock();33 34 do {35 if (server)36 afs_unuse_server_notime(net, server, afs_server_trace_put_find_rsq);37 server = NULL;38 seq++; /* 2 on the 1st/lockless path, otherwise odd */39 read_seqbegin_or_lock(&net->fs_addr_lock, &seq);40 41 hlist_for_each_entry_rcu(server, &net->fs_addresses, addr_link) {42 estate = rcu_dereference(server->endpoint_state);43 alist = estate->addresses;44 for (i = 0; i < alist->nr_addrs; i++)45 if (alist->addrs[i].peer == peer)46 goto found;47 }48 49 server = NULL;50 continue;51 found:52 server = afs_maybe_use_server(server, afs_server_trace_get_by_addr);53 54 } while (need_seqretry(&net->fs_addr_lock, seq));55 56 done_seqretry(&net->fs_addr_lock, seq);57 58 rcu_read_unlock();59 return server;60}61 62/*63 * Look up a server by its UUID and mark it active.64 */65struct afs_server *afs_find_server_by_uuid(struct afs_net *net, const uuid_t *uuid)66{67 struct afs_server *server = NULL;68 struct rb_node *p;69 int diff, seq = 1;70 71 _enter("%pU", uuid);72 73 do {74 /* Unfortunately, rbtree walking doesn't give reliable results75 * under just the RCU read lock, so we have to check for76 * changes.77 */78 if (server)79 afs_unuse_server(net, server, afs_server_trace_put_uuid_rsq);80 server = NULL;81 seq++; /* 2 on the 1st/lockless path, otherwise odd */82 read_seqbegin_or_lock(&net->fs_lock, &seq);83 84 p = net->fs_servers.rb_node;85 while (p) {86 server = rb_entry(p, struct afs_server, uuid_rb);87 88 diff = memcmp(uuid, &server->uuid, sizeof(*uuid));89 if (diff < 0) {90 p = p->rb_left;91 } else if (diff > 0) {92 p = p->rb_right;93 } else {94 afs_use_server(server, afs_server_trace_get_by_uuid);95 break;96 }97 98 server = NULL;99 }100 } while (need_seqretry(&net->fs_lock, seq));101 102 done_seqretry(&net->fs_lock, seq);103 104 _leave(" = %p", server);105 return server;106}107 108/*109 * Install a server record in the namespace tree. If there's a clash, we stick110 * it into a list anchored on whichever afs_server struct is actually in the111 * tree.112 */113static struct afs_server *afs_install_server(struct afs_cell *cell,114 struct afs_server *candidate)115{116 const struct afs_endpoint_state *estate;117 const struct afs_addr_list *alist;118 struct afs_server *server, *next;119 struct afs_net *net = cell->net;120 struct rb_node **pp, *p;121 int diff;122 123 _enter("%p", candidate);124 125 write_seqlock(&net->fs_lock);126 127 /* Firstly install the server in the UUID lookup tree */128 pp = &net->fs_servers.rb_node;129 p = NULL;130 while (*pp) {131 p = *pp;132 _debug("- consider %p", p);133 server = rb_entry(p, struct afs_server, uuid_rb);134 diff = memcmp(&candidate->uuid, &server->uuid, sizeof(uuid_t));135 if (diff < 0) {136 pp = &(*pp)->rb_left;137 } else if (diff > 0) {138 pp = &(*pp)->rb_right;139 } else {140 if (server->cell == cell)141 goto exists;142 143 /* We have the same UUID representing servers in144 * different cells. Append the new server to the list.145 */146 for (;;) {147 next = rcu_dereference_protected(148 server->uuid_next,149 lockdep_is_held(&net->fs_lock.lock));150 if (!next)151 break;152 server = next;153 }154 rcu_assign_pointer(server->uuid_next, candidate);155 candidate->uuid_prev = server;156 server = candidate;157 goto added_dup;158 }159 }160 161 server = candidate;162 rb_link_node(&server->uuid_rb, p, pp);163 rb_insert_color(&server->uuid_rb, &net->fs_servers);164 hlist_add_head_rcu(&server->proc_link, &net->fs_proc);165 166added_dup:167 write_seqlock(&net->fs_addr_lock);168 estate = rcu_dereference_protected(server->endpoint_state,169 lockdep_is_held(&net->fs_addr_lock.lock));170 alist = estate->addresses;171 172 /* Secondly, if the server has any IPv4 and/or IPv6 addresses, install173 * it in the IPv4 and/or IPv6 reverse-map lists.174 *175 * TODO: For speed we want to use something other than a flat list176 * here; even sorting the list in terms of lowest address would help a177 * bit, but anything we might want to do gets messy and memory178 * intensive.179 */180 if (alist->nr_addrs > 0)181 hlist_add_head_rcu(&server->addr_link, &net->fs_addresses);182 183 write_sequnlock(&net->fs_addr_lock);184 185exists:186 afs_get_server(server, afs_server_trace_get_install);187 write_sequnlock(&net->fs_lock);188 return server;189}190 191/*192 * Allocate a new server record and mark it active.193 */194static struct afs_server *afs_alloc_server(struct afs_cell *cell,195 const uuid_t *uuid,196 struct afs_addr_list *alist)197{198 struct afs_endpoint_state *estate;199 struct afs_server *server;200 struct afs_net *net = cell->net;201 202 _enter("");203 204 server = kzalloc(sizeof(struct afs_server), GFP_KERNEL);205 if (!server)206 goto enomem;207 208 estate = kzalloc(sizeof(struct afs_endpoint_state), GFP_KERNEL);209 if (!estate)210 goto enomem_server;211 212 refcount_set(&server->ref, 1);213 atomic_set(&server->active, 1);214 server->debug_id = atomic_inc_return(&afs_server_debug_id);215 server->addr_version = alist->version;216 server->uuid = *uuid;217 rwlock_init(&server->fs_lock);218 INIT_LIST_HEAD(&server->volumes);219 init_waitqueue_head(&server->probe_wq);220 INIT_LIST_HEAD(&server->probe_link);221 spin_lock_init(&server->probe_lock);222 server->cell = cell;223 server->rtt = UINT_MAX;224 server->service_id = FS_SERVICE;225 226 server->probe_counter = 1;227 server->probed_at = jiffies - LONG_MAX / 2;228 refcount_set(&estate->ref, 1);229 estate->addresses = alist;230 estate->server_id = server->debug_id;231 estate->probe_seq = 1;232 rcu_assign_pointer(server->endpoint_state, estate);233 234 afs_inc_servers_outstanding(net);235 trace_afs_server(server->debug_id, 1, 1, afs_server_trace_alloc);236 trace_afs_estate(estate->server_id, estate->probe_seq, refcount_read(&estate->ref),237 afs_estate_trace_alloc_server);238 _leave(" = %p", server);239 return server;240 241enomem_server:242 kfree(server);243enomem:244 _leave(" = NULL [nomem]");245 return NULL;246}247 248/*249 * Look up an address record for a server250 */251static struct afs_addr_list *afs_vl_lookup_addrs(struct afs_cell *cell,252 struct key *key, const uuid_t *uuid)253{254 struct afs_vl_cursor vc;255 struct afs_addr_list *alist = NULL;256 int ret;257 258 ret = -ERESTARTSYS;259 if (afs_begin_vlserver_operation(&vc, cell, key)) {260 while (afs_select_vlserver(&vc)) {261 if (test_bit(AFS_VLSERVER_FL_IS_YFS, &vc.server->flags))262 alist = afs_yfsvl_get_endpoints(&vc, uuid);263 else264 alist = afs_vl_get_addrs_u(&vc, uuid);265 }266 267 ret = afs_end_vlserver_operation(&vc);268 }269 270 return ret < 0 ? ERR_PTR(ret) : alist;271}272 273/*274 * Get or create a fileserver record.275 */276struct afs_server *afs_lookup_server(struct afs_cell *cell, struct key *key,277 const uuid_t *uuid, u32 addr_version)278{279 struct afs_addr_list *alist;280 struct afs_server *server, *candidate;281 282 _enter("%p,%pU", cell->net, uuid);283 284 server = afs_find_server_by_uuid(cell->net, uuid);285 if (server) {286 if (server->addr_version != addr_version)287 set_bit(AFS_SERVER_FL_NEEDS_UPDATE, &server->flags);288 return server;289 }290 291 alist = afs_vl_lookup_addrs(cell, key, uuid);292 if (IS_ERR(alist))293 return ERR_CAST(alist);294 295 candidate = afs_alloc_server(cell, uuid, alist);296 if (!candidate) {297 afs_put_addrlist(alist, afs_alist_trace_put_server_oom);298 return ERR_PTR(-ENOMEM);299 }300 301 server = afs_install_server(cell, candidate);302 if (server != candidate) {303 afs_put_addrlist(alist, afs_alist_trace_put_server_dup);304 kfree(candidate);305 } else {306 /* Immediately dispatch an asynchronous probe to each interface307 * on the fileserver. This will make sure the repeat-probing308 * service is started.309 */310 afs_fs_probe_fileserver(cell->net, server, alist, key);311 }312 313 return server;314}315 316/*317 * Set the server timer to fire after a given delay, assuming it's not already318 * set for an earlier time.319 */320static void afs_set_server_timer(struct afs_net *net, time64_t delay)321{322 if (net->live) {323 afs_inc_servers_outstanding(net);324 if (timer_reduce(&net->fs_timer, jiffies + delay * HZ))325 afs_dec_servers_outstanding(net);326 }327}328 329/*330 * Server management timer. We have an increment on fs_outstanding that we331 * need to pass along to the work item.332 */333void afs_servers_timer(struct timer_list *timer)334{335 struct afs_net *net = container_of(timer, struct afs_net, fs_timer);336 337 _enter("");338 if (!queue_work(afs_wq, &net->fs_manager))339 afs_dec_servers_outstanding(net);340}341 342/*343 * Get a reference on a server object.344 */345struct afs_server *afs_get_server(struct afs_server *server,346 enum afs_server_trace reason)347{348 unsigned int a;349 int r;350 351 __refcount_inc(&server->ref, &r);352 a = atomic_read(&server->active);353 trace_afs_server(server->debug_id, r + 1, a, reason);354 return server;355}356 357/*358 * Try to get a reference on a server object.359 */360static struct afs_server *afs_maybe_use_server(struct afs_server *server,361 enum afs_server_trace reason)362{363 unsigned int a;364 int r;365 366 if (!__refcount_inc_not_zero(&server->ref, &r))367 return NULL;368 369 a = atomic_inc_return(&server->active);370 trace_afs_server(server->debug_id, r + 1, a, reason);371 return server;372}373 374/*375 * Get an active count on a server object.376 */377struct afs_server *afs_use_server(struct afs_server *server, enum afs_server_trace reason)378{379 unsigned int a;380 int r;381 382 __refcount_inc(&server->ref, &r);383 a = atomic_inc_return(&server->active);384 385 trace_afs_server(server->debug_id, r + 1, a, reason);386 return server;387}388 389/*390 * Release a reference on a server record.391 */392void afs_put_server(struct afs_net *net, struct afs_server *server,393 enum afs_server_trace reason)394{395 unsigned int a, debug_id = server->debug_id;396 bool zero;397 int r;398 399 if (!server)400 return;401 402 a = atomic_read(&server->active);403 zero = __refcount_dec_and_test(&server->ref, &r);404 trace_afs_server(debug_id, r - 1, a, reason);405 if (unlikely(zero))406 __afs_put_server(net, server);407}408 409/*410 * Drop an active count on a server object without updating the last-unused411 * time.412 */413void afs_unuse_server_notime(struct afs_net *net, struct afs_server *server,414 enum afs_server_trace reason)415{416 if (server) {417 unsigned int active = atomic_dec_return(&server->active);418 419 if (active == 0)420 afs_set_server_timer(net, afs_server_gc_delay);421 afs_put_server(net, server, reason);422 }423}424 425/*426 * Drop an active count on a server object.427 */428void afs_unuse_server(struct afs_net *net, struct afs_server *server,429 enum afs_server_trace reason)430{431 if (server) {432 server->unuse_time = ktime_get_real_seconds();433 afs_unuse_server_notime(net, server, reason);434 }435}436 437static void afs_server_rcu(struct rcu_head *rcu)438{439 struct afs_server *server = container_of(rcu, struct afs_server, rcu);440 441 trace_afs_server(server->debug_id, refcount_read(&server->ref),442 atomic_read(&server->active), afs_server_trace_free);443 afs_put_endpoint_state(rcu_access_pointer(server->endpoint_state),444 afs_estate_trace_put_server);445 kfree(server);446}447 448static void __afs_put_server(struct afs_net *net, struct afs_server *server)449{450 call_rcu(&server->rcu, afs_server_rcu);451 afs_dec_servers_outstanding(net);452}453 454static void afs_give_up_callbacks(struct afs_net *net, struct afs_server *server)455{456 struct afs_endpoint_state *estate = rcu_access_pointer(server->endpoint_state);457 struct afs_addr_list *alist = estate->addresses;458 459 afs_fs_give_up_all_callbacks(net, server, &alist->addrs[alist->preferred], NULL);460}461 462/*463 * destroy a dead server464 */465static void afs_destroy_server(struct afs_net *net, struct afs_server *server)466{467 if (test_bit(AFS_SERVER_FL_MAY_HAVE_CB, &server->flags))468 afs_give_up_callbacks(net, server);469 470 afs_put_server(net, server, afs_server_trace_destroy);471}472 473/*474 * Garbage collect any expired servers.475 */476static void afs_gc_servers(struct afs_net *net, struct afs_server *gc_list)477{478 struct afs_server *server, *next, *prev;479 int active;480 481 while ((server = gc_list)) {482 gc_list = server->gc_next;483 484 write_seqlock(&net->fs_lock);485 486 active = atomic_read(&server->active);487 if (active == 0) {488 trace_afs_server(server->debug_id, refcount_read(&server->ref),489 active, afs_server_trace_gc);490 next = rcu_dereference_protected(491 server->uuid_next, lockdep_is_held(&net->fs_lock.lock));492 prev = server->uuid_prev;493 if (!prev) {494 /* The one at the front is in the tree */495 if (!next) {496 rb_erase(&server->uuid_rb, &net->fs_servers);497 } else {498 rb_replace_node_rcu(&server->uuid_rb,499 &next->uuid_rb,500 &net->fs_servers);501 next->uuid_prev = NULL;502 }503 } else {504 /* This server is not at the front */505 rcu_assign_pointer(prev->uuid_next, next);506 if (next)507 next->uuid_prev = prev;508 }509 510 list_del(&server->probe_link);511 hlist_del_rcu(&server->proc_link);512 if (!hlist_unhashed(&server->addr_link))513 hlist_del_rcu(&server->addr_link);514 }515 write_sequnlock(&net->fs_lock);516 517 if (active == 0)518 afs_destroy_server(net, server);519 }520}521 522/*523 * Manage the records of servers known to be within a network namespace. This524 * includes garbage collecting unused servers.525 *526 * Note also that we were given an increment on net->servers_outstanding by527 * whoever queued us that we need to deal with before returning.528 */529void afs_manage_servers(struct work_struct *work)530{531 struct afs_net *net = container_of(work, struct afs_net, fs_manager);532 struct afs_server *gc_list = NULL;533 struct rb_node *cursor;534 time64_t now = ktime_get_real_seconds(), next_manage = TIME64_MAX;535 bool purging = !net->live;536 537 _enter("");538 539 /* Trawl the server list looking for servers that have expired from540 * lack of use.541 */542 read_seqlock_excl(&net->fs_lock);543 544 for (cursor = rb_first(&net->fs_servers); cursor; cursor = rb_next(cursor)) {545 struct afs_server *server =546 rb_entry(cursor, struct afs_server, uuid_rb);547 int active = atomic_read(&server->active);548 549 _debug("manage %pU %u", &server->uuid, active);550 551 if (purging) {552 trace_afs_server(server->debug_id, refcount_read(&server->ref),553 active, afs_server_trace_purging);554 if (active != 0)555 pr_notice("Can't purge s=%08x\n", server->debug_id);556 }557 558 if (active == 0) {559 time64_t expire_at = server->unuse_time;560 561 if (!test_bit(AFS_SERVER_FL_VL_FAIL, &server->flags) &&562 !test_bit(AFS_SERVER_FL_NOT_FOUND, &server->flags))563 expire_at += afs_server_gc_delay;564 if (purging || expire_at <= now) {565 server->gc_next = gc_list;566 gc_list = server;567 } else if (expire_at < next_manage) {568 next_manage = expire_at;569 }570 }571 }572 573 read_sequnlock_excl(&net->fs_lock);574 575 /* Update the timer on the way out. We have to pass an increment on576 * servers_outstanding in the namespace that we are in to the timer or577 * the work scheduler.578 */579 if (!purging && next_manage < TIME64_MAX) {580 now = ktime_get_real_seconds();581 582 if (next_manage - now <= 0) {583 if (queue_work(afs_wq, &net->fs_manager))584 afs_inc_servers_outstanding(net);585 } else {586 afs_set_server_timer(net, next_manage - now);587 }588 }589 590 afs_gc_servers(net, gc_list);591 592 afs_dec_servers_outstanding(net);593 _leave(" [%d]", atomic_read(&net->servers_outstanding));594}595 596static void afs_queue_server_manager(struct afs_net *net)597{598 afs_inc_servers_outstanding(net);599 if (!queue_work(afs_wq, &net->fs_manager))600 afs_dec_servers_outstanding(net);601}602 603/*604 * Purge list of servers.605 */606void afs_purge_servers(struct afs_net *net)607{608 _enter("");609 610 if (del_timer_sync(&net->fs_timer))611 afs_dec_servers_outstanding(net);612 613 afs_queue_server_manager(net);614 615 _debug("wait");616 atomic_dec(&net->servers_outstanding);617 wait_var_event(&net->servers_outstanding,618 !atomic_read(&net->servers_outstanding));619 _leave("");620}621 622/*623 * Get an update for a server's address list.624 */625static noinline bool afs_update_server_record(struct afs_operation *op,626 struct afs_server *server,627 struct key *key)628{629 struct afs_endpoint_state *estate;630 struct afs_addr_list *alist;631 bool has_addrs;632 633 _enter("");634 635 trace_afs_server(server->debug_id, refcount_read(&server->ref),636 atomic_read(&server->active),637 afs_server_trace_update);638 639 alist = afs_vl_lookup_addrs(op->volume->cell, op->key, &server->uuid);640 if (IS_ERR(alist)) {641 rcu_read_lock();642 estate = rcu_dereference(server->endpoint_state);643 has_addrs = estate->addresses;644 rcu_read_unlock();645 646 if ((PTR_ERR(alist) == -ERESTARTSYS ||647 PTR_ERR(alist) == -EINTR) &&648 (op->flags & AFS_OPERATION_UNINTR) &&649 has_addrs) {650 _leave(" = t [intr]");651 return true;652 }653 afs_op_set_error(op, PTR_ERR(alist));654 _leave(" = f [%d]", afs_op_error(op));655 return false;656 }657 658 if (server->addr_version != alist->version)659 afs_fs_probe_fileserver(op->net, server, alist, key);660 661 afs_put_addrlist(alist, afs_alist_trace_put_server_update);662 _leave(" = t");663 return true;664}665 666/*667 * See if a server's address list needs updating.668 */669bool afs_check_server_record(struct afs_operation *op, struct afs_server *server,670 struct key *key)671{672 bool success;673 int ret, retries = 0;674 675 _enter("");676 677 ASSERT(server);678 679retry:680 if (test_bit(AFS_SERVER_FL_UPDATING, &server->flags))681 goto wait;682 if (test_bit(AFS_SERVER_FL_NEEDS_UPDATE, &server->flags))683 goto update;684 _leave(" = t [good]");685 return true;686 687update:688 if (!test_and_set_bit_lock(AFS_SERVER_FL_UPDATING, &server->flags)) {689 clear_bit(AFS_SERVER_FL_NEEDS_UPDATE, &server->flags);690 success = afs_update_server_record(op, server, key);691 clear_bit_unlock(AFS_SERVER_FL_UPDATING, &server->flags);692 wake_up_bit(&server->flags, AFS_SERVER_FL_UPDATING);693 _leave(" = %d", success);694 return success;695 }696 697wait:698 ret = wait_on_bit(&server->flags, AFS_SERVER_FL_UPDATING,699 (op->flags & AFS_OPERATION_UNINTR) ?700 TASK_UNINTERRUPTIBLE : TASK_INTERRUPTIBLE);701 if (ret == -ERESTARTSYS) {702 afs_op_set_error(op, ret);703 _leave(" = f [intr]");704 return false;705 }706 707 retries++;708 if (retries == 4) {709 _leave(" = f [stale]");710 ret = -ESTALE;711 return false;712 }713 goto retry;714}715