]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
NFSD: Add nfsd4_encode_fattr4_posix_access_acl
authorRick Macklem <rmacklem@uoguelph.ca>
Fri, 9 Jan 2026 16:21:36 +0000 (11:21 -0500)
committerChuck Lever <chuck.lever@oracle.com>
Thu, 29 Jan 2026 14:48:33 +0000 (09:48 -0500)
The POSIX ACL extension to NFSv4 defines FATTR4_POSIX_ACCESS_ACL
for retrieving the access ACL of a file or directory. This patch
adds the XDR encoder for that attribute.

The access ACL is retrieved via get_inode_acl(). If the filesystem
provides no explicit access ACL, one is synthesized from the file
mode via posix_acl_from_mode(). Each entry is encoded as a
posixace4: tag type, permission bits, and principal name (empty
for structural entries, resolved via idmapping for USER/GROUP
entries).

Unlike the default ACL encoder which applies only to directories,
this encoder handles all inode types and ensures an access ACL is
always available through mode-based synthesis when needed.

Signed-off-by: Rick Macklem <rmacklem@uoguelph.ca>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
fs/nfsd/nfs4xdr.c

index 781f662d8918623c82a0873f31bf4205bc6bf678..358fa014be15ddb2b9cc1dcdbbc540c6d4a73b22 100644 (file)
@@ -3016,6 +3016,7 @@ struct nfsd4_fattr_args {
 #endif
 #ifdef CONFIG_NFSD_V4_POSIX_ACLS
        struct posix_acl        *dpacl;
+       struct posix_acl        *pacl;
 #endif
        u32                     rdattr_err;
        bool                    contextsupport;
@@ -3585,6 +3586,12 @@ static __be32 nfsd4_encode_fattr4_posix_default_acl(struct xdr_stream *xdr,
        return nfsd4_encode_posixacl(xdr, args->rqstp, args->dpacl);
 }
 
+static __be32 nfsd4_encode_fattr4_posix_access_acl(struct xdr_stream *xdr,
+                                                  const struct nfsd4_fattr_args *args)
+{
+       return nfsd4_encode_posixacl(xdr, args->rqstp, args->pacl);
+}
+
 #endif /* CONFIG_NFSD_V4_POSIX_ACLS */
 
 static const nfsd4_enc_attr nfsd4_enc_fattr4_encode_ops[] = {
@@ -3699,10 +3706,12 @@ static const nfsd4_enc_attr nfsd4_enc_fattr4_encode_ops[] = {
        [FATTR4_ACL_TRUEFORM]           = nfsd4_encode_fattr4_acl_trueform,
        [FATTR4_ACL_TRUEFORM_SCOPE]     = nfsd4_encode_fattr4_acl_trueform_scope,
        [FATTR4_POSIX_DEFAULT_ACL]      = nfsd4_encode_fattr4_posix_default_acl,
+       [FATTR4_POSIX_ACCESS_ACL]       = nfsd4_encode_fattr4_posix_access_acl,
 #else
        [FATTR4_ACL_TRUEFORM]           = nfsd4_encode_fattr4__noop,
        [FATTR4_ACL_TRUEFORM_SCOPE]     = nfsd4_encode_fattr4__noop,
        [FATTR4_POSIX_DEFAULT_ACL]      = nfsd4_encode_fattr4__noop,
+       [FATTR4_POSIX_ACCESS_ACL]       = nfsd4_encode_fattr4__noop,
 #endif
 };
 
@@ -3746,6 +3755,7 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
 #endif
 #ifdef CONFIG_NFSD_V4_POSIX_ACLS
        args.dpacl = NULL;
+       args.pacl = NULL;
 #endif
 
        /*
@@ -3877,6 +3887,29 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
                        }
                }
        }
+       if (attrmask[2] & FATTR4_WORD2_POSIX_ACCESS_ACL) {
+               struct inode *inode = d_inode(dentry);
+               struct posix_acl *pacl;
+
+               pacl = get_inode_acl(inode, ACL_TYPE_ACCESS);
+               if (!pacl)
+                       pacl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
+               if (IS_ERR(pacl)) {
+                       switch (PTR_ERR(pacl)) {
+                       case -EOPNOTSUPP:
+                               attrmask[2] &= ~FATTR4_WORD2_POSIX_ACCESS_ACL;
+                               break;
+                       case -EINVAL:
+                               status = nfserr_attrnotsupp;
+                               goto out;
+                       default:
+                               err = PTR_ERR(pacl);
+                               goto out_nfserr;
+                       }
+               } else {
+                       args.pacl = pacl;
+               }
+       }
 #endif /* CONFIG_NFSD_V4_POSIX_ACLS */
 
        /* attrmask */
@@ -3905,6 +3938,8 @@ out:
 #ifdef CONFIG_NFSD_V4_POSIX_ACLS
        if (args.dpacl)
                posix_acl_release(args.dpacl);
+       if (args.pacl)
+               posix_acl_release(args.pacl);
 #endif /* CONFIG_NFSD_V4_POSIX_ACLS */
 #ifdef CONFIG_NFSD_V4_SECURITY_LABEL
        if (args.context.context)