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 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 @@ iterate_address: 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 @@ failed: 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);