summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRick Macklem <rmacklem@uoguelph.ca>2026-01-09 19:21:36 +0300
committerChuck Lever <chuck.lever@oracle.com>2026-01-29 17:48:33 +0300
commit97e9a9ec32231d75cc241f63ed6fd4cd210079a0 (patch)
tree36b885b45ac06c6aaabba6fe61980e2f55b72b80
parent5e62c904e4dcc0e53471edca6347cdbc20fd18f8 (diff)
downloadlinux-97e9a9ec32231d75cc241f63ed6fd4cd210079a0.tar.xz
NFSD: Add nfsd4_encode_fattr4_posix_access_acl
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>
-rw-r--r--fs/nfsd/nfs4xdr.c35
1 files changed, 35 insertions, 0 deletions
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 781f662d8918..358fa014be15 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -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)