[PATCH] afs: Fix afs_listxattr() to not list YFS xattrs if a non-YFS server is seen

David Howells dhowells at redhat.com
Mon Mar 8 21:55:19 GMT 2021


afs_listxattr() always lists all the available special afs xattrs
(i.e. those in the "afs.*" space), no matter what sort of server we're
dealing with.  But OpenAFS servers, for example, cannot deal with some of
the extra-capable attributes that AuriStor (YFS) servers provide.

Unfortunately, the presence of the afs.yfs.* attributes causes errors for
anything that tries to read them if the server is of the wrong type.

Note that in the case of a mixed environment, where a cell may have a
volume that is replicated across a set of servers that includes both
OpenAFS and AuriStor servers, such a volume offers only the capabilities
available on the OpenAFS servers (so, for example, more capable YFS ACLs
aren't available in that volume).

Fix afs_listxattr() to only list the afs.yfs.* xattrs if we don't detect
any OpenAFS servers in the mix for that volume.

To this end, the type of a server is consolidated into its own field in the
afs_server structure and this is set during probing instead of setting a
"this is YFS flag".  afs_listxattr() can then scan the server list and
determine what xattrs to present.

As an addition, the server type is displayed in /proc/fs/afs/servers for
YFS servers to make it easier to check.

Fixes: ae46578b963f ("afs: Get YFS ACLs and information through xattrs")
Reported-by: Gaja Sophie Peters <gaja.peters at math.uni-hamburg.de>
Signed-off-by: David Howells <dhowells at redhat.com>
Link: http://lists.infradead.org/pipermail/linux-afs/2021-March/003508.html
---
 fs/afs/fs_operation.c |    5 +++--
 fs/afs/fs_probe.c     |    4 ++--
 fs/afs/internal.h     |    8 +++++++-
 fs/afs/proc.c         |    5 +++--
 fs/afs/xattr.c        |   39 +++++++++++++++++++++++++++++++++++----
 5 files changed, 50 insertions(+), 11 deletions(-)

diff --git a/fs/afs/fs_operation.c b/fs/afs/fs_operation.c
index 71c58723763d..4026e0ad3ad7 100644
--- a/fs/afs/fs_operation.c
+++ b/fs/afs/fs_operation.c
@@ -178,10 +178,11 @@ void afs_wait_for_operation(struct afs_operation *op)
 
 	while (afs_select_fileserver(op)) {
 		op->cb_s_break = op->server->cb_s_break;
-		if (test_bit(AFS_SERVER_FL_IS_YFS, &op->server->flags) &&
+		if (op->server->type == AFS_SERVER_TYPE_YFS &&
 		    op->ops->issue_yfs_rpc)
 			op->ops->issue_yfs_rpc(op);
-		else if (op->ops->issue_afs_rpc)
+		else if (op->server->type == AFS_SERVER_TYPE_AFS &&
+			 op->ops->issue_afs_rpc)
 			op->ops->issue_afs_rpc(op);
 		else
 			op->ac.error = -ENOTSUPP;
diff --git a/fs/afs/fs_probe.c b/fs/afs/fs_probe.c
index e7e98ad63a91..fda449866267 100644
--- a/fs/afs/fs_probe.c
+++ b/fs/afs/fs_probe.c
@@ -151,12 +151,12 @@ void afs_fileserver_probe_result(struct afs_call *call)
 
 	if (call->service_id == YFS_FS_SERVICE) {
 		server->probe.is_yfs = true;
-		set_bit(AFS_SERVER_FL_IS_YFS, &server->flags);
+		server->type = AFS_SERVER_TYPE_YFS;
 		alist->addrs[index].srx_service = call->service_id;
 	} else {
 		server->probe.not_yfs = true;
 		if (!server->probe.is_yfs) {
-			clear_bit(AFS_SERVER_FL_IS_YFS, &server->flags);
+			server->type = AFS_SERVER_TYPE_AFS;
 			alist->addrs[index].srx_service = call->service_id;
 		}
 	}
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index b626e38e9ab5..7a8b178c3e3b 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -479,6 +479,12 @@ struct afs_vldb_entry {
 	u8			name[AFS_MAXVOLNAME + 1]; /* NUL-padded volume name */
 };
 
+enum afs_server_type {
+	AFS_SERVER_TYPE_UNKNOWN,
+	AFS_SERVER_TYPE_AFS,		/* Server is known to be AFS3, eg. OpenAFS */
+	AFS_SERVER_TYPE_YFS,		/* Server is known to be YFS, eg. AuriStor */
+};
+
 /*
  * Record of fileserver with which we're actively communicating.
  */
@@ -508,7 +514,6 @@ struct afs_server {
 #define AFS_SERVER_FL_NOT_FOUND	5		/* VL server says no such server */
 #define AFS_SERVER_FL_VL_FAIL	6		/* Failed to access VL server */
 #define AFS_SERVER_FL_MAY_HAVE_CB 8		/* May have callbacks on this fileserver */
-#define AFS_SERVER_FL_IS_YFS	16		/* Server is YFS not AFS */
 #define AFS_SERVER_FL_NO_IBULK	17		/* Fileserver doesn't support FS.InlineBulkStatus */
 #define AFS_SERVER_FL_NO_RM2	18		/* Fileserver doesn't support YFS.RemoveFile2 */
 	atomic_t		ref;		/* Object refcount */
@@ -516,6 +521,7 @@ struct afs_server {
 	u32			addr_version;	/* Address list version */
 	unsigned int		rtt;		/* Server's current RTT in uS */
 	unsigned int		debug_id;	/* Debugging ID for traces */
+	enum afs_server_type	type;		/* Type of server */
 
 	/* file service access */
 	rwlock_t		fs_lock;	/* access lock */
diff --git a/fs/afs/proc.c b/fs/afs/proc.c
index 065a28bfa3f1..349283da3180 100644
--- a/fs/afs/proc.c
+++ b/fs/afs/proc.c
@@ -390,8 +390,9 @@ static int afs_proc_servers_show(struct seq_file *m, void *v)
 		   &server->uuid,
 		   atomic_read(&server->ref),
 		   atomic_read(&server->active));
-	seq_printf(m, "  - info: fl=%lx rtt=%u brk=%x\n",
-		   server->flags, server->rtt, server->cb_s_break);
+	seq_printf(m, "  - info: fl=%lx rtt=%u brk=%x%s\n",
+		   server->flags, server->rtt, server->cb_s_break,
+		   server->type == AFS_SERVER_TYPE_YFS ? " yfs" : "");
 	seq_printf(m, "  - probe: last=%d out=%d\n",
 		   (int)(jiffies - server->probed_at) / HZ,
 		   atomic_read(&server->probe_outstanding));
diff --git a/fs/afs/xattr.c b/fs/afs/xattr.c
index 4934e325a14a..7531b2b3d141 100644
--- a/fs/afs/xattr.c
+++ b/fs/afs/xattr.c
@@ -12,6 +12,12 @@
 #include "internal.h"
 
 static const char afs_xattr_list[] =
+	"afs.acl\0"
+	"afs.cell\0"
+	"afs.fid\0"
+	"afs.volume";
+
+static const char yfs_xattr_list[] =
 	"afs.acl\0"
 	"afs.cell\0"
 	"afs.fid\0"
@@ -26,12 +32,37 @@ static const char afs_xattr_list[] =
  */
 ssize_t afs_listxattr(struct dentry *dentry, char *buffer, size_t size)
 {
+	const struct afs_server_list *servers;
+	struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry));
+	const char *list;
+	size_t list_size;
+	bool afs_only = false;
+	int i;
+
+	rcu_read_lock();
+	servers = rcu_dereference(vnode->volume->servers);
+	for (i = 0; i < servers->nr_servers; i++) {
+		if (servers->servers[i].server->type != AFS_SERVER_TYPE_YFS) {
+			afs_only = true;
+			break;
+		}
+	}
+	rcu_read_unlock();
+
+	if (afs_only) {
+		list = afs_xattr_list;
+		list_size = sizeof(afs_xattr_list);
+	} else {
+		list = yfs_xattr_list;
+		list_size = sizeof(yfs_xattr_list);
+	}
+
 	if (size == 0)
-		return sizeof(afs_xattr_list);
-	if (size < sizeof(afs_xattr_list))
+		return list_size;
+	if (size < list_size)
 		return -ERANGE;
-	memcpy(buffer, afs_xattr_list, sizeof(afs_xattr_list));
-	return sizeof(afs_xattr_list);
+	memcpy(buffer, list, list_size);
+	return list_size;
 }
 
 /*




More information about the linux-afs mailing list