NFSv4: Add encoders/decoders for the NFSv4.1 dacl and sacl attributes
authorTrond Myklebust <trond.myklebust@hammerspace.com>
Sat, 14 May 2022 14:36:59 +0000 (10:36 -0400)
committerAnna Schumaker <Anna.Schumaker@Netapp.com>
Tue, 17 May 2022 17:32:46 +0000 (13:32 -0400)
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: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
fs/nfs/nfs4proc.c
fs/nfs/nfs4xdr.c
include/linux/nfs_xdr.h

index e6c830d..b2ddbaf 100644 (file)
@@ -5911,9 +5911,11 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf,
        struct page **pages;
        struct nfs_getaclargs args = {
                .fh = NFS_FH(inode),
+               .acl_type = type,
                .acl_len = buflen,
        };
        struct nfs_getaclres res = {
+               .acl_type = type,
                .acl_len = buflen,
        };
        struct rpc_message msg = {
@@ -6028,9 +6030,10 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf,
        struct nfs_server *server = NFS_SERVER(inode);
        struct page *pages[NFS4ACL_MAXPAGES];
        struct nfs_setaclargs arg = {
-               .fh             = NFS_FH(inode),
-               .acl_pages      = pages,
-               .acl_len        = buflen,
+               .fh = NFS_FH(inode),
+               .acl_type = type,
+               .acl_len = buflen,
+               .acl_pages = pages,
        };
        struct nfs_setaclres res;
        struct rpc_message msg = {
index 86a5f65..0b41e00 100644 (file)
@@ -1680,19 +1680,35 @@ encode_restorefh(struct xdr_stream *xdr, struct compound_hdr *hdr)
        encode_op_hdr(xdr, OP_RESTOREFH, decode_restorefh_maxsz, hdr);
 }
 
-static void
-encode_setacl(struct xdr_stream *xdr, const struct nfs_setaclargs *arg,
-               struct compound_hdr *hdr)
+static void nfs4_acltype_to_bitmap(enum nfs4_acl_type type, __u32 bitmap[2])
 {
-       __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_nfs4_stateid(xdr, &zero_stateid);
-       p = reserve_space(xdr, 2*4);
-       *p++ = cpu_to_be32(1);
-       *p = cpu_to_be32(FATTR4_WORD0_ACL);
-       p = reserve_space(xdr, 4);
-       *p = cpu_to_be32(arg->acl_len);
+       xdr_encode_bitmap4(xdr, bitmap, ARRAY_SIZE(bitmap));
+       encode_uint32(xdr, 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,
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
-       const __u32 nfs4_acl_bitmap[1] = {
-               [0] = FATTR4_WORD0_ACL,
-       };
+       __u32 nfs4_acl_bitmap[2];
        uint32_t replen;
 
+       nfs4_acltype_to_bitmap(args->acl_type, nfs4_acl_bitmap);
+
        encode_compound_hdr(xdr, req, &hdr);
        encode_sequence(xdr, &args->seq_args, &hdr);
        encode_putfh(xdr, args->fh, &hdr);
@@ -5386,7 +5402,7 @@ decode_restorefh(struct xdr_stream *xdr)
 }
 
 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;
        uint32_t attrlen,
@@ -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)
                goto out;
 
-       if (unlikely(bitmap[0] & (FATTR4_WORD0_ACL - 1U)))
-               return -EIO;
-       if (likely(bitmap[0] & FATTR4_WORD0_ACL)) {
-
-               /* 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));
-               }
-       } else
-               status = -EOPNOTSUPP;
+       switch (type) {
+       default:
+               if (unlikely(bitmap[0] & (FATTR4_WORD0_ACL - 1U)))
+                       return -EIO;
+               if (!(bitmap[0] & FATTR4_WORD0_ACL))
+                       return -EOPNOTSUPP;
+               break;
+       case NFS4ACL_DACL:
+               if (unlikely(bitmap[0] || bitmap[1] & (FATTR4_WORD1_DACL - 1U)))
+                       return -EIO;
+               if (!(bitmap[1] & FATTR4_WORD1_DACL))
+                       return -EOPNOTSUPP;
+               break;
+       case NFS4ACL_SACL:
+               if (unlikely(bitmap[0] || bitmap[1] & (FATTR4_WORD1_SACL - 1U)))
+                       return -EIO;
+               if (!(bitmap[1] & FATTR4_WORD1_SACL))
+                       return -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:
        return status;
 }
@@ -6486,7 +6515,7 @@ nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
        status = decode_putfh(xdr);
        if (status)
                goto out;
-       status = decode_getacl(xdr, rqstp, res);
+       status = decode_getacl(xdr, rqstp, res, res->acl_type);
 
 out:
        return status;
index 13d068c..4a8ba84 100644 (file)
@@ -810,6 +810,7 @@ enum nfs4_acl_type {
 struct nfs_setaclargs {
        struct nfs4_sequence_args       seq_args;
        struct nfs_fh *                 fh;
+       enum nfs4_acl_type              acl_type;
        size_t                          acl_len;
        struct page **                  acl_pages;
 };
@@ -821,6 +822,7 @@ struct nfs_setaclres {
 struct nfs_getaclargs {
        struct nfs4_sequence_args       seq_args;
        struct nfs_fh *                 fh;
+       enum nfs4_acl_type              acl_type;
        size_t                          acl_len;
        struct page **                  acl_pages;
 };
@@ -829,6 +831,7 @@ struct nfs_getaclargs {
 #define NFS4_ACL_TRUNC         0x0001  /* ACL was truncated */
 struct nfs_getaclres {
        struct nfs4_sequence_res        seq_res;
+       enum nfs4_acl_type              acl_type;
        size_t                          acl_len;
        size_t                          acl_data_offset;
        int                             acl_flags;