// SPDX-License-Identifier: GPL-2.0-or-later /* AFS fileserver probing * * Copyright (C) 2018, 2020 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com)
*/
dead = __refcount_dec_and_test(&estate->ref, &r);
trace_afs_estate(server_id, probe_seq, r, where); if (dead)
call_rcu(&estate->rcu, afs_endpoint_state_rcu);
}
}
/* * Start the probe polling timer. We have to supply it with an inc on the * outstanding server count.
*/ staticvoid afs_schedule_fs_probe(struct afs_net *net, struct afs_server *server, bool fast)
{ unsignedlong atj;
if (!net->live) return;
atj = server->probed_at;
atj += fast ? afs_fs_probe_fast_poll_interval : afs_fs_probe_slow_poll_interval;
afs_inc_servers_outstanding(net); if (timer_reduce(&net->fs_probe_timer, atj))
afs_dec_servers_outstanding(net);
}
/* * Handle the completion of a set of probes.
*/ staticvoid afs_finished_fs_probe(struct afs_net *net, struct afs_server *server, struct afs_endpoint_state *estate)
{ bool responded = test_bit(AFS_ESTATE_RESPONDED, &estate->flags);
/* * Handle the completion of a probe.
*/ staticvoid afs_done_one_fs_probe(struct afs_net *net, struct afs_server *server, struct afs_endpoint_state *estate)
{
_enter("");
if (atomic_dec_and_test(&estate->nr_probing))
afs_finished_fs_probe(net, server, estate);
wake_up_all(&server->probe_wq);
}
/* * Handle inability to send a probe due to ENOMEM when trying to allocate a * call struct.
*/ staticvoid afs_fs_probe_not_done(struct afs_net *net, struct afs_server *server, struct afs_endpoint_state *estate, int index)
{
_enter("");
/* * Process the result of probing a fileserver. This is called after successful * or failed delivery of an FS.GetCapabilities operation.
*/ void afs_fileserver_probe_result(struct afs_call *call)
{ struct afs_endpoint_state *estate = call->probe; struct afs_addr_list *alist = estate->addresses; struct afs_address *addr = &alist->addrs[call->probe_index]; struct afs_server *server = call->server; unsignedint index = call->probe_index; unsignedint rtt_us = -1, cap0; int ret = call->error;
_enter("%pU,%u", &server->uuid, index);
WRITE_ONCE(addr->last_error, ret);
spin_lock(&server->probe_lock);
switch (ret) { case 0:
estate->error = 0; goto responded; case -ECONNABORTED: if (!test_bit(AFS_ESTATE_RESPONDED, &estate->flags)) {
estate->abort_code = call->abort_code;
estate->error = ret;
} goto responded; case -ENOMEM: case -ENONET:
clear_bit(index, &estate->responsive_set);
set_bit(AFS_ESTATE_LOCAL_FAILURE, &estate->flags);
trace_afs_io_error(call->debug_id, ret, afs_io_error_fs_probe_fail); goto out; case -ECONNRESET: /* Responded, but call expired. */ case -ERFKILL: case -EADDRNOTAVAIL: case -ENETUNREACH: case -EHOSTUNREACH: case -EHOSTDOWN: case -ECONNREFUSED: case -ETIMEDOUT: case -ETIME: default:
clear_bit(index, &estate->responsive_set);
set_bit(index, &estate->failed_set); if (!test_bit(AFS_ESTATE_RESPONDED, &estate->flags) &&
(estate->error == 0 ||
estate->error == -ETIMEDOUT ||
estate->error == -ETIME))
estate->error = ret;
trace_afs_io_error(call->debug_id, ret, afs_io_error_fs_probe_fail); goto out;
}
/* * Probe all of a fileserver's addresses to find out the best route and to * query its capabilities.
*/ int afs_fs_probe_fileserver(struct afs_net *net, struct afs_server *server, struct afs_addr_list *new_alist, struct key *key)
{ struct afs_endpoint_state *estate, *old; struct afs_addr_list *old_alist = NULL, *alist; unsignedlong unprobed;
_enter("%pU", &server->uuid);
estate = kzalloc(sizeof(*estate), GFP_KERNEL); if (!estate) return -ENOMEM;
/* * Wait for the first as-yet untried fileserver to respond, for the probe state * to be superseded or for all probes to finish.
*/ int afs_wait_for_fs_probes(struct afs_operation *op, struct afs_server_state *states, bool intr)
{ struct afs_endpoint_state *estate; struct afs_server_list *slist = op->server_list; bool still_probing = true; int ret = 0, i;
_enter("%u", slist->nr_servers);
for (i = 0; i < slist->nr_servers; i++) {
estate = states[i].endpoint_state; if (test_bit(AFS_ESTATE_SUPERSEDED, &estate->flags)) return 2; if (atomic_read(&estate->nr_probing))
still_probing = true; if (estate->responsive_set & states[i].untried_addrs) return 1;
} if (!still_probing) return 0;
for (i = 0; i < slist->nr_servers; i++)
add_wait_queue(&slist->servers[i].server->probe_wq, &states[i].probe_waiter);
for (;;) {
still_probing = false;
set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); for (i = 0; i < slist->nr_servers; i++) {
estate = states[i].endpoint_state; if (test_bit(AFS_ESTATE_SUPERSEDED, &estate->flags)) {
ret = 2; goto stop;
} if (atomic_read(&estate->nr_probing))
still_probing = true; if (estate->responsive_set & states[i].untried_addrs) {
ret = 1; goto stop;
}
}
if (!still_probing || signal_pending(current)) goto stop;
schedule();
}
stop:
set_current_state(TASK_RUNNING);
for (i = 0; i < slist->nr_servers; i++)
remove_wait_queue(&slist->servers[i].server->probe_wq, &states[i].probe_waiter);
if (!ret && signal_pending(current))
ret = -ERESTARTSYS; return ret;
}
/* * Probe timer. We have an increment on fs_outstanding that we need to pass * along to the work item.
*/ void afs_fs_probe_timer(struct timer_list *timer)
{ struct afs_net *net = container_of(timer, struct afs_net, fs_probe_timer);
if (!net->live || !queue_work(afs_wq, &net->fs_prober))
afs_dec_servers_outstanding(net);
}
/* * Dispatch a probe to a server.
*/ staticvoid afs_dispatch_fs_probe(struct afs_net *net, struct afs_server *server)
__releases(&net->fs_lock)
{ struct key *key = NULL;
/* We remove it from the queues here - it will be added back to * one of the queues on the completion of the probe.
*/
list_del_init(&server->probe_link);
/* * Probe a server immediately without waiting for its due time to come * round. This is used when all of the addresses have been tried.
*/ void afs_probe_fileserver(struct afs_net *net, struct afs_server *server)
{
write_seqlock(&net->fs_lock); if (!list_empty(&server->probe_link)) return afs_dispatch_fs_probe(net, server);
write_sequnlock(&net->fs_lock);
}
if (server) { if (!queue_work(afs_wq, &net->fs_prober))
afs_dec_servers_outstanding(net);
_leave(" [requeue]");
} elseif (set_timer) { if (timer_reduce(&net->fs_probe_timer, timer_at))
afs_dec_servers_outstanding(net);
_leave(" [timer]");
} else {
afs_dec_servers_outstanding(net);
_leave(" [quiesce]");
}
}
/* * Wait for a probe on a particular fileserver to complete for 2s.
*/ int afs_wait_for_one_fs_probe(struct afs_server *server, struct afs_endpoint_state *estate, unsignedlong exclude, bool is_intr)
{ struct wait_queue_entry wait; unsignedlong timo = 2 * HZ;
if (atomic_read(&estate->nr_probing) == 0) goto dont_wait;
dont_wait: if (test_bit(AFS_ESTATE_SUPERSEDED, &estate->flags)) return 0; if (estate->responsive_set & ~exclude) return 1; if (is_intr && signal_pending(current)) return -ERESTARTSYS; if (timo == 0) return -ETIME; return -EDESTADDRREQ;
}
/* * Clean up the probing when the namespace is killed off.
*/ void afs_fs_probe_cleanup(struct afs_net *net)
{ if (timer_delete_sync(&net->fs_probe_timer))
afs_dec_servers_outstanding(net);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.