[PATCH 22/25] afs: Allow dumping of server cursor on operation failure [ver #2]

From: David Howells
Date: Tue Oct 23 2018 - 23:38:36 EST


Provide an option to allow the file or volume location server cursor to be
dumped if the rotation routine falls off the end without managing to
contact a server.

Signed-off-by: David Howells <dhowells@xxxxxxxxxx>
---

fs/afs/Kconfig | 12 +++++++++++
fs/afs/addr_list.c | 2 ++
fs/afs/internal.h | 3 +++
fs/afs/rotate.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++
fs/afs/vl_rotate.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 127 insertions(+)

diff --git a/fs/afs/Kconfig b/fs/afs/Kconfig
index ebba3b18e5da..701aaa9b1899 100644
--- a/fs/afs/Kconfig
+++ b/fs/afs/Kconfig
@@ -27,3 +27,15 @@ config AFS_FSCACHE
help
Say Y here if you want AFS data to be cached locally on disk through
the generic filesystem cache manager
+
+config AFS_DEBUG_CURSOR
+ bool "AFS server cursor debugging"
+ depends on AFS_FS
+ help
+ Say Y here to cause the contents of a server cursor to be dumped to
+ the dmesg log if the server rotation algorithm fails to successfully
+ contact a server.
+
+ See <file:Documentation/filesystems/afs.txt> for more information.
+
+ If unsure, say N.
diff --git a/fs/afs/addr_list.c b/fs/afs/addr_list.c
index 3f60b4012587..bc5ce31a4ae4 100644
--- a/fs/afs/addr_list.c
+++ b/fs/afs/addr_list.c
@@ -358,6 +358,8 @@ bool afs_iterate_addresses(struct afs_addr_cursor *ac)
if (!ac->alist)
return false;

+ ac->nr_iterations++;
+
if (ac->begun) {
ac->index++;
if (ac->index == ac->alist->nr_addrs)
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index ce79bd514331..ac9da1e4050e 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -660,6 +660,7 @@ struct afs_addr_cursor {
short error;
bool begun; /* T if we've begun iteration */
bool responded; /* T if the current address responded */
+ unsigned short nr_iterations; /* Number of address iterations */
};

/*
@@ -677,6 +678,7 @@ struct afs_vl_cursor {
#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 */
};

/*
@@ -700,6 +702,7 @@ struct afs_fs_cursor {
#define AFS_FS_CURSOR_VNOVOL 0x0008 /* Set if seen VNOVOL */
#define AFS_FS_CURSOR_CUR_ONLY 0x0010 /* Set if current server only (file lock held) */
#define AFS_FS_CURSOR_NO_VSLEEP 0x0020 /* Set to prevent sleep on VBUSY, VOFFLINE, ... */
+ unsigned short nr_iterations; /* Number of server iterations */
};

/*
diff --git a/fs/afs/rotate.c b/fs/afs/rotate.c
index 41405dde0113..7c4487781637 100644
--- a/fs/afs/rotate.c
+++ b/fs/afs/rotate.c
@@ -156,6 +156,8 @@ bool afs_select_fileserver(struct afs_fs_cursor *fc)
return false;
}

+ fc->nr_iterations++;
+
/* Evaluate the result of the previous operation, if there was one. */
switch (error) {
case SHRT_MAX:
@@ -519,6 +521,56 @@ bool afs_select_current_fileserver(struct afs_fs_cursor *fc)
return false;
}

