afs: Simplify error handling

Simplify error handling a bit by moving it from the afs_addr_cursor struct
to the afs_operation and afs_vl_cursor structs and using the error
prioritisation function for accumulating errors from multiple sources (AFS
tries to rotate between multiple fileservers, some of which may be
inaccessible or in some state of offlinedness).

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: linux-afs@lists.infradead.org
This commit is contained in:
David Howells 2023-10-25 17:53:33 +01:00
parent 6f2ff7e89b
commit aa453becce
15 changed files with 174 additions and 143 deletions

View File

@ -386,26 +386,24 @@ bool afs_iterate_addresses(struct afs_addr_cursor *ac)
selected:
ac->index = index;
set_bit(index, &ac->tried);
ac->responded = false;
ac->call_responded = false;
return true;
}
/*
* Release an address list cursor.
*/
int afs_end_cursor(struct afs_addr_cursor *ac)
void afs_end_cursor(struct afs_addr_cursor *ac)
{
struct afs_addr_list *alist;
alist = ac->alist;
if (alist) {
if (ac->responded &&
if (ac->call_responded &&
ac->index != alist->preferred &&
test_bit(ac->alist->preferred, &ac->tried))
WRITE_ONCE(alist->preferred, ac->index);
afs_put_addrlist(alist);
ac->alist = NULL;
}
return ac->error;
}

View File

@ -693,8 +693,9 @@ static void afs_do_lookup_success(struct afs_operation *op)
vp = &op->file[0];
abort_code = vp->scb.status.abort_code;
if (abort_code != 0) {
op->ac.abort_code = abort_code;
op->error = afs_abort_to_error(abort_code);
op->call_abort_code = abort_code;
afs_op_set_error(op, afs_abort_to_error(abort_code));
op->cumul_error.abort_code = abort_code;
}
break;
@ -846,13 +847,14 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry,
_debug("nr_files %u", op->nr_files);
/* Need space for examining all the selected files */
op->error = -ENOMEM;
if (op->nr_files > 2) {
op->more_files = kvcalloc(op->nr_files - 2,
sizeof(struct afs_vnode_param),
GFP_KERNEL);
if (!op->more_files)
if (!op->more_files) {
afs_op_nomem(op);
goto out_op;
}
for (i = 2; i < op->nr_files; i++) {
vp = &op->more_files[i - 2];
@ -1255,7 +1257,7 @@ void afs_check_for_remote_deletion(struct afs_operation *op)
{
struct afs_vnode *vnode = op->file[0].vnode;
switch (op->ac.abort_code) {
switch (afs_op_abort_code(op)) {
case VNOVNODE:
set_bit(AFS_VNODE_DELETED, &vnode->flags);
afs_break_callback(vnode, afs_cb_break_for_deleted);
@ -1280,7 +1282,7 @@ static void afs_vnode_new_inode(struct afs_operation *op)
/* ENOMEM or EINTR at a really inconvenient time - just abandon
* the new directory on the server.
*/
op->error = PTR_ERR(inode);
afs_op_accumulate_error(op, PTR_ERR(inode), 0);
return;
}

View File

@ -218,7 +218,7 @@ static int afs_do_silly_unlink(struct afs_vnode *dvnode, struct afs_vnode *vnode
/* If there was a conflict with a third party, check the status of the
* unlinked vnode.
*/
if (op->error == 0 && (op->flags & AFS_OPERATION_DIR_CONFLICT)) {
if (op->cumul_error.error == 0 && (op->flags & AFS_OPERATION_DIR_CONFLICT)) {
op->file[1].update_ctime = false;
op->fetch_status.which = 1;
op->ops = &afs_fetch_status_operation;

View File

@ -245,10 +245,7 @@ static void afs_fetch_data_notify(struct afs_operation *op)
struct netfs_io_subrequest *subreq = req->subreq;
int error = afs_op_error(op);
if (error == -ECONNABORTED)
error = afs_abort_to_error(op->ac.abort_code);
req->error = error;
if (subreq) {
__set_bit(NETFS_SREQ_CLEAR_TAIL, &subreq->flags);
netfs_subreq_terminated(subreq, error ?: req->actual_len, false);

View File

@ -169,9 +169,6 @@ static void afs_end_vnode_operation(struct afs_operation *op)
}
afs_drop_io_locks(op);
if (op->error == -ECONNABORTED)
op->error = afs_abort_to_error(op->ac.abort_code);
}
/*
@ -182,6 +179,8 @@ void afs_wait_for_operation(struct afs_operation *op)
_enter("");
while (afs_select_fileserver(op)) {
op->call_error = 0;
op->call_abort_code = 0;
op->cb_s_break = op->server->cb_s_break;
if (test_bit(AFS_SERVER_FL_IS_YFS, &op->server->flags) &&
op->ops->issue_yfs_rpc)
@ -189,28 +188,29 @@ void afs_wait_for_operation(struct afs_operation *op)
else if (op->ops->issue_afs_rpc)
op->ops->issue_afs_rpc(op);
else
op->ac.error = -ENOTSUPP;
op->call_error = -ENOTSUPP;
if (op->call) {
afs_wait_for_call_to_complete(op->call, &op->ac);
op->error = op->ac.error;
op->call_abort_code = op->call->abort_code;
op->call_error = op->call->error;
op->call_responded = op->call->responded;
op->ac.call_responded = true;
WRITE_ONCE(op->ac.alist->addrs[op->ac.index].last_error,
op->call_error);
afs_put_call(op->call);
}
}
switch (op->error) {
case 0:
if (!afs_op_error(op)) {
_debug("success");
op->ops->success(op);
break;
case -ECONNABORTED:
} else if (op->cumul_error.aborted) {
if (op->ops->aborted)
op->ops->aborted(op);
fallthrough;
default:
} else {
if (op->ops->failed)
op->ops->failed(op);
break;
}
afs_end_vnode_operation(op);

View File

@ -1629,6 +1629,7 @@ int afs_fs_give_up_all_callbacks(struct afs_net *net,
call->server = afs_use_server(server, afs_server_trace_give_up_cb);
afs_make_call(ac, call, GFP_NOFS);
afs_wait_for_call_to_complete(call, ac);
ret = call->error;
afs_put_call(call);
return ret;
}

View File

@ -75,6 +75,7 @@ enum afs_call_state {
struct afs_address {
struct rxrpc_peer *peer;
u16 service_id;
short last_error; /* Last error from this address */
};
/*
@ -121,7 +122,6 @@ struct afs_call {
};
void *buffer; /* reply receive buffer */
union {
long ret0; /* Value to reply with instead of 0 */
struct afs_addr_list *ret_alist;
struct afs_vldb_entry *ret_vldb;
char *ret_str;
@ -145,6 +145,7 @@ struct afs_call {
bool upgrade; /* T to request service upgrade */
bool intr; /* T if interruptible */
bool unmarshalling_error; /* T if an unmarshalling error occurred */
bool responded; /* Got a response from the call (may be abort) */
u16 service_id; /* Actual service ID (after upgrade) */
unsigned int debug_id; /* Trace ID */
u32 operation_ID; /* operation ID for an incoming call */
@ -719,8 +720,10 @@ struct afs_permits {
* Error prioritisation and accumulation.
*/
struct afs_error {
short error; /* Accumulated error */
s32 abort_code; /* Cumulative abort code */
short error; /* Cumulative error */
bool responded; /* T if server responded */
bool aborted; /* T if ->error is from an abort */
};
/*
@ -730,10 +733,8 @@ struct afs_addr_cursor {
struct afs_addr_list *alist; /* Current address list (pins ref) */
unsigned long tried; /* Tried addresses */
signed char index; /* Current address */
bool responded; /* T if the current address responded */
unsigned short nr_iterations; /* Number of address iterations */
short error;
u32 abort_code;
bool call_responded;
};
/*
@ -746,13 +747,16 @@ struct afs_vl_cursor {
struct afs_vlserver *server; /* Server on which this resides */
struct key *key; /* Key for the server */
unsigned long untried; /* Bitmask of untried servers */
struct afs_error cumul_error; /* Cumulative error */
s32 call_abort_code;
short index; /* Current server */
short error;
short call_error; /* Error from single call */
unsigned short flags;
#define AFS_VL_CURSOR_STOP 0x0001 /* Set to cease iteration */
#define AFS_VL_CURSOR_RETRY 0x0002 /* Set to do a retry */
#define AFS_VL_CURSOR_RETRIED 0x0004 /* Set if started a retry */
unsigned short nr_iterations; /* Number of server iterations */
short nr_iterations; /* Number of server iterations */
bool call_responded; /* T if the current address responded */
};
/*
@ -803,8 +807,10 @@ struct afs_operation {
struct dentry *dentry_2; /* Second dentry to be altered */
struct timespec64 mtime; /* Modification time to record */
struct timespec64 ctime; /* Change time to set */
struct afs_error cumul_error; /* Cumulative error */
short nr_files; /* Number of entries in file[], more_files */
short error;
short call_error; /* Error from single call */
s32 call_abort_code; /* Abort code from single call */
unsigned int debug_id;
unsigned int cb_v_break; /* Volume break counter before op */
@ -860,6 +866,8 @@ struct afs_operation {
unsigned long untried; /* Bitmask of untried servers */
short index; /* Current server */
short nr_iterations; /* Number of server iterations */
bool call_responded; /* T if the current address responded */
unsigned int flags;
#define AFS_OPERATION_STOP 0x0001 /* Set to cease iteration */
@ -976,7 +984,7 @@ bool afs_addr_list_same(const struct afs_addr_list *a,
const struct afs_addr_list *b);
extern struct afs_vlserver_list *afs_dns_query(struct afs_cell *, time64_t *);
extern bool afs_iterate_addresses(struct afs_addr_cursor *);
extern int afs_end_cursor(struct afs_addr_cursor *);
extern void afs_end_cursor(struct afs_addr_cursor *ac);
extern int afs_merge_fs_addr4(struct afs_net *net, struct afs_addr_list *addr,
__be32 xdr, u16 port);
@ -1235,17 +1243,27 @@ extern void afs_prioritise_error(struct afs_error *, int, u32);
static inline void afs_op_nomem(struct afs_operation *op)
{
op->error = -ENOMEM;
op->cumul_error.error = -ENOMEM;
}
static inline int afs_op_error(const struct afs_operation *op)
{
return op->error;
return op->cumul_error.error;
}
static inline s32 afs_op_abort_code(const struct afs_operation *op)
{
return op->cumul_error.abort_code;
}
static inline int afs_op_set_error(struct afs_operation *op, int error)
{
return op->error = error;
return op->cumul_error.error = error;
}
static inline void afs_op_accumulate_error(struct afs_operation *op, int error, s32 abort_code)
{
afs_prioritise_error(&op->cumul_error, error, abort_code);
}
/*
@ -1619,7 +1637,7 @@ static inline void afs_update_dentry_version(struct afs_operation *op,
struct afs_vnode_param *dir_vp,
struct dentry *dentry)
{
if (!op->error)
if (!op->cumul_error.error)
dentry->d_fsdata =
(void *)(unsigned long)dir_vp->scb.status.data_version;
}

View File

@ -116,6 +116,8 @@ void afs_prioritise_error(struct afs_error *e, int error, u32 abort_code)
{
switch (error) {
case 0:
e->aborted = false;
e->error = 0;
return;
default:
if (e->error == -ETIMEDOUT ||
@ -161,12 +163,16 @@ void afs_prioritise_error(struct afs_error *e, int error, u32 abort_code)
if (e->responded)
return;
e->error = error;
e->aborted = false;
return;
case -ECONNABORTED:
error = afs_abort_to_error(abort_code);
fallthrough;
e->error = afs_abort_to_error(abort_code);
e->aborted = true;
e->responded = true;
return;
case -ENETRESET: /* Responded, but we seem to have changed address */
e->aborted = false;
e->responded = true;
e->error = error;
return;

View File

@ -112,9 +112,9 @@ bool afs_select_fileserver(struct afs_operation *op)
struct afs_addr_list *alist;
struct afs_server *server;
struct afs_vnode *vnode = op->file[0].vnode;
struct afs_error e;
unsigned int rtt;
int error = op->ac.error, i;
s32 abort_code = op->call_abort_code;
int error = op->call_error, i;
op->nr_iterations++;
@ -122,7 +122,7 @@ bool afs_select_fileserver(struct afs_operation *op)
op->debug_id, op->nr_iterations, op->volume->vid,
op->untried, op->index,
op->ac.tried, op->ac.index,
error, op->ac.abort_code);
error, abort_code);
if (op->flags & AFS_OPERATION_STOP) {
_leave(" = f [stopped]");
@ -133,8 +133,10 @@ bool afs_select_fileserver(struct afs_operation *op)
goto start;
/* Evaluate the result of the previous operation, if there was one. */
switch (error) {
switch (op->call_error) {
case 0:
op->cumul_error.responded = true;
fallthrough;
default:
/* Success or local failure. Stop. */
afs_op_set_error(op, error);
@ -151,7 +153,8 @@ bool afs_select_fileserver(struct afs_operation *op)
* errors instead. IBM AFS and OpenAFS fileservers, however, do leak
* these abort codes.
*/
switch (op->ac.abort_code) {
op->cumul_error.responded = true;
switch (abort_code) {
case VNOVOL:
/* This fileserver doesn't know about the volume.
* - May indicate that the VL is wrong - retry once and compare
@ -164,7 +167,7 @@ bool afs_select_fileserver(struct afs_operation *op)
* (administrative action).
*/
if (op->flags & AFS_OPERATION_VNOVOL) {
op->error = -EREMOTEIO;
afs_op_accumulate_error(op, -EREMOTEIO, abort_code);
goto next_server;
}
@ -188,7 +191,7 @@ bool afs_select_fileserver(struct afs_operation *op)
* it's the fileserver having trouble.
*/
if (rcu_access_pointer(op->volume->servers) == op->server_list) {
op->error = -EREMOTEIO;
afs_op_accumulate_error(op, -EREMOTEIO, abort_code);
goto next_server;
}
@ -201,8 +204,8 @@ bool afs_select_fileserver(struct afs_operation *op)
case VONLINE:
/* These should not be returned from the fileserver. */
pr_warn("Fileserver returned unexpected abort %d\n",
op->ac.abort_code);
op->error = -EREMOTEIO;
abort_code);
afs_op_accumulate_error(op, -EREMOTEIO, abort_code);
goto next_server;
case VNOSERVICE:
@ -233,7 +236,7 @@ bool afs_select_fileserver(struct afs_operation *op)
* VNOSERVICE should be treated as an alias for RX_CALL_TIMEOUT.
*/
case RX_CALL_TIMEOUT:
op->error = -ETIMEDOUT;
afs_op_accumulate_error(op, -ETIMEDOUT, abort_code);
goto next_server;
case VSALVAGING: /* This error should not be leaked to cache managers
@ -248,7 +251,7 @@ bool afs_select_fileserver(struct afs_operation *op)
* days).
*/
if (!test_and_set_bit(AFS_VOLUME_OFFLINE, &op->volume->flags)) {
afs_busy(op->volume, op->ac.abort_code);
afs_busy(op->volume, abort_code);
clear_bit(AFS_VOLUME_BUSY, &op->volume->flags);
}
if (op->flags & AFS_OPERATION_NO_VSLEEP) {
@ -281,7 +284,7 @@ bool afs_select_fileserver(struct afs_operation *op)
goto failed;
}
if (!test_and_set_bit(AFS_VOLUME_BUSY, &op->volume->flags)) {
afs_busy(op->volume, op->ac.abort_code);
afs_busy(op->volume, abort_code);
clear_bit(AFS_VOLUME_OFFLINE, &op->volume->flags);
}
busy:
@ -329,7 +332,7 @@ bool afs_select_fileserver(struct afs_operation *op)
* TODO: Retry a few times with sleeps.
*/
if (rcu_access_pointer(op->volume->servers) == op->server_list) {
op->error = -ENOMEDIUM;
afs_op_accumulate_error(op, -ENOMEDIUM, abort_code);
goto failed;
}
@ -337,7 +340,7 @@ bool afs_select_fileserver(struct afs_operation *op)
case UAEIO:
case VIO:
op->error = -EREMOTEIO;
afs_op_accumulate_error(op, -EREMOTEIO, abort_code);
if (op->volume->type != AFSVL_RWVOL)
goto next_server;
goto failed;
@ -361,7 +364,7 @@ bool afs_select_fileserver(struct afs_operation *op)
goto failed_but_online;
default:
op->error = afs_abort_to_error(op->ac.abort_code);
afs_op_accumulate_error(op, error, abort_code);
failed_but_online:
clear_bit(AFS_VOLUME_OFFLINE, &op->volume->flags);
clear_bit(AFS_VOLUME_BUSY, &op->volume->flags);
@ -380,7 +383,7 @@ bool afs_select_fileserver(struct afs_operation *op)
case -EHOSTDOWN:
case -ECONNREFUSED:
_debug("no conn");
op->error = error;
afs_op_accumulate_error(op, error, 0);
goto iterate_address;
case -ENETRESET:
@ -506,6 +509,7 @@ iterate_address:
op->index, op->ac.index, op->ac.alist->nr_addrs,
rxrpc_kernel_remote_addr(op->ac.alist->addrs[op->ac.index].peer));
op->call_responded = false;
_leave(" = t");
return true;
@ -543,17 +547,14 @@ no_more_servers:
if (op->flags & AFS_OPERATION_VBUSY)
goto restart_from_beginning;
e.error = -EDESTADDRREQ;
e.responded = false;
for (i = 0; i < op->server_list->nr_servers; i++) {
struct afs_server *s = op->server_list->servers[i].server;
afs_prioritise_error(&e, READ_ONCE(s->probe.error),
s->probe.abort_code);
error = READ_ONCE(s->probe.error);
if (error < 0)
afs_op_accumulate_error(op, error, s->probe.abort_code);
}
error = e.error;
op->error = error;
failed:
op->flags |= AFS_OPERATION_STOP;
afs_end_cursor(&op->ac);
@ -576,11 +577,13 @@ void afs_dump_edestaddrreq(const struct afs_operation *op)
rcu_read_lock();
pr_notice("EDESTADDR occurred\n");
pr_notice("FC: cbb=%x cbb2=%x fl=%x err=%hd\n",
pr_notice("OP: cbb=%x cbb2=%x fl=%x err=%hd\n",
op->file[0].cb_break_before,
op->file[1].cb_break_before, op->flags, op->error);
pr_notice("FC: ut=%lx ix=%d ni=%u\n",
op->file[1].cb_break_before, op->flags, op->cumul_error.error);
pr_notice("OP: ut=%lx ix=%d ni=%u\n",
op->untried, op->index, op->nr_iterations);
pr_notice("OP: call er=%d ac=%d r=%u\n",
op->call_error, op->call_abort_code, op->call_responded);
if (op->server_list) {
const struct afs_server_list *sl = op->server_list;
@ -605,8 +608,7 @@ void afs_dump_edestaddrreq(const struct afs_operation *op)
}
}
pr_notice("AC: t=%lx ax=%u ac=%d er=%d r=%u ni=%u\n",
op->ac.tried, op->ac.index, op->ac.abort_code, op->ac.error,
op->ac.responded, op->ac.nr_iterations);
pr_notice("AC: t=%lx ax=%u ni=%u\n",
op->ac.tried, op->ac.index, op->ac.nr_iterations);
rcu_read_unlock();
}

View File

@ -408,8 +408,7 @@ error_do_abort:
rxrpc_kernel_recv_data(call->net->socket, rxcall,
&msg.msg_iter, &len, false,
&call->abort_code, &call->service_id);
ac->abort_code = call->abort_code;
ac->responded = true;
call->responded = true;
}
call->error = ret;
trace_afs_call_done(call);
@ -429,7 +428,7 @@ error_kill_call:
afs_set_call_complete(call, ret, 0);
}
ac->error = ret;
call->error = ret;
call->state = AFS_CALL_COMPLETE;
_leave(" = %d", ret);
}
@ -510,6 +509,7 @@ static void afs_deliver_to_call(struct afs_call *call)
ret = -EBADMSG;
switch (ret) {
case 0:
call->responded = true;
afs_queue_call_work(call);
if (state == AFS_CALL_CL_PROC_REPLY) {
if (call->op)
@ -524,9 +524,11 @@ static void afs_deliver_to_call(struct afs_call *call)
goto out;
case -ECONNABORTED:
ASSERTCMP(state, ==, AFS_CALL_COMPLETE);
call->responded = true;
afs_log_error(call, call->abort_code);
goto done;
case -ENOTSUPP:
call->responded = true;
abort_code = RXGEN_OPCODE;
rxrpc_kernel_abort_call(call->net->socket, call->rxcall,
abort_code, ret,
@ -573,7 +575,7 @@ call_complete:
}
/*
* Wait synchronously for a call to complete and clean up the call struct.
* Wait synchronously for a call to complete.
*/
void afs_wait_for_call_to_complete(struct afs_call *call, struct afs_addr_cursor *ac)
{
@ -626,13 +628,8 @@ void afs_wait_for_call_to_complete(struct afs_call *call, struct afs_addr_cursor
}
}
spin_lock_bh(&call->state_lock);
ac->abort_code = call->abort_code;
ac->error = call->error;
spin_unlock_bh(&call->state_lock);
if (call->error == 0 || call->error == -ECONNABORTED)
ac->responded = true;
call->responded = true;
}
/*

View File

@ -437,7 +437,6 @@ static void afs_give_up_callbacks(struct afs_net *net, struct afs_server *server
struct afs_addr_cursor ac = {
.alist = alist,
.index = alist->preferred,
.error = 0,
};
afs_fs_give_up_all_callbacks(net, server, &ac, NULL);

View File

@ -236,7 +236,7 @@ static char *afs_vl_get_cell_name(struct afs_cell *cell, struct key *key)
while (afs_select_vlserver(&vc)) {
if (!test_bit(AFS_VLSERVER_FL_IS_YFS, &vc.server->flags)) {
vc.ac.error = -EOPNOTSUPP;
vc.call_error = -EOPNOTSUPP;
skipped = true;
continue;
}

View File

@ -169,10 +169,11 @@ static bool afs_do_probe_vlserver(struct afs_net *net,
call = afs_vl_get_capabilities(net, &ac, key, server,
server_index);
if (!IS_ERR(call)) {
afs_prioritise_error(_e, call->error, call->abort_code);
afs_put_call(call);
in_progress = true;
} else {
afs_prioritise_error(_e, PTR_ERR(call), ac.abort_code);
afs_prioritise_error(_e, PTR_ERR(call), 0);
afs_done_one_vl_probe(server, false);
}
}
@ -187,12 +188,10 @@ int afs_send_vl_probes(struct afs_net *net, struct key *key,
struct afs_vlserver_list *vllist)
{
struct afs_vlserver *server;
struct afs_error e;
struct afs_error e = {};
bool in_progress = false;
int i;
e.error = 0;
e.responded = false;
for (i = 0; i < vllist->nr_servers; i++) {
server = vllist->servers[i].server;
if (test_bit(AFS_VLSERVER_FL_PROBED, &server->flags))

View File

@ -20,11 +20,11 @@ bool afs_begin_vlserver_operation(struct afs_vl_cursor *vc, struct afs_cell *cel
memset(vc, 0, sizeof(*vc));
vc->cell = cell;
vc->key = key;
vc->error = -EDESTADDRREQ;
vc->ac.error = SHRT_MAX;
vc->cumul_error.error = -EDESTADDRREQ;
vc->nr_iterations = -1;
if (signal_pending(current)) {
vc->error = -EINTR;
vc->cumul_error.error = -EINTR;
vc->flags |= AFS_VL_CURSOR_STOP;
return false;
}
@ -52,7 +52,7 @@ static bool afs_start_vl_iteration(struct afs_vl_cursor *vc)
&cell->dns_lookup_count,
smp_load_acquire(&cell->dns_lookup_count)
!= dns_lookup_count) < 0) {
vc->error = -ERESTARTSYS;
vc->cumul_error.error = -ERESTARTSYS;
return false;
}
}
@ -60,12 +60,12 @@ static bool afs_start_vl_iteration(struct afs_vl_cursor *vc)
/* 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->error = -ENOENT;
vc->cumul_error.error = -ENOENT;
return false;
}
if (cell->dns_source == DNS_RECORD_UNAVAILABLE) {
vc->error = -EDESTADDRREQ;
vc->cumul_error.error = -EDESTADDRREQ;
return false;
}
}
@ -91,52 +91,52 @@ bool afs_select_vlserver(struct afs_vl_cursor *vc)
{
struct afs_addr_list *alist;
struct afs_vlserver *vlserver;
struct afs_error e;
unsigned int rtt;
int error = vc->ac.error, i;
s32 abort_code = vc->call_abort_code;
int error = vc->call_error, i;
vc->nr_iterations++;
_enter("%lx[%d],%lx[%d],%d,%d",
vc->untried, vc->index,
vc->ac.tried, vc->ac.index,
error, vc->ac.abort_code);
error, abort_code);
if (vc->flags & AFS_VL_CURSOR_STOP) {
_leave(" = f [stopped]");
return false;
}
vc->nr_iterations++;
if (vc->nr_iterations == 0)
goto start;
/* Evaluate the result of the previous operation, if there was one. */
switch (error) {
case SHRT_MAX:
goto start;
default:
case 0:
/* Success or local failure. Stop. */
vc->error = error;
vc->cumul_error.error = error;
vc->flags |= AFS_VL_CURSOR_STOP;
_leave(" = f [okay/local %d]", vc->ac.error);
_leave(" = f [okay/local %d]", vc->cumul_error.error);
return false;
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 (vc->ac.abort_code) {
switch (abort_code) {
case AFSVL_IO:
case AFSVL_BADVOLOPER:
case AFSVL_NOMEM:
/* The server went weird. */
vc->error = -EREMOTEIO;
afs_prioritise_error(&vc->cumul_error, -EREMOTEIO, abort_code);
//write_lock(&vc->cell->vl_servers_lock);
//vc->server_list->weird_mask |= 1 << vc->index;
//write_unlock(&vc->cell->vl_servers_lock);
goto next_server;
default:
vc->error = afs_abort_to_error(vc->ac.abort_code);
afs_prioritise_error(&vc->cumul_error, error, abort_code);
goto failed;
}
@ -149,12 +149,12 @@ bool afs_select_vlserver(struct afs_vl_cursor *vc)
case -ETIMEDOUT:
case -ETIME:
_debug("no conn %d", error);
vc->error = error;
afs_prioritise_error(&vc->cumul_error, error, 0);
goto iterate_address;
case -ECONNRESET:
_debug("call reset");
vc->error = error;
afs_prioritise_error(&vc->cumul_error, error, 0);
vc->flags |= AFS_VL_CURSOR_RETRY;
goto next_server;
@ -178,15 +178,19 @@ start:
goto failed;
error = afs_send_vl_probes(vc->cell->net, vc->key, vc->server_list);
if (error < 0)
goto failed_set_error;
if (error < 0) {
afs_prioritise_error(&vc->cumul_error, error, 0);
goto failed;
}
pick_server:
_debug("pick [%lx]", vc->untried);
error = afs_wait_for_vl_probes(vc->server_list, vc->untried);
if (error < 0)
goto failed_set_error;
if (error < 0) {
afs_prioritise_error(&vc->cumul_error, error, 0);
goto failed;
}
/* Pick the untried server with the lowest RTT. */
vc->index = vc->server_list->preferred;
@ -249,6 +253,7 @@ iterate_address:
_debug("VL address %d/%d", vc->ac.index, vc->ac.alist->nr_addrs);
vc->call_responded = false;
_leave(" = t %pISpc", rxrpc_kernel_remote_addr(vc->ac.alist->addrs[vc->ac.index].peer));
return true;
@ -264,25 +269,19 @@ no_more_servers:
if (vc->flags & AFS_VL_CURSOR_RETRY)
goto restart_from_beginning;
e.error = -EDESTADDRREQ;
e.responded = false;
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))
e.responded = true;
afs_prioritise_error(&e, READ_ONCE(s->probe.error),
vc->cumul_error.responded = true;
afs_prioritise_error(&vc->cumul_error, READ_ONCE(s->probe.error),
s->probe.abort_code);
}
error = e.error;
failed_set_error:
vc->error = error;
failed:
vc->flags |= AFS_VL_CURSOR_STOP;
afs_end_cursor(&vc->ac);
_leave(" = f [failed %d]", vc->error);
_leave(" = f [failed %d]", vc->cumul_error.error);
return false;
}
@ -305,7 +304,10 @@ static void afs_vl_dump_edestaddrreq(const struct afs_vl_cursor *vc)
pr_notice("DNS: src=%u st=%u lc=%x\n",
cell->dns_source, cell->dns_status, cell->dns_lookup_count);
pr_notice("VC: ut=%lx ix=%u ni=%hu fl=%hx err=%hd\n",
vc->untried, vc->index, vc->nr_iterations, vc->flags, vc->error);
vc->untried, vc->index, vc->nr_iterations, vc->flags,
vc->cumul_error.error);
pr_notice("VC: call er=%d ac=%d r=%u\n",
vc->call_error, vc->call_abort_code, vc->call_responded);
if (vc->server_list) {
const struct afs_vlserver_list *sl = vc->server_list;
@ -329,9 +331,8 @@ static void afs_vl_dump_edestaddrreq(const struct afs_vl_cursor *vc)
}
}
pr_notice("AC: t=%lx ax=%u ac=%d er=%d r=%u ni=%u\n",
vc->ac.tried, vc->ac.index, vc->ac.abort_code, vc->ac.error,
vc->ac.responded, vc->ac.nr_iterations);
pr_notice("AC: t=%lx ax=%u ni=%u\n",
vc->ac.tried, vc->ac.index, vc->ac.nr_iterations);
rcu_read_unlock();
}
@ -342,17 +343,16 @@ int afs_end_vlserver_operation(struct afs_vl_cursor *vc)
{
struct afs_net *net = vc->cell->net;
if (vc->error == -EDESTADDRREQ ||
vc->error == -EADDRNOTAVAIL ||
vc->error == -ENETUNREACH ||
vc->error == -EHOSTUNREACH)
switch (vc->cumul_error.error) {
case -EDESTADDRREQ:
case -EADDRNOTAVAIL:
case -ENETUNREACH:
case -EHOSTUNREACH:
afs_vl_dump_edestaddrreq(vc);
break;
}
afs_end_cursor(&vc->ac);
afs_put_vlserverlist(net, vc->server_list);
if (vc->error == -ECONNABORTED)
vc->error = afs_abort_to_error(vc->ac.abort_code);
return vc->error;
return vc->cumul_error.error;
}

View File

@ -161,10 +161,13 @@ struct afs_vldb_entry *afs_vl_get_entry_by_name_u(struct afs_vl_cursor *vc,
trace_afs_make_vl_call(call);
afs_make_call(&vc->ac, call, GFP_KERNEL);
afs_wait_for_call_to_complete(call, &vc->ac);
vc->call_abort_code = call->abort_code;
vc->call_error = call->error;
vc->call_responded = call->responded;
afs_put_call(call);
if (vc->ac.error) {
if (vc->call_error) {
kfree(entry);
return ERR_PTR(vc->ac.error);
return ERR_PTR(vc->call_error);
}
return entry;
}
@ -305,11 +308,14 @@ struct afs_addr_list *afs_vl_get_addrs_u(struct afs_vl_cursor *vc,
trace_afs_make_vl_call(call);
afs_make_call(&vc->ac, call, GFP_KERNEL);
afs_wait_for_call_to_complete(call, &vc->ac);
alist = call->ret_alist;
vc->call_abort_code = call->abort_code;
vc->call_error = call->error;
vc->call_responded = call->responded;
alist = call->ret_alist;
afs_put_call(call);
if (vc->ac.error) {
if (vc->call_error) {
afs_put_addrlist(alist);
return ERR_PTR(vc->ac.error);
return ERR_PTR(vc->call_error);
}
return alist;
}
@ -656,11 +662,14 @@ struct afs_addr_list *afs_yfsvl_get_endpoints(struct afs_vl_cursor *vc,
trace_afs_make_vl_call(call);
afs_make_call(&vc->ac, call, GFP_KERNEL);
afs_wait_for_call_to_complete(call, &vc->ac);
alist = call->ret_alist;
vc->call_abort_code = call->abort_code;
vc->call_error = call->error;
vc->call_responded = call->responded;
alist = call->ret_alist;
afs_put_call(call);
if (vc->ac.error) {
if (vc->call_error) {
afs_put_addrlist(alist);
return ERR_PTR(vc->ac.error);
return ERR_PTR(vc->call_error);
}
return alist;
}
@ -769,11 +778,14 @@ char *afs_yfsvl_get_cell_name(struct afs_vl_cursor *vc)
trace_afs_make_vl_call(call);
afs_make_call(&vc->ac, call, GFP_KERNEL);
afs_wait_for_call_to_complete(call, &vc->ac);
cellname = call->ret_str;
vc->call_abort_code = call->abort_code;
vc->call_error = call->error;
vc->call_responded = call->responded;
cellname = call->ret_str;
afs_put_call(call);
if (vc->ac.error) {
if (vc->call_error) {
kfree(cellname);
return ERR_PTR(vc->ac.error);
return ERR_PTR(vc->call_error);
}
return cellname;
}