Commit db145db0 authored by Trond Myklebust's avatar Trond Myklebust Committed by Anna Schumaker

NFSv4: Add encoders/decoders for the NFSv4.1 dacl and sacl attributes

Add the ability to set or retrieve the acl using the NFSv4.1 'dacl' and
'sacl' attributes to the NFSv4 xdr encoders/decoders.
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: default avatarAnna Schumaker <Anna.Schumaker@Netapp.com>
parent 7b8b44eb
...@@ -5911,9 +5911,11 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, ...@@ -5911,9 +5911,11 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf,
struct page **pages; struct page **pages;
struct nfs_getaclargs args = { struct nfs_getaclargs args = {
.fh = NFS_FH(inode), .fh = NFS_FH(inode),
.acl_type = type,
.acl_len = buflen, .acl_len = buflen,
}; };
struct nfs_getaclres res = { struct nfs_getaclres res = {
.acl_type = type,
.acl_len = buflen, .acl_len = buflen,
}; };
struct rpc_message msg = { struct rpc_message msg = {
...@@ -6028,9 +6030,10 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, ...@@ -6028,9 +6030,10 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf,
struct nfs_server *server = NFS_SERVER(inode); struct nfs_server *server = NFS_SERVER(inode);
struct page *pages[NFS4ACL_MAXPAGES]; struct page *pages[NFS4ACL_MAXPAGES];
struct nfs_setaclargs arg = { struct nfs_setaclargs arg = {
.fh = NFS_FH(inode), .fh = NFS_FH(inode),
.acl_pages = pages, .acl_type = type,
.acl_len = buflen, .acl_len = buflen,
.acl_pages = pages,
}; };
struct nfs_setaclres res; struct nfs_setaclres res;
struct rpc_message msg = { struct rpc_message msg = {
......
...@@ -1680,19 +1680,35 @@ encode_restorefh(struct xdr_stream *xdr, struct compound_hdr *hdr) ...@@ -1680,19 +1680,35 @@ encode_restorefh(struct xdr_stream *xdr, struct compound_hdr *hdr)
encode_op_hdr(xdr, OP_RESTOREFH, decode_restorefh_maxsz, hdr); encode_op_hdr(xdr, OP_RESTOREFH, decode_restorefh_maxsz, hdr);
} }
static void static void nfs4_acltype_to_bitmap(enum nfs4_acl_type type, __u32 bitmap[2])
encode_setacl(struct xdr_stream *xdr, const struct nfs_setaclargs *arg,
struct compound_hdr *hdr)
{ {
__be32 *p; switch (type) {
default:
bitmap[0] = FATTR4_WORD0_ACL;
bitmap[1] = 0;
break;
case NFS4ACL_DACL:
bitmap[0] = 0;
bitmap[1] = FATTR4_WORD1_DACL;
break;
case NFS4ACL_SACL:
bitmap[0] = 0;
bitmap[1] = FATTR4_WORD1_SACL;
}
}
static void encode_setacl(struct xdr_stream *xdr,
const struct nfs_setaclargs *arg,
struct compound_hdr *hdr)
{
__u32 bitmap[2];
nfs4_acltype_to_bitmap(arg->acl_type, bitmap);
encode_op_hdr(xdr, OP_SETATTR, decode_setacl_maxsz, hdr); encode_op_hdr(xdr, OP_SETATTR, decode_setacl_maxsz, hdr);
encode_nfs4_stateid(xdr, &zero_stateid); encode_nfs4_stateid(xdr, &zero_stateid);
p = reserve_space(xdr, 2*4); xdr_encode_bitmap4(xdr, bitmap, ARRAY_SIZE(bitmap));
*p++ = cpu_to_be32(1); encode_uint32(xdr, arg->acl_len);
*p = cpu_to_be32(FATTR4_WORD0_ACL);
p = reserve_space(xdr, 4);
*p = cpu_to_be32(arg->acl_len);
xdr_write_pages(xdr, arg->acl_pages, 0, arg->acl_len); xdr_write_pages(xdr, arg->acl_pages, 0, arg->acl_len);
} }
...@@ -2587,11 +2603,11 @@ static void nfs4_xdr_enc_getacl(struct rpc_rqst *req, struct xdr_stream *xdr, ...@@ -2587,11 +2603,11 @@ static void nfs4_xdr_enc_getacl(struct rpc_rqst *req, struct xdr_stream *xdr,
struct compound_hdr hdr = { struct compound_hdr hdr = {
.minorversion = nfs4_xdr_minorversion(&args->seq_args), .minorversion = nfs4_xdr_minorversion(&args->seq_args),
}; };
const __u32 nfs4_acl_bitmap[1] = { __u32 nfs4_acl_bitmap[2];
[0] = FATTR4_WORD0_ACL,
};
uint32_t replen; uint32_t replen;
nfs4_acltype_to_bitmap(args->acl_type, nfs4_acl_bitmap);
encode_compound_hdr(xdr, req, &hdr); encode_compound_hdr(xdr, req, &hdr);
encode_sequence(xdr, &args->seq_args, &hdr); encode_sequence(xdr, &args->seq_args, &hdr);
encode_putfh(xdr, args->fh, &hdr); encode_putfh(xdr, args->fh, &hdr);
...@@ -5386,7 +5402,7 @@ decode_restorefh(struct xdr_stream *xdr) ...@@ -5386,7 +5402,7 @@ decode_restorefh(struct xdr_stream *xdr)
} }
static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req, static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
struct nfs_getaclres *res) struct nfs_getaclres *res, enum nfs4_acl_type type)
{ {
unsigned int savep; unsigned int savep;
uint32_t attrlen, uint32_t attrlen,
...@@ -5404,26 +5420,39 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req, ...@@ -5404,26 +5420,39 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0) if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
goto out; goto out;
if (unlikely(bitmap[0] & (FATTR4_WORD0_ACL - 1U))) switch (type) {
return -EIO; default:
if (likely(bitmap[0] & FATTR4_WORD0_ACL)) { if (unlikely(bitmap[0] & (FATTR4_WORD0_ACL - 1U)))
return -EIO;
/* The bitmap (xdr len + bitmaps) and the attr xdr len words if (!(bitmap[0] & FATTR4_WORD0_ACL))
* are stored with the acl data to handle the problem of return -EOPNOTSUPP;
* variable length bitmaps.*/ break;
res->acl_data_offset = xdr_page_pos(xdr); case NFS4ACL_DACL:
res->acl_len = attrlen; if (unlikely(bitmap[0] || bitmap[1] & (FATTR4_WORD1_DACL - 1U)))
return -EIO;
/* Check for receive buffer overflow */ if (!(bitmap[1] & FATTR4_WORD1_DACL))
if (res->acl_len > xdr_stream_remaining(xdr) || return -EOPNOTSUPP;
res->acl_len + res->acl_data_offset > xdr->buf->page_len) { break;
res->acl_flags |= NFS4_ACL_TRUNC; case NFS4ACL_SACL:
dprintk("NFS: acl reply: attrlen %u > page_len %zu\n", if (unlikely(bitmap[0] || bitmap[1] & (FATTR4_WORD1_SACL - 1U)))
attrlen, xdr_stream_remaining(xdr)); return -EIO;
} if (!(bitmap[1] & FATTR4_WORD1_SACL))
} else return -EOPNOTSUPP;
status = -EOPNOTSUPP; }
/* The bitmap (xdr len + bitmaps) and the attr xdr len words
* are stored with the acl data to handle the problem of
* variable length bitmaps.*/
res->acl_data_offset = xdr_page_pos(xdr);
res->acl_len = attrlen;
/* Check for receive buffer overflow */
if (res->acl_len > xdr_stream_remaining(xdr) ||
res->acl_len + res->acl_data_offset > xdr->buf->page_len) {
res->acl_flags |= NFS4_ACL_TRUNC;
dprintk("NFS: acl reply: attrlen %u > page_len %zu\n",
attrlen, xdr_stream_remaining(xdr));
}
out: out:
return status; return status;
} }
...@@ -6486,7 +6515,7 @@ nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, struct xdr_stream *xdr, ...@@ -6486,7 +6515,7 @@ nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
status = decode_putfh(xdr); status = decode_putfh(xdr);
if (status) if (status)
goto out; goto out;
status = decode_getacl(xdr, rqstp, res); status = decode_getacl(xdr, rqstp, res, res->acl_type);
out: out:
return status; return status;
......
...@@ -810,6 +810,7 @@ enum nfs4_acl_type { ...@@ -810,6 +810,7 @@ enum nfs4_acl_type {
struct nfs_setaclargs { struct nfs_setaclargs {
struct nfs4_sequence_args seq_args; struct nfs4_sequence_args seq_args;
struct nfs_fh * fh; struct nfs_fh * fh;
enum nfs4_acl_type acl_type;
size_t acl_len; size_t acl_len;
struct page ** acl_pages; struct page ** acl_pages;
}; };
...@@ -821,6 +822,7 @@ struct nfs_setaclres { ...@@ -821,6 +822,7 @@ struct nfs_setaclres {
struct nfs_getaclargs { struct nfs_getaclargs {
struct nfs4_sequence_args seq_args; struct nfs4_sequence_args seq_args;
struct nfs_fh * fh; struct nfs_fh * fh;
enum nfs4_acl_type acl_type;
size_t acl_len; size_t acl_len;
struct page ** acl_pages; struct page ** acl_pages;
}; };
...@@ -829,6 +831,7 @@ struct nfs_getaclargs { ...@@ -829,6 +831,7 @@ struct nfs_getaclargs {
#define NFS4_ACL_TRUNC 0x0001 /* ACL was truncated */ #define NFS4_ACL_TRUNC 0x0001 /* ACL was truncated */
struct nfs_getaclres { struct nfs_getaclres {
struct nfs4_sequence_res seq_res; struct nfs4_sequence_res seq_res;
enum nfs4_acl_type acl_type;
size_t acl_len; size_t acl_len;
size_t acl_data_offset; size_t acl_data_offset;
int acl_flags; int acl_flags;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment