// SPDX-License-Identifier: GPL-2.0-or-later /* Handle vlserver selection and rotation. * * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com)
*/
/* * Begin iteration through a server list, starting with the last used server if * possible, or the last recorded good server if not.
*/ staticbool afs_start_vl_iteration(struct afs_vl_cursor *vc)
{ struct afs_cell *cell = vc->cell; unsignedint dns_lookup_count;
if (cell->dns_source == DNS_RECORD_UNAVAILABLE) { if (wait_var_event_interruptible(
&cell->dns_lookup_count,
smp_load_acquire(&cell->dns_lookup_count)
!= dns_lookup_count) < 0) {
vc->cumul_error.error = -ERESTARTSYS; returnfalse;
}
}
/* Status load is ordered after lookup counter load */ if (cell->dns_status == DNS_LOOKUP_GOT_NOT_FOUND) {
pr_warn("No record of cell %s\n", cell->name);
vc->cumul_error.error = -ENOENT; returnfalse;
}
/* * Select the vlserver to use. May be called multiple times to rotate * through the vlservers.
*/ bool afs_select_vlserver(struct afs_vl_cursor *vc)
{ struct afs_addr_list *alist = vc->alist; struct afs_vlserver *vlserver; unsignedlong set, failed; unsignedint rtt;
s32 abort_code = vc->call_abort_code; int error = vc->call_error, i;
/* Evaluate the result of the previous operation, if there was one. */ switch (error) { default: case 0: /* Success or local failure. Stop. */
vc->cumul_error.error = error;
vc->flags |= AFS_VL_CURSOR_STOP;
_leave(" = f [okay/local %d]", vc->cumul_error.error); returnfalse;
case -ECONNABORTED: /* The far side rejected the operation on some grounds. This * might involve the server being busy or the volume having been moved.
*/ switch (abort_code) { case AFSVL_IO: case AFSVL_BADVOLOPER: case AFSVL_NOMEM: /* The server went weird. */
afs_prioritise_error(&vc->cumul_error, -EREMOTEIO, abort_code); //write_lock(&vc->cell->vl_servers_lock); //vc->server_list->weird_mask |= 1 << vc->server_index; //write_unlock(&vc->cell->vl_servers_lock); goto next_server;
case -ERFKILL: case -EADDRNOTAVAIL: case -ENETUNREACH: case -EHOSTUNREACH: case -EHOSTDOWN: case -ECONNREFUSED: case -ETIMEDOUT: case -ETIME:
_debug("no conn %d", error);
afs_prioritise_error(&vc->cumul_error, error, 0); goto iterate_address;
/* Pick the untried server with the lowest RTT. */
vc->server_index = vc->server_list->preferred; if (test_bit(vc->server_index, &vc->untried_servers)) goto selected_server;
vc->server_index = -1;
rtt = UINT_MAX; for (i = 0; i < vc->server_list->nr_servers; i++) { struct afs_vlserver *s = vc->server_list->servers[i].server;
if (!test_bit(i, &vc->untried_servers) ||
!test_bit(AFS_VLSERVER_FL_RESPONDING, &s->flags)) continue; if (s->probe.rtt <= rtt) {
vc->server_index = i;
rtt = s->probe.rtt;
}
}
/* We're starting on a different vlserver from the list. We need to * check it, find its address list and probe its capabilities before we * use it.
*/
vlserver = vc->server_list->servers[vc->server_index].server;
vc->server = vlserver;
iterate_address: /* Iterate over the current server's address list to try and find an * address on which it will respond to us.
*/
set = READ_ONCE(alist->responded);
failed = READ_ONCE(alist->probe_failed);
vc->addr_index = READ_ONCE(alist->preferred);
no_more_servers: /* That's all the servers poked to no good effect. Try again if some * of them were busy.
*/ if (vc->flags & AFS_VL_CURSOR_RETRY) goto restart_from_beginning;
for (i = 0; i < vc->server_list->nr_servers; i++) { struct afs_vlserver *s = vc->server_list->servers[i].server;
if (test_bit(AFS_VLSERVER_FL_RESPONDING, &s->flags))
vc->cumul_error.responded = true;
afs_prioritise_error(&vc->cumul_error, READ_ONCE(s->probe.error),
s->probe.abort_code);
}
/* * Dump cursor state in the case of the error being EDESTADDRREQ.
*/ staticvoid afs_vl_dump_edestaddrreq(conststruct afs_vl_cursor *vc)
{ struct afs_cell *cell = vc->cell; staticint count; int i;
if (!IS_ENABLED(CONFIG_AFS_DEBUG_CURSOR) || count > 3) return;
count++;
/* * Tidy up a volume location server cursor and unlock the vnode.
*/ int afs_end_vlserver_operation(struct afs_vl_cursor *vc)
{ struct afs_net *net = vc->cell->net;
switch (vc->cumul_error.error) { case -EDESTADDRREQ: case -EADDRNOTAVAIL: case -ENETUNREACH: case -EHOSTUNREACH:
afs_vl_dump_edestaddrreq(vc); break;
}
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.