forked from Minki/linux
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
@ -39,6 +39,14 @@ static inline bool nfs42_files_from_same_server(struct file *in,
|
|||||||
c_out->cl_serverowner);
|
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.
|
* Maximum XDR buffer size needed for a listxattr buffer of buflen size.
|
||||||
*
|
*
|
||||||
|
@ -1088,3 +1088,239 @@ out_put_src_lock:
|
|||||||
nfs_put_lock_context(src_lock);
|
nfs_put_lock_context(src_lock);
|
||||||
return err;
|
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 New Issue
Block a user