afs: Probe multiple fileservers simultaneously

Send probes to all the unprobed fileservers in a fileserver list on all
addresses simultaneously in an attempt to find out the fastest route whilst
not getting stuck for 20s on any server or address that we don't get a
reply from.

This alleviates the problem whereby attempting to access a new server can
take a long time because the rotation algorithm ends up rotating through
all servers and addresses until it finds one that responds.

Signed-off-by: David Howells <dhowells@redhat.com>
This commit is contained in:
David Howells
2018-10-20 00:57:59 +01:00
parent 18ac61853c
commit 3bf0fb6f33
17 changed files with 1050 additions and 350 deletions

View File

@@ -43,7 +43,6 @@ int afs_open_socket(struct afs_net *net)
struct sockaddr_rxrpc srx;
struct socket *socket;
unsigned int min_level;
u16 service_upgrade[2];
int ret;
_enter("");
@@ -82,13 +81,12 @@ int afs_open_socket(struct afs_net *net)
if (ret < 0)
goto error_2;
service_upgrade[0] = CM_SERVICE;
service_upgrade[1] = YFS_CM_SERVICE;
ret = kernel_setsockopt(socket, SOL_RXRPC, RXRPC_UPGRADEABLE_SERVICE,
(void *)service_upgrade, sizeof(service_upgrade));
if (ret < 0)
goto error_2;
/* Ideally, we'd turn on service upgrade here, but we can't because
* OpenAFS is buggy and leaks the userStatus field from packet to
* packet and between FS packets and CB packets - so if we try to do an
* upgrade on an FS packet, OpenAFS will leak that into the CB packet
* it sends back to us.
*/
rxrpc_kernel_new_call_notification(socket, afs_rx_new_call,
afs_rx_discard_new_call);
@@ -192,6 +190,7 @@ void afs_put_call(struct afs_call *call)
afs_put_server(call->net, call->cm_server);
afs_put_cb_interest(call->net, call->cbi);
afs_put_addrlist(call->alist);
kfree(call->request);
trace_afs_call(call, afs_call_trace_free, 0, o,
@@ -205,21 +204,22 @@ void afs_put_call(struct afs_call *call)
}
/*
* Queue the call for actual work. Returns 0 unconditionally for convenience.
* Queue the call for actual work.
*/
int afs_queue_call_work(struct afs_call *call)
static void afs_queue_call_work(struct afs_call *call)
{
int u = atomic_inc_return(&call->usage);
if (call->type->work) {
int u = atomic_inc_return(&call->usage);
trace_afs_call(call, afs_call_trace_work, u,
atomic_read(&call->net->nr_outstanding_calls),
__builtin_return_address(0));
trace_afs_call(call, afs_call_trace_work, u,
atomic_read(&call->net->nr_outstanding_calls),
__builtin_return_address(0));
INIT_WORK(&call->work, call->type->work);
INIT_WORK(&call->work, call->type->work);
if (!queue_work(afs_wq, &call->work))
afs_put_call(call);
return 0;
if (!queue_work(afs_wq, &call->work))
afs_put_call(call);
}
}
/*
@@ -376,6 +376,8 @@ long afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call,
atomic_read(&call->net->nr_outstanding_calls));
call->async = async;
call->addr_ix = ac->index;
call->alist = afs_get_addrlist(ac->alist);
/* Work out the length we're going to transmit. This is awkward for
* calls such as FS.StoreData where there's an extra injection of data
@@ -407,6 +409,7 @@ long afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call,
call->debug_id);
if (IS_ERR(rxcall)) {
ret = PTR_ERR(rxcall);
call->error = ret;
goto error_kill_call;
}
@@ -458,6 +461,8 @@ error_do_abort:
call->error = ret;
trace_afs_call_done(call);
error_kill_call:
if (call->type->done)
call->type->done(call);
afs_put_call(call);
ac->error = ret;
_leave(" = %d", ret);
@@ -509,6 +514,7 @@ static void afs_deliver_to_call(struct afs_call *call)
state = READ_ONCE(call->state);
switch (ret) {
case 0:
afs_queue_call_work(call);
if (state == AFS_CALL_CL_PROC_REPLY) {
if (call->cbi)
set_bit(AFS_SERVER_FL_MAY_HAVE_CB,
@@ -546,6 +552,8 @@ static void afs_deliver_to_call(struct afs_call *call)
}
done:
if (call->type->done)
call->type->done(call);
if (state == AFS_CALL_COMPLETE && call->incoming)
afs_put_call(call);
out: