From 318579c0935c2faf1cccbc6359b410ff2ca4b84a Mon Sep 17 00:00:00 2001 From: Rick Macklem Date: Fri, 9 Jan 2026 11:21:41 -0500 Subject: [PATCH] NFSD: Add POSIX draft ACL support to the NFSv4 SETATTR operation The POSIX ACL extension to NFSv4 enables clients to set access and default ACLs via FATTR4_POSIX_ACCESS_ACL and FATTR4_POSIX_DEFAULT_ACL attributes. Integration of these attributes into SETATTR processing requires wiring them through the nfsd_attrs structure and ensuring proper cleanup on all code paths. This patch connects the na_pacl and na_dpacl fields in nfsd_attrs to the decoded ACL pointers from the NFSv4 SETATTR decoder. Ownership of these ACL references transfers to attrs immediately after initialization, with the decoder's pointers cleared to NULL. This transfer ensures nfsd_attrs_free() releases the ACLs on normal completion, while new error paths call posix_acl_release() directly when cleanup occurs before nfsd_attrs_free() runs. Early returns in the nfsd4_setattr() function gain conversions to goto statements that branch to proper cleanup handlers. Error paths before fh_want_write() branch to out_err for ACL release only; paths after fh_want_write() use the existing out label for full cleanup via nfsd_attrs_free(). The patch adds mutual exclusion between NFSv4 ACLs (sa_acl) and POSIX ACLs. Setting both types simultaneously returns nfserr_inval because these ACL models cannot coexist on the same file object. Signed-off-by: Rick Macklem Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4proc.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 72edf4add536a..d476d108f6e10 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -1214,6 +1214,8 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd_attrs attrs = { .na_iattr = &setattr->sa_iattr, .na_seclabel = &setattr->sa_label, + .na_pacl = setattr->sa_pacl, + .na_dpacl = setattr->sa_dpacl, }; bool save_no_wcc, deleg_attrs; struct nfs4_stid *st = NULL; @@ -1221,6 +1223,10 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, __be32 status = nfs_ok; int err; + /* Transfer ownership to attrs for cleanup via nfsd_attrs_free() */ + setattr->sa_pacl = NULL; + setattr->sa_dpacl = NULL; + deleg_attrs = setattr->sa_bmval[2] & (FATTR4_WORD2_TIME_DELEG_ACCESS | FATTR4_WORD2_TIME_DELEG_MODIFY); @@ -1234,7 +1240,7 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, &cstate->current_fh, &setattr->sa_stateid, flags, NULL, &st); if (status) - return status; + goto out_err; } if (deleg_attrs) { @@ -1252,17 +1258,24 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, if (st) nfs4_put_stid(st); if (status) - return status; + goto out_err; err = fh_want_write(&cstate->current_fh); - if (err) - return nfserrno(err); + if (err) { + status = nfserrno(err); + goto out_err; + } status = nfs_ok; status = check_attr_support(cstate, setattr->sa_bmval, nfsd_attrmask); if (status) goto out; + if (setattr->sa_acl && (attrs.na_dpacl || attrs.na_pacl)) { + status = nfserr_inval; + goto out; + } + inode = cstate->current_fh.fh_dentry->d_inode; status = nfsd4_acl_to_attr(S_ISDIR(inode->i_mode) ? NF4DIR : NF4REG, setattr->sa_acl, &attrs); @@ -1280,8 +1293,9 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, if (!status) status = nfserrno(attrs.na_paclerr); out: - nfsd_attrs_free(&attrs); fh_drop_write(&cstate->current_fh); +out_err: + nfsd_attrs_free(&attrs); return status; } -- 2.47.3