summaryrefslogtreecommitdiffstats
path: root/fs/afs/fs_probe.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2020-04-22 00:02:46 +0100
committerDavid Howells <dhowells@redhat.com>2020-06-04 15:37:58 +0100
commit8409f67b6437c4b327ee95a71081b9c7bfee0b00 (patch)
tree79e150c5ad3a0f22f03cebc6dd25fdd9d0473f4f /fs/afs/fs_probe.c
parent32275d3f758f1252511709b77b3bab060a0e1d4f (diff)
downloadlinux-8409f67b6437c4b327ee95a71081b9c7bfee0b00.tar.gz
linux-8409f67b6437c4b327ee95a71081b9c7bfee0b00.tar.bz2
linux-8409f67b6437c4b327ee95a71081b9c7bfee0b00.zip
afs: Adjust the fileserver rotation algorithm to reprobe/retry more quickly
Adjust the fileserver rotation algorithm so that if we've tried all the addresses on a server (cumulatively over multiple operations) until we've run out of untried addresses, immediately reprobe all that server's interfaces and retry the op at least once before we move onto the next server. Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'fs/afs/fs_probe.c')
-rw-r--r--fs/afs/fs_probe.c47
1 files changed, 47 insertions, 0 deletions
diff --git a/fs/afs/fs_probe.c b/fs/afs/fs_probe.c
index c41cf3b2ab89..b34f74b0f319 100644
--- a/fs/afs/fs_probe.c
+++ b/fs/afs/fs_probe.c
@@ -339,6 +339,18 @@ static void afs_dispatch_fs_probe(struct afs_net *net, struct afs_server *server
}
/*
+ * 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, true);
+ write_sequnlock(&net->fs_lock);
+}
+
+/*
* Probe dispatcher to regularly dispatch probes to keep NAT alive.
*/
void afs_fs_probe_dispatcher(struct work_struct *work)
@@ -411,3 +423,38 @@ again:
_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, bool is_intr)
+{
+ struct wait_queue_entry wait;
+ unsigned long timo = 2 * HZ;
+
+ if (atomic_read(&server->probe_outstanding) == 0)
+ goto dont_wait;
+
+ init_wait_entry(&wait, 0);
+ for (;;) {
+ prepare_to_wait_event(&server->probe_wq, &wait,
+ is_intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
+ if (timo == 0 ||
+ server->probe.responded ||
+ atomic_read(&server->probe_outstanding) == 0 ||
+ (is_intr && signal_pending(current)))
+ break;
+ timo = schedule_timeout(timo);
+ }
+
+ finish_wait(&server->probe_wq, &wait);
+
+dont_wait:
+ if (server->probe.responded)
+ return 0;
+ if (is_intr && signal_pending(current))
+ return -ERESTARTSYS;
+ if (timo == 0)
+ return -ETIME;
+ return -EDESTADDRREQ;
+}