mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	NFSv4.2: add the extended attribute proc functions.
Implement the extended attribute procedures for NFSv4.2 extended attribute support (RFC 8276). Signed-off-by: Frank van der Linden <fllinden@amazon.com> Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
This commit is contained in:
		
							parent
							
								
									ccde1e9c01
								
							
						
					
					
						commit
						c10a75145f
					
				
					 2 changed files with 244 additions and 0 deletions
				
			
		| 
						 | 
				
			
			@ -39,6 +39,14 @@ static inline bool nfs42_files_from_same_server(struct file *in,
 | 
			
		|||
					       c_out->cl_serverowner);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ssize_t nfs42_proc_getxattr(struct inode *inode, const char *name,
 | 
			
		||||
			    void *buf, size_t buflen);
 | 
			
		||||
int nfs42_proc_setxattr(struct inode *inode, const char *name,
 | 
			
		||||
			const void *buf, size_t buflen, int flags);
 | 
			
		||||
ssize_t nfs42_proc_listxattrs(struct inode *inode, void *buf,
 | 
			
		||||
			       size_t buflen, u64 *cookiep, bool *eofp);
 | 
			
		||||
int nfs42_proc_removexattr(struct inode *inode, const char *name);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Maximum XDR buffer size needed for a listxattr buffer of buflen size.
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1088,3 +1088,239 @@ int nfs42_proc_clone(struct file *src_f, struct file *dst_f,
 | 
			
		|||
	nfs_put_lock_context(src_lock);
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define NFS4XATTR_MAXPAGES DIV_ROUND_UP(XATTR_SIZE_MAX, PAGE_SIZE)
 | 
			
		||||
 | 
			
		||||
static int _nfs42_proc_removexattr(struct inode *inode, const char *name)
 | 
			
		||||
{
 | 
			
		||||
	struct nfs_server *server = NFS_SERVER(inode);
 | 
			
		||||
	struct nfs42_removexattrargs args = {
 | 
			
		||||
		.fh = NFS_FH(inode),
 | 
			
		||||
		.xattr_name = name,
 | 
			
		||||
	};
 | 
			
		||||
	struct nfs42_removexattrres res;
 | 
			
		||||
	struct rpc_message msg = {
 | 
			
		||||
		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVEXATTR],
 | 
			
		||||
		.rpc_argp = &args,
 | 
			
		||||
		.rpc_resp = &res,
 | 
			
		||||
	};
 | 
			
		||||
	int ret;
 | 
			
		||||
	unsigned long timestamp = jiffies;
 | 
			
		||||
 | 
			
		||||
	ret = nfs4_call_sync(server->client, server, &msg, &args.seq_args,
 | 
			
		||||
	    &res.seq_res, 1);
 | 
			
		||||
	if (!ret)
 | 
			
		||||
		nfs4_update_changeattr(inode, &res.cinfo, timestamp, 0);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _nfs42_proc_setxattr(struct inode *inode, const char *name,
 | 
			
		||||
				const void *buf, size_t buflen, int flags)
 | 
			
		||||
{
 | 
			
		||||
	struct nfs_server *server = NFS_SERVER(inode);
 | 
			
		||||
	struct page *pages[NFS4XATTR_MAXPAGES];
 | 
			
		||||
	struct nfs42_setxattrargs arg = {
 | 
			
		||||
		.fh		= NFS_FH(inode),
 | 
			
		||||
		.xattr_pages	= pages,
 | 
			
		||||
		.xattr_len	= buflen,
 | 
			
		||||
		.xattr_name	= name,
 | 
			
		||||
		.xattr_flags	= flags,
 | 
			
		||||
	};
 | 
			
		||||
	struct nfs42_setxattrres res;
 | 
			
		||||
	struct rpc_message msg = {
 | 
			
		||||
		.rpc_proc	= &nfs4_procedures[NFSPROC4_CLNT_SETXATTR],
 | 
			
		||||
		.rpc_argp	= &arg,
 | 
			
		||||
		.rpc_resp	= &res,
 | 
			
		||||
	};
 | 
			
		||||
	int ret, np;
 | 
			
		||||
	unsigned long timestamp = jiffies;
 | 
			
		||||
 | 
			
		||||
	if (buflen > server->sxasize)
 | 
			
		||||
		return -ERANGE;
 | 
			
		||||
 | 
			
		||||
	if (buflen > 0) {
 | 
			
		||||
		np = nfs4_buf_to_pages_noslab(buf, buflen, arg.xattr_pages);
 | 
			
		||||
		if (np < 0)
 | 
			
		||||
			return np;
 | 
			
		||||
	} else
 | 
			
		||||
		np = 0;
 | 
			
		||||
 | 
			
		||||
	ret = nfs4_call_sync(server->client, server, &msg, &arg.seq_args,
 | 
			
		||||
	    &res.seq_res, 1);
 | 
			
		||||
 | 
			
		||||
	for (; np > 0; np--)
 | 
			
		||||
		put_page(pages[np - 1]);
 | 
			
		||||
 | 
			
		||||
	if (!ret)
 | 
			
		||||
		nfs4_update_changeattr(inode, &res.cinfo, timestamp, 0);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ssize_t _nfs42_proc_getxattr(struct inode *inode, const char *name,
 | 
			
		||||
				void *buf, size_t buflen)
 | 
			
		||||
{
 | 
			
		||||
	struct nfs_server *server = NFS_SERVER(inode);
 | 
			
		||||
	struct page *pages[NFS4XATTR_MAXPAGES] = {};
 | 
			
		||||
	struct nfs42_getxattrargs arg = {
 | 
			
		||||
		.fh		= NFS_FH(inode),
 | 
			
		||||
		.xattr_pages	= pages,
 | 
			
		||||
		.xattr_len	= buflen,
 | 
			
		||||
		.xattr_name	= name,
 | 
			
		||||
	};
 | 
			
		||||
	struct nfs42_getxattrres res;
 | 
			
		||||
	struct rpc_message msg = {
 | 
			
		||||
		.rpc_proc	= &nfs4_procedures[NFSPROC4_CLNT_GETXATTR],
 | 
			
		||||
		.rpc_argp	= &arg,
 | 
			
		||||
		.rpc_resp	= &res,
 | 
			
		||||
	};
 | 
			
		||||
	int ret, np;
 | 
			
		||||
 | 
			
		||||
	ret = nfs4_call_sync(server->client, server, &msg, &arg.seq_args,
 | 
			
		||||
	    &res.seq_res, 0);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	if (buflen) {
 | 
			
		||||
		if (res.xattr_len > buflen)
 | 
			
		||||
			return -ERANGE;
 | 
			
		||||
		_copy_from_pages(buf, pages, 0, res.xattr_len);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	np = DIV_ROUND_UP(res.xattr_len, PAGE_SIZE);
 | 
			
		||||
	while (--np >= 0)
 | 
			
		||||
		__free_page(pages[np]);
 | 
			
		||||
 | 
			
		||||
	return res.xattr_len;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ssize_t _nfs42_proc_listxattrs(struct inode *inode, void *buf,
 | 
			
		||||
				 size_t buflen, u64 *cookiep, bool *eofp)
 | 
			
		||||
{
 | 
			
		||||
	struct nfs_server *server = NFS_SERVER(inode);
 | 
			
		||||
	struct page **pages;
 | 
			
		||||
	struct nfs42_listxattrsargs arg = {
 | 
			
		||||
		.fh		= NFS_FH(inode),
 | 
			
		||||
		.cookie		= *cookiep,
 | 
			
		||||
	};
 | 
			
		||||
	struct nfs42_listxattrsres res = {
 | 
			
		||||
		.eof = false,
 | 
			
		||||
		.xattr_buf = buf,
 | 
			
		||||
		.xattr_len = buflen,
 | 
			
		||||
	};
 | 
			
		||||
	struct rpc_message msg = {
 | 
			
		||||
		.rpc_proc	= &nfs4_procedures[NFSPROC4_CLNT_LISTXATTRS],
 | 
			
		||||
		.rpc_argp	= &arg,
 | 
			
		||||
		.rpc_resp	= &res,
 | 
			
		||||
	};
 | 
			
		||||
	u32 xdrlen;
 | 
			
		||||
	int ret, np;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	res.scratch = alloc_page(GFP_KERNEL);
 | 
			
		||||
	if (!res.scratch)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	xdrlen = nfs42_listxattr_xdrsize(buflen);
 | 
			
		||||
	if (xdrlen > server->lxasize)
 | 
			
		||||
		xdrlen = server->lxasize;
 | 
			
		||||
	np = xdrlen / PAGE_SIZE + 1;
 | 
			
		||||
 | 
			
		||||
	pages = kcalloc(np, sizeof(struct page *), GFP_KERNEL);
 | 
			
		||||
	if (pages == NULL) {
 | 
			
		||||
		__free_page(res.scratch);
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	arg.xattr_pages = pages;
 | 
			
		||||
	arg.count = xdrlen;
 | 
			
		||||
 | 
			
		||||
	ret = nfs4_call_sync(server->client, server, &msg, &arg.seq_args,
 | 
			
		||||
	    &res.seq_res, 0);
 | 
			
		||||
 | 
			
		||||
	if (ret >= 0) {
 | 
			
		||||
		ret = res.copied;
 | 
			
		||||
		*cookiep = res.cookie;
 | 
			
		||||
		*eofp = res.eof;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	while (--np >= 0) {
 | 
			
		||||
		if (pages[np])
 | 
			
		||||
			__free_page(pages[np]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	__free_page(res.scratch);
 | 
			
		||||
	kfree(pages);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ssize_t nfs42_proc_getxattr(struct inode *inode, const char *name,
 | 
			
		||||
			      void *buf, size_t buflen)
 | 
			
		||||
{
 | 
			
		||||
	struct nfs4_exception exception = { };
 | 
			
		||||
	ssize_t err;
 | 
			
		||||
 | 
			
		||||
	do {
 | 
			
		||||
		err = _nfs42_proc_getxattr(inode, name, buf, buflen);
 | 
			
		||||
		if (err >= 0)
 | 
			
		||||
			break;
 | 
			
		||||
		err = nfs4_handle_exception(NFS_SERVER(inode), err,
 | 
			
		||||
				&exception);
 | 
			
		||||
	} while (exception.retry);
 | 
			
		||||
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int nfs42_proc_setxattr(struct inode *inode, const char *name,
 | 
			
		||||
			      const void *buf, size_t buflen, int flags)
 | 
			
		||||
{
 | 
			
		||||
	struct nfs4_exception exception = { };
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	do {
 | 
			
		||||
		err = _nfs42_proc_setxattr(inode, name, buf, buflen, flags);
 | 
			
		||||
		if (!err)
 | 
			
		||||
			break;
 | 
			
		||||
		err = nfs4_handle_exception(NFS_SERVER(inode), err,
 | 
			
		||||
				&exception);
 | 
			
		||||
	} while (exception.retry);
 | 
			
		||||
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ssize_t nfs42_proc_listxattrs(struct inode *inode, void *buf,
 | 
			
		||||
			      size_t buflen, u64 *cookiep, bool *eofp)
 | 
			
		||||
{
 | 
			
		||||
	struct nfs4_exception exception = { };
 | 
			
		||||
	ssize_t err;
 | 
			
		||||
 | 
			
		||||
	do {
 | 
			
		||||
		err = _nfs42_proc_listxattrs(inode, buf, buflen,
 | 
			
		||||
		    cookiep, eofp);
 | 
			
		||||
		if (err >= 0)
 | 
			
		||||
			break;
 | 
			
		||||
		err = nfs4_handle_exception(NFS_SERVER(inode), err,
 | 
			
		||||
				&exception);
 | 
			
		||||
	} while (exception.retry);
 | 
			
		||||
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int nfs42_proc_removexattr(struct inode *inode, const char *name)
 | 
			
		||||
{
 | 
			
		||||
	struct nfs4_exception exception = { };
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	do {
 | 
			
		||||
		err = _nfs42_proc_removexattr(inode, name);
 | 
			
		||||
		if (!err)
 | 
			
		||||
			break;
 | 
			
		||||
		err = nfs4_handle_exception(NFS_SERVER(inode), err,
 | 
			
		||||
				&exception);
 | 
			
		||||
	} while (exception.retry);
 | 
			
		||||
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue