Commit 012a211a authored by Frank van der Linden's avatar Frank van der Linden Committed by Trond Myklebust
Browse files

NFSv4.2: hook in the user extended attribute handlers



Now that all the lower level code is there to make the RPC calls, hook
it in to the xattr handlers and the listxattr entry point, to make them
available.

Signed-off-by: default avatarFrank van der Linden <fllinden@amazon.com>
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
parent c10a7514
Loading
Loading
Loading
Loading
+121 −2
Original line number Diff line number Diff line
@@ -66,6 +66,7 @@
#include "nfs4idmap.h"
#include "nfs4session.h"
#include "fscache.h"
#include "nfs42.h"

#include "nfs4trace.h"

@@ -7440,6 +7441,103 @@ nfs4_listxattr_nfs4_label(struct inode *inode, char *list, size_t list_len)

#endif

#ifdef CONFIG_NFS_V4_2
static int nfs4_xattr_set_nfs4_user(const struct xattr_handler *handler,
				    struct dentry *unused, struct inode *inode,
				    const char *key, const void *buf,
				    size_t buflen, int flags)
{
	struct nfs_access_entry cache;

	if (!nfs_server_capable(inode, NFS_CAP_XATTR))
		return -EOPNOTSUPP;

	/*
	 * There is no mapping from the MAY_* flags to the NFS_ACCESS_XA*
	 * flags right now. Handling of xattr operations use the normal
	 * file read/write permissions.
	 *
	 * Just in case the server has other ideas (which RFC 8276 allows),
	 * do a cached access check for the XA* flags to possibly avoid
	 * doing an RPC and getting EACCES back.
	 */
	if (!nfs_access_get_cached(inode, current_cred(), &cache, true)) {
		if (!(cache.mask & NFS_ACCESS_XAWRITE))
			return -EACCES;
	}

	if (buf == NULL)
		return nfs42_proc_removexattr(inode, key);
	else
		return nfs42_proc_setxattr(inode, key, buf, buflen, flags);
}

static int nfs4_xattr_get_nfs4_user(const struct xattr_handler *handler,
				    struct dentry *unused, struct inode *inode,
				    const char *key, void *buf, size_t buflen)
{
	struct nfs_access_entry cache;

	if (!nfs_server_capable(inode, NFS_CAP_XATTR))
		return -EOPNOTSUPP;

	if (!nfs_access_get_cached(inode, current_cred(), &cache, true)) {
		if (!(cache.mask & NFS_ACCESS_XAREAD))
			return -EACCES;
	}

	return nfs42_proc_getxattr(inode, key, buf, buflen);
}

static ssize_t
nfs4_listxattr_nfs4_user(struct inode *inode, char *list, size_t list_len)
{
	u64 cookie;
	bool eof;
	int ret, size;
	char *buf;
	size_t buflen;
	struct nfs_access_entry cache;

	if (!nfs_server_capable(inode, NFS_CAP_XATTR))
		return 0;

	if (!nfs_access_get_cached(inode, current_cred(), &cache, true)) {
		if (!(cache.mask & NFS_ACCESS_XALIST))
			return 0;
	}

	cookie = 0;
	eof = false;
	buflen = list_len ? list_len : XATTR_LIST_MAX;
	buf = list_len ? list : NULL;
	size = 0;

	while (!eof) {
		ret = nfs42_proc_listxattrs(inode, buf, buflen,
		    &cookie, &eof);
		if (ret < 0)
			return ret;

		if (list_len) {
			buf += ret;
			buflen -= ret;
		}
		size += ret;
	}

	return size;
}

#else

static ssize_t
nfs4_listxattr_nfs4_user(struct inode *inode, char *list, size_t list_len)
{
	return 0;
}
#endif /* CONFIG_NFS_V4_2 */

/*
 * nfs_fhget will use either the mounted_on_fileid or the fileid
 */
@@ -10045,7 +10143,7 @@ const struct nfs4_minor_version_ops *nfs_v4_minor_ops[] = {

static ssize_t nfs4_listxattr(struct dentry *dentry, char *list, size_t size)
{
	ssize_t error, error2;
	ssize_t error, error2, error3;

	error = generic_listxattr(dentry, list, size);
	if (error < 0)
@@ -10058,7 +10156,17 @@ static ssize_t nfs4_listxattr(struct dentry *dentry, char *list, size_t size)
	error2 = nfs4_listxattr_nfs4_label(d_inode(dentry), list, size);
	if (error2 < 0)
		return error2;
	return error + error2;

	if (list) {
		list += error2;
		size -= error2;
	}

	error3 = nfs4_listxattr_nfs4_user(d_inode(dentry), list, size);
	if (error3 < 0)
		return error3;

	return error + error2 + error3;
}

static const struct inode_operations nfs4_dir_inode_operations = {
@@ -10146,10 +10254,21 @@ static const struct xattr_handler nfs4_xattr_nfs4_acl_handler = {
	.set	= nfs4_xattr_set_nfs4_acl,
};

#ifdef CONFIG_NFS_V4_2
static const struct xattr_handler nfs4_xattr_nfs4_user_handler = {
	.prefix	= XATTR_USER_PREFIX,
	.get	= nfs4_xattr_get_nfs4_user,
	.set	= nfs4_xattr_set_nfs4_user,
};
#endif

const struct xattr_handler *nfs4_xattr_handlers[] = {
	&nfs4_xattr_nfs4_acl_handler,
#ifdef CONFIG_NFS_V4_SECURITY_LABEL
	&nfs4_xattr_nfs4_label_handler,
#endif
#ifdef CONFIG_NFS_V4_2
	&nfs4_xattr_nfs4_user_handler,
#endif
	NULL
};