+/*
+ * Dump cursor state in the case of the error being EDESTADDRREQ.
+ */
+static void afs_dump_edestaddrreq(const struct afs_fs_cursor *fc)
+{
+ static int count;
+ int i;
+
+ if (!IS_ENABLED(CONFIG_AFS_DEBUG_CURSOR) || count > 3)
+ return;
+ count++;
+
+ rcu_read_lock();
+
+ pr_notice("EDESTADDR occurred\n");
+ pr_notice("FC: cbb=%x cbb2=%x fl=%hx err=%hd\n",
+ fc->cb_break, fc->cb_break_2, fc->flags, fc->error);
+ pr_notice("FC: st=%u ix=%u ni=%u\n",
+ fc->start, fc->index, fc->nr_iterations);
+
+ if (fc->server_list) {
+ const struct afs_server_list *sl = fc->server_list;
+ pr_notice("FC: SL nr=%u ix=%u vnov=%hx\n",
+ sl->nr_servers, sl->index, sl->vnovol_mask);
+ for (i = 0; i < sl->nr_servers; i++) {
+ const struct afs_server *s = sl->servers[i].server;
+ pr_notice("FC: server fl=%lx av=%u %pU\n",
+ s->flags, s->addr_version, &s->uuid);
+ if (s->addresses) {
+ const struct afs_addr_list *a =
+ rcu_dereference(s->addresses);
+ pr_notice("FC: - av=%u nr=%u/%u/%u ax=%u\n",
+ a->version,
+ a->nr_ipv4, a->nr_addrs, a->max_addrs,
+ a->index);
+ pr_notice("FC: - pr=%lx yf=%lx\n",
+ a->probed, a->yfs);
+ if (a == fc->ac.alist)
+ pr_notice("FC: - current\n");
+ }
+ }
+ }
+
+ pr_notice("AC: as=%u ax=%u ac=%d er=%d b=%u r=%u ni=%u\n",
+ fc->ac.start, fc->ac.index, fc->ac.abort_code, fc->ac.error,
+ fc->ac.begun, fc->ac.responded, fc->ac.nr_iterations);
+
+ rcu_read_unlock();
+}
+
/*
* Tidy up a filesystem cursor and unlock the vnode.
*/
@@ -526,6 +578,11 @@ int afs_end_vnode_operation(struct afs_fs_cursor *fc)
{
struct afs_net *net = afs_v2net(fc->vnode);

+ if (fc->error == -EDESTADDRREQ ||
+ fc->error == -ENETUNREACH ||
+ fc->error == -EHOSTUNREACH)
+ afs_dump_edestaddrreq(fc);
+
mutex_unlock(&fc->vnode->io_lock);

afs_end_cursor(&fc->ac);
diff --git a/fs/afs/vl_rotate.c b/fs/afs/vl_rotate.c
index 44a936ad9c7a..5b99ea7be194 100644
--- a/fs/afs/vl_rotate.c
+++ b/fs/afs/vl_rotate.c
@@ -83,6 +83,8 @@ bool afs_select_vlserver(struct afs_vl_cursor *vc)
return false;
}

+ vc->nr_iterations++;
+
/* Evaluate the result of the previous operation, if there was one. */
switch (error) {
case SHRT_MAX:
@@ -234,6 +236,52 @@ bool afs_select_vlserver(struct afs_vl_cursor *vc)
return false;
}

+/*
+ * Dump cursor state in the case of the error being EDESTADDRREQ.
+ */
+static void afs_vl_dump_edestaddrreq(const struct afs_vl_cursor *vc)
+{
+ static int count;
+ int i;
+
+ if (!IS_ENABLED(CONFIG_AFS_DEBUG_CURSOR) || count > 3)
+ return;
+ count++;
+
+ rcu_read_lock();
+ pr_notice("EDESTADDR occurred\n");
+ pr_notice("VC: st=%u ix=%u ni=%hu fl=%hx err=%hd\n",
+ vc->start, vc->index, vc->nr_iterations, vc->flags, vc->error);
+
+ if (vc->server_list) {
+ const struct afs_vlserver_list *sl = vc->server_list;
+ pr_notice("VC: SL nr=%u ix=%u\n",
+ sl->nr_servers, sl->index);
+ for (i = 0; i < sl->nr_servers; i++) {
+ const struct afs_vlserver *s = sl->servers[i].server;
+ pr_notice("VC: server fl=%lx %s+%hu\n",
+ s->flags, s->name, s->port);
+ if (s->addresses) {
+ const struct afs_addr_list *a =
+ rcu_dereference(s->addresses);
+ pr_notice("VC: - av=%u nr=%u/%u/%u ax=%u\n",
+ a->version,
+ a->nr_ipv4, a->nr_addrs, a->max_addrs,
+ a->index);
+ pr_notice("VC: - pr=%lx yf=%lx\n",
+ a->probed, a->yfs);
+ if (a == vc->ac.alist)
+ pr_notice("VC: - current\n");
+ }
+ }
+ }
+
+ pr_notice("AC: as=%u ax=%u ac=%d er=%d b=%u r=%u ni=%hu\n",
+ vc->ac.start, vc->ac.index, vc->ac.abort_code, vc->ac.error,
+ vc->ac.begun, vc->ac.responded, vc->ac.nr_iterations);
+ rcu_read_unlock();
+}
+
/*
* Tidy up a volume location server cursor and unlock the vnode.
*/
@@ -241,6 +289,11 @@ int afs_end_vlserver_operation(struct afs_vl_cursor *vc)
{
struct afs_net *net = vc->cell->net;

+ if (vc->error == -EDESTADDRREQ ||
+ vc->error == -ENETUNREACH ||
+ vc->error == -EHOSTUNREACH)
+ afs_vl_dump_edestaddrreq(vc);
+
afs_end_cursor(&vc->ac);
afs_put_vlserverlist(net, vc->server_list);