Skip to content

Commit

Permalink
NFSv4.2: add the extended attribute proc functions.
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Frank van der Linden authored and Trond Myklebust committed Jul 13, 2020
1 parent ccde1e9 commit c10a751
Show file tree
Hide file tree
Showing 2 changed files with 244 additions and 0 deletions.
8 changes: 8 additions & 0 deletions fs/nfs/nfs42.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down
236 changes: 236 additions & 0 deletions fs/nfs/nfs42proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

0 comments on commit c10a751

Please sign in to comment.