[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