* [PATCH v2 0/8] Add NFSv4.2 POSIX ACL support to the client
@ 2026-01-03 23:40 rick.macklem
2026-01-03 23:40 ` [PATCH v2 1/8] Add definitions for the POSIX draft ACL attributes rick.macklem
` (7 more replies)
0 siblings, 8 replies; 12+ messages in thread
From: rick.macklem @ 2026-01-03 23:40 UTC (permalink / raw)
To: linux-nfs; +Cc: Rick Macklem
From: Rick Macklem <rmacklem@uoguelph.ca>
The Internet draft "POSIX Draft ACL support for
Network File System Version 4, Minor Version2"
https://datatracker.ietf.org/doc/draft-ietf-nfsv4-posix-acls/
describes an extension to NFSv4.2 so that POSIX
draft ACLs can get acquired and set directly,
without using the loosey NFSv4->POSIX draft mapping
algorith. It extends the protocol with four new
attributes.
This patch series implements the client side of
this extension for the nfs client. It is analogous
to the NFSACL protocol used as a sideband protocol
for NFSv3 and allows the ACLs to be acquired/set
be getfacl(1)/setfacl(1).
The current implementation may not handle the
"per file" scope, where individual file objects
store/use either an NFSv4 ACL or a POSIX draft ACL.
The only known file system that implements this
is IBM's GPFS, and only if the "all" option is
set for ACLs on it. Until a server implements
this case, it will be difficult to implement
correct client semantics for this case.
The last patch is rather large, but I would
get either build failures or build warnings
when I broke it up into smaller chunks.
The only changes from v1 is the addition of
the 0001 patch from the server series, to
make the kernel test robot happy and a small
change to the calculation of NFS4_ACL_MAXPAGES.
Rick Macklem (8):
Add definitions for the POSIX draft ACL attributes
Add entries to the predefined client operations enum
Add new entries for handling POSIX draft ACLs
Make posix_acl_from_nfsacl() global
Make three functions global and move them to acl.c
Make nfs4_server_supports_acls() global
Set SB_POSIXACL if the server supports the extension
Add support for the NFSv4.2 POSIX draft ACL attributes
fs/nfs/Makefile | 2 +-
fs/nfs/nfs.h | 3 +
fs/nfs/nfs34acl.c | 40 +++
fs/nfs/nfs3acl.c | 44 +--
fs/nfs/nfs42proc.c | 304 +++++++++++++++++++
fs/nfs/nfs42xdr.c | 642 ++++++++++++++++++++++++++++++++++++++++
fs/nfs/nfs4_fs.h | 9 +
fs/nfs/nfs4proc.c | 18 +-
fs/nfs/nfs4xdr.c | 2 +
fs/nfs/super.c | 5 +
fs/nfs_common/nfsacl.c | 3 +-
include/linux/nfs4.h | 39 +++
include/linux/nfs_xdr.h | 59 ++++
include/linux/nfsacl.h | 2 +
14 files changed, 1130 insertions(+), 42 deletions(-)
create mode 100644 fs/nfs/nfs34acl.c
--
2.49.0
^ permalink raw reply [flat|nested] 12+ messages in thread* [PATCH v2 1/8] Add definitions for the POSIX draft ACL attributes 2026-01-03 23:40 [PATCH v2 0/8] Add NFSv4.2 POSIX ACL support to the client rick.macklem @ 2026-01-03 23:40 ` rick.macklem 2026-01-03 23:40 ` [PATCH v2 2/8] Add entries to the predefined client operations enum rick.macklem ` (6 subsequent siblings) 7 siblings, 0 replies; 12+ messages in thread From: rick.macklem @ 2026-01-03 23:40 UTC (permalink / raw) To: linux-nfs; +Cc: Rick Macklem, kernel test robot From: Rick Macklem <rmacklem@uoguelph.ca> The Internet draft "POSIX Draft ACL support for Network File System Version 4, Minor Version2" https://datatracker.ietf.org/doc/draft-ietf-nfsv4-posix-acls/ describes an extension to NFSv4.2 so that POSIX draft ACLs can get acquired and set directly, without using the loosey NFSv4->POSIX draft mapping algorith. It extends the protocol with four new attributes. This patch adds definitions of these four attributes to the nfs4.h file. Signed-off-by: Rick Macklem <rmacklem@uoguelph.ca> Reported-by: kernel test robot <lkp@intel.com> Closes: https://lore.kernel.org/oe-kbuild-all/202601031506.MX594pma-lkp@intel.com/ Closes: https://lore.kernel.org/oe-kbuild-all/202601031639.zIQYLs4h-lkp@intel.com/ Closes: https://lore.kernel.org/oe-kbuild-all/202601031746.QiLqxADW-lkp@intel.com/ Signed-off-by: Rick Macklem <rmacklem@uoguelph.ca> --- include/linux/nfs4.h | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index e947af6a3684..9d70a5e6a8d0 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h @@ -516,6 +516,39 @@ enum { FATTR4_XATTR_SUPPORT = 82, }; +/* + * Symbol names and values are from draft-rmacklem-nfsv4-posix-acls + * "POSIX Draft ACL support for Network File System Version 4, Minor version 2" + * Section 10. + */ +enum { + ACL_MODEL_NFS4 = 1, + ACL_MODEL_POSIX_DRAFT = 2, + ACL_MODEL_NONE = 3, +}; + +enum { + ACL_SCOPE_FILE_OBJECT = 1, + ACL_SCOPE_FILE_SYSTEM = 2, + ACL_SCOPE_SERVER = 3, +}; + +enum { + POSIXACE4_TAG_USER_OBJ = 1, + POSIXACE4_TAG_USER = 2, + POSIXACE4_TAG_GROUP_OBJ = 3, + POSIXACE4_TAG_GROUP = 4, + POSIXACE4_TAG_MASK = 5, + POSIXACE4_TAG_OTHER = 6, +}; + +enum { + FATTR4_ACL_TRUEFORM = 89, + FATTR4_ACL_TRUEFORM_SCOPE = 90, + FATTR4_POSIX_DEFAULT_ACL = 91, + FATTR4_POSIX_ACCESS_ACL = 92, +}; + /* * The following internal definitions enable processing the above * attribute bits within 32-bit word boundaries. @@ -598,6 +631,10 @@ enum { #define FATTR4_WORD2_TIME_DELEG_ACCESS BIT(FATTR4_TIME_DELEG_ACCESS - 64) #define FATTR4_WORD2_TIME_DELEG_MODIFY BIT(FATTR4_TIME_DELEG_MODIFY - 64) #define FATTR4_WORD2_OPEN_ARGUMENTS BIT(FATTR4_OPEN_ARGUMENTS - 64) +#define FATTR4_WORD2_ACL_TRUEFORM BIT(FATTR4_ACL_TRUEFORM - 64) +#define FATTR4_WORD2_ACL_TRUEFORM_SCOPE BIT(FATTR4_ACL_TRUEFORM_SCOPE - 64) +#define FATTR4_WORD2_POSIX_DEFAULT_ACL BIT(FATTR4_POSIX_DEFAULT_ACL - 64) +#define FATTR4_WORD2_POSIX_ACCESS_ACL BIT(FATTR4_POSIX_ACCESS_ACL - 64) /* MDS threshold bitmap bits */ #define THRESHOLD_RD (1UL << 0) -- 2.49.0 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v2 2/8] Add entries to the predefined client operations enum 2026-01-03 23:40 [PATCH v2 0/8] Add NFSv4.2 POSIX ACL support to the client rick.macklem 2026-01-03 23:40 ` [PATCH v2 1/8] Add definitions for the POSIX draft ACL attributes rick.macklem @ 2026-01-03 23:40 ` rick.macklem 2026-01-03 23:40 ` [PATCH v2 3/8] Add new entries for handling POSIX draft ACLs rick.macklem ` (5 subsequent siblings) 7 siblings, 0 replies; 12+ messages in thread From: rick.macklem @ 2026-01-03 23:40 UTC (permalink / raw) To: linux-nfs; +Cc: Rick Macklem From: Rick Macklem <rmacklem@uoguelph.ca> Add entries to the predefined Linux client operations to get/set POSIX draft ACLs. Signed-off-by: Rick Macklem <rmacklem@uoguelph.ca> --- include/linux/nfs4.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index 9d70a5e6a8d0..25f89d1c8ef2 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h @@ -732,6 +732,8 @@ enum { NFSPROC4_CLNT_REMOVEXATTR, NFSPROC4_CLNT_READ_PLUS, NFSPROC4_CLNT_OFFLOAD_STATUS, + NFSPROC4_CLNT_GETPOSIXACL, + NFSPROC4_CLNT_SETPOSIXACL, }; /* nfs41 types */ -- 2.49.0 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v2 3/8] Add new entries for handling POSIX draft ACLs 2026-01-03 23:40 [PATCH v2 0/8] Add NFSv4.2 POSIX ACL support to the client rick.macklem 2026-01-03 23:40 ` [PATCH v2 1/8] Add definitions for the POSIX draft ACL attributes rick.macklem 2026-01-03 23:40 ` [PATCH v2 2/8] Add entries to the predefined client operations enum rick.macklem @ 2026-01-03 23:40 ` rick.macklem 2026-01-03 23:40 ` [PATCH v2 4/8] Make posix_acl_from_nfsacl() global rick.macklem ` (4 subsequent siblings) 7 siblings, 0 replies; 12+ messages in thread From: rick.macklem @ 2026-01-03 23:40 UTC (permalink / raw) To: linux-nfs; +Cc: Rick Macklem From: Rick Macklem <rmacklem@uoguelph.ca> Add structures and definitions for the handling of POSIX draft ACLs for the NFS client. Signed-off-by: Rick Macklem <rmacklem@uoguelph.ca> --- include/linux/nfs_xdr.h | 57 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 79fe2dfb470f..e787de158fd9 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -1622,6 +1622,54 @@ struct nfs42_removexattrres { struct nfs4_change_info cinfo; }; +struct nfs42_getposixaclargs { + struct nfs4_sequence_args seq_args; + struct nfs_fh * fh; + int mask; + struct page ** pages; +}; + +struct nfs42_getposixaclres { + struct nfs4_sequence_res seq_res; + const struct nfs_server * server; + int mask; + unsigned int acl_access_count; + unsigned int acl_default_count; + struct posix_acl * acl_access; + struct posix_acl * acl_default; +}; + +struct nfs42_setposixaclargs { + struct nfs4_sequence_args seq_args; + struct nfs_fh * fh; + const struct nfs_server * server; + struct inode * inode; + int mask; + struct posix_acl * acl_access; + struct posix_acl * acl_default; + size_t len; + struct page ** pages; +}; + +struct nfs42_setposixaclres { + struct nfs4_sequence_res seq_res; + const struct nfs_server * server; +}; + +/* + * An NFSv4.2 POSIX draft ACL consists of: + * - an ACE cnt + * - 4 basic ACEs, which usually have a who string of 0 length + * - additional ACEs with who strings of up to IDMAP_NAMESZ + * - the above are 4byte quantities. + * All of the above is multiplied by 2, for the case where a directory + * has both a default and access ACL. + */ +#define NFS4_ACL_INLINE_BUFSIZE (2*(((1+NFS_ACL_MAX_ENTRIES_INLINE*3)*4)+ \ + (NFS_ACL_MAX_ENTRIES_INLINE-4)*IDMAP_NAMESZ)) +#define NFS4_ACL_MAXPAGES (((2*(4+(3*4+IDMAP_NAMESZ)* \ + NFS_ACL_MAX_ENTRIES))+PAGE_SIZE-1)>>PAGE_SHIFT) + #endif /* CONFIG_NFS_V4_2 */ struct nfs_page; @@ -1765,6 +1813,15 @@ struct nfs_renamedata { bool cancelled; }; +struct nfs_xdr_putpage_desc { + struct page **pages; + void *p; + void *endp; + size_t npages; + size_t page_pos; + size_t max_npages; +}; + struct nfs_access_entry; struct nfs_client; struct rpc_timeout; -- 2.49.0 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v2 4/8] Make posix_acl_from_nfsacl() global 2026-01-03 23:40 [PATCH v2 0/8] Add NFSv4.2 POSIX ACL support to the client rick.macklem ` (2 preceding siblings ...) 2026-01-03 23:40 ` [PATCH v2 3/8] Add new entries for handling POSIX draft ACLs rick.macklem @ 2026-01-03 23:40 ` rick.macklem 2026-01-03 23:40 ` [PATCH v2 5/8] Make three functions global and move them to acl.c rick.macklem ` (3 subsequent siblings) 7 siblings, 0 replies; 12+ messages in thread From: rick.macklem @ 2026-01-03 23:40 UTC (permalink / raw) To: linux-nfs; +Cc: Rick Macklem From: Rick Macklem <rmacklem@uoguelph.ca> The function posix_acl_from_nfsacl() needs to be called from the NFSv4.2 client code handling the POSIX draft ACL extensions. Signed-off-by: Rick Macklem <rmacklem@uoguelph.ca> --- fs/nfs_common/nfsacl.c | 3 ++- include/linux/nfsacl.h | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/nfs_common/nfsacl.c b/fs/nfs_common/nfsacl.c index e2eaac14fd8e..2ef7038b8d69 100644 --- a/fs/nfs_common/nfsacl.c +++ b/fs/nfs_common/nfsacl.c @@ -289,7 +289,7 @@ cmp_acl_entry(const void *x, const void *y) /* * Convert from a Solaris ACL to a POSIX 1003.1e draft 17 ACL. */ -static int +int posix_acl_from_nfsacl(struct posix_acl *acl) { struct posix_acl_entry *pa, *pe, @@ -325,6 +325,7 @@ posix_acl_from_nfsacl(struct posix_acl *acl) } return 0; } +EXPORT_SYMBOL_GPL(posix_acl_from_nfsacl); /** * nfsacl_decode - Decode an NFSv3 ACL diff --git a/include/linux/nfsacl.h b/include/linux/nfsacl.h index 8e76a79cdc6a..f068160bfdc5 100644 --- a/include/linux/nfsacl.h +++ b/include/linux/nfsacl.h @@ -44,5 +44,7 @@ nfs_stream_decode_acl(struct xdr_stream *xdr, unsigned int *aclcnt, extern bool nfs_stream_encode_acl(struct xdr_stream *xdr, struct inode *inode, struct posix_acl *acl, int encode_entries, int typeflag); +extern int +posix_acl_from_nfsacl(struct posix_acl *acl); #endif /* __LINUX_NFSACL_H */ -- 2.49.0 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v2 5/8] Make three functions global and move them to acl.c 2026-01-03 23:40 [PATCH v2 0/8] Add NFSv4.2 POSIX ACL support to the client rick.macklem ` (3 preceding siblings ...) 2026-01-03 23:40 ` [PATCH v2 4/8] Make posix_acl_from_nfsacl() global rick.macklem @ 2026-01-03 23:40 ` rick.macklem 2026-01-03 23:40 ` [PATCH v2 6/8] Make nfs4_server_supports_acls() global rick.macklem ` (2 subsequent siblings) 7 siblings, 0 replies; 12+ messages in thread From: rick.macklem @ 2026-01-03 23:40 UTC (permalink / raw) To: linux-nfs; +Cc: Rick Macklem From: Rick Macklem <rmacklem@uoguelph.ca> The three functions: nfs3_prepare_get_acl() nfs3_complete_get_acl() nfs3_abort_get_acl() have been moved to a new file called nfs34acl.c and renamed nfs34_XXX(), so that they can be called from the NFSv4.2 client code implementing the POSIX draft ACL attributes. Signed-off-by: Rick Macklem <rmacklem@uoguelph.ca> --- fs/nfs/Makefile | 2 +- fs/nfs/nfs.h | 3 +++ fs/nfs/nfs34acl.c | 40 ++++++++++++++++++++++++++++++++++++++++ fs/nfs/nfs3acl.c | 44 +++++++------------------------------------- 4 files changed, 51 insertions(+), 38 deletions(-) create mode 100644 fs/nfs/nfs34acl.c diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile index 9fb2f2cac87e..afb84c44a019 100644 --- a/fs/nfs/Makefile +++ b/fs/nfs/Makefile @@ -9,7 +9,7 @@ CFLAGS_nfstrace.o += -I$(src) nfs-y := client.o dir.o file.o getroot.o inode.o super.o \ io.o direct.o pagelist.o read.o symlink.o unlink.o \ write.o namespace.o mount_clnt.o nfstrace.o \ - export.o sysfs.o fs_context.o + export.o sysfs.o fs_context.o nfs34acl.o nfs-$(CONFIG_ROOT_NFS) += nfsroot.o nfs-$(CONFIG_SYSCTL) += sysctl.o nfs-$(CONFIG_NFS_FSCACHE) += fscache.o diff --git a/fs/nfs/nfs.h b/fs/nfs/nfs.h index 8a5f51be013a..b5d1cfb92ab1 100644 --- a/fs/nfs/nfs.h +++ b/fs/nfs/nfs.h @@ -26,5 +26,8 @@ int get_nfs_version(struct nfs_subversion *); void put_nfs_version(struct nfs_subversion *); void register_nfs_version(struct nfs_subversion *); void unregister_nfs_version(struct nfs_subversion *); +void nfs34_prepare_get_acl(struct posix_acl **); +void nfs34_complete_get_acl(struct posix_acl **, struct posix_acl *); +void nfs34_abort_get_acl(struct posix_acl **); #endif /* __LINUX_INTERNAL_NFS_H */ diff --git a/fs/nfs/nfs34acl.c b/fs/nfs/nfs34acl.c new file mode 100644 index 000000000000..e3322f222c53 --- /dev/null +++ b/fs/nfs/nfs34acl.c @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/fs.h> +#include <linux/nfs_fs.h> +#include <linux/posix_acl.h> + +#include "nfs.h" + +/* + * nfs34_prepare_get_acl, nfs34_complete_get_acl, nfs34_abort_get_acl: Helpers + * for caching get_acl results in a race-free way. See fs/posix_acl.c:get_acl() + * for explanations. + */ +void nfs34_prepare_get_acl(struct posix_acl **p) +{ + struct posix_acl *sentinel = uncached_acl_sentinel(current); + + /* If the ACL isn't being read yet, set our sentinel. */ + cmpxchg(p, ACL_NOT_CACHED, sentinel); +} +EXPORT_SYMBOL_GPL(nfs34_prepare_get_acl); + +void nfs34_complete_get_acl(struct posix_acl **p, struct posix_acl *acl) +{ + struct posix_acl *sentinel = uncached_acl_sentinel(current); + + /* Only cache the ACL if our sentinel is still in place. */ + posix_acl_dup(acl); + if (cmpxchg(p, sentinel, acl) != sentinel) + posix_acl_release(acl); +} +EXPORT_SYMBOL_GPL(nfs34_complete_get_acl); + +void nfs34_abort_get_acl(struct posix_acl **p) +{ + struct posix_acl *sentinel = uncached_acl_sentinel(current); + + /* Remove our sentinel upon failure. */ + cmpxchg(p, sentinel, ACL_NOT_CACHED); +} +EXPORT_SYMBOL_GPL(nfs34_abort_get_acl); diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c index a126eb31f62f..61aa56a632e3 100644 --- a/fs/nfs/nfs3acl.c +++ b/fs/nfs/nfs3acl.c @@ -8,41 +8,11 @@ #include <linux/nfsacl.h> #include "internal.h" +#include "nfs.h" #include "nfs3_fs.h" #define NFSDBG_FACILITY NFSDBG_PROC -/* - * nfs3_prepare_get_acl, nfs3_complete_get_acl, nfs3_abort_get_acl: Helpers for - * caching get_acl results in a race-free way. See fs/posix_acl.c:get_acl() - * for explanations. - */ -static void nfs3_prepare_get_acl(struct posix_acl **p) -{ - struct posix_acl *sentinel = uncached_acl_sentinel(current); - - /* If the ACL isn't being read yet, set our sentinel. */ - cmpxchg(p, ACL_NOT_CACHED, sentinel); -} - -static void nfs3_complete_get_acl(struct posix_acl **p, struct posix_acl *acl) -{ - struct posix_acl *sentinel = uncached_acl_sentinel(current); - - /* Only cache the ACL if our sentinel is still in place. */ - posix_acl_dup(acl); - if (cmpxchg(p, sentinel, acl) != sentinel) - posix_acl_release(acl); -} - -static void nfs3_abort_get_acl(struct posix_acl **p) -{ - struct posix_acl *sentinel = uncached_acl_sentinel(current); - - /* Remove our sentinel upon failure. */ - cmpxchg(p, sentinel, ACL_NOT_CACHED); -} - struct posix_acl *nfs3_get_acl(struct inode *inode, int type, bool rcu) { struct nfs_server *server = NFS_SERVER(inode); @@ -91,9 +61,9 @@ struct posix_acl *nfs3_get_acl(struct inode *inode, int type, bool rcu) return ERR_PTR(-ENOMEM); if (args.mask & NFS_ACL) - nfs3_prepare_get_acl(&inode->i_acl); + nfs34_prepare_get_acl(&inode->i_acl); if (args.mask & NFS_DFACL) - nfs3_prepare_get_acl(&inode->i_default_acl); + nfs34_prepare_get_acl(&inode->i_default_acl); status = rpc_call_sync(server->client_acl, &msg, 0); dprintk("NFS reply getacl: %d\n", status); @@ -131,12 +101,12 @@ struct posix_acl *nfs3_get_acl(struct inode *inode, int type, bool rcu) } if (res.mask & NFS_ACL) - nfs3_complete_get_acl(&inode->i_acl, res.acl_access); + nfs34_complete_get_acl(&inode->i_acl, res.acl_access); else forget_cached_acl(inode, ACL_TYPE_ACCESS); if (res.mask & NFS_DFACL) - nfs3_complete_get_acl(&inode->i_default_acl, res.acl_default); + nfs34_complete_get_acl(&inode->i_default_acl, res.acl_default); else forget_cached_acl(inode, ACL_TYPE_DEFAULT); @@ -150,8 +120,8 @@ struct posix_acl *nfs3_get_acl(struct inode *inode, int type, bool rcu) } getout: - nfs3_abort_get_acl(&inode->i_acl); - nfs3_abort_get_acl(&inode->i_default_acl); + nfs34_abort_get_acl(&inode->i_acl); + nfs34_abort_get_acl(&inode->i_default_acl); posix_acl_release(res.acl_access); posix_acl_release(res.acl_default); nfs_free_fattr(res.fattr); -- 2.49.0 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v2 6/8] Make nfs4_server_supports_acls() global 2026-01-03 23:40 [PATCH v2 0/8] Add NFSv4.2 POSIX ACL support to the client rick.macklem ` (4 preceding siblings ...) 2026-01-03 23:40 ` [PATCH v2 5/8] Make three functions global and move them to acl.c rick.macklem @ 2026-01-03 23:40 ` rick.macklem 2026-01-03 23:40 ` [PATCH v2 7/8] Set SB_POSIXACL if the server supports the extension rick.macklem 2026-01-03 23:40 ` [PATCH v2 8/8] Add support for the NFSv4.2 POSIX draft ACL attributes rick.macklem 7 siblings, 0 replies; 12+ messages in thread From: rick.macklem @ 2026-01-03 23:40 UTC (permalink / raw) To: linux-nfs; +Cc: Rick Macklem From: Rick Macklem <rmacklem@uoguelph.ca> Add support for the POSIX draft ACL attributes to nfs4_server_supports_acls() and make it global, so that support for POSIX draft ACLs can be checked in nfs4proc.c. Signed-off-by: Rick Macklem <rmacklem@uoguelph.ca> --- fs/nfs/nfs4_fs.h | 2 ++ fs/nfs/nfs4proc.c | 6 +++++- include/linux/nfs_xdr.h | 2 ++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index c34c89af9c7d..19e3398d50f7 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -337,6 +337,8 @@ extern void nfs4_update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo, unsigned long timestamp, unsigned long cache_validity); +extern bool nfs4_server_supports_acls(const struct nfs_server *server, + enum nfs4_acl_type type); extern int nfs4_buf_to_pages_noslab(const void *buf, size_t buflen, struct page **pages); diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index ec1ce593dea2..3057622ed61a 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -6069,7 +6069,7 @@ static int nfs4_proc_renew(struct nfs_client *clp, const struct cred *cred) return 0; } -static bool nfs4_server_supports_acls(const struct nfs_server *server, +bool nfs4_server_supports_acls(const struct nfs_server *server, enum nfs4_acl_type type) { switch (type) { @@ -6079,6 +6079,10 @@ static bool nfs4_server_supports_acls(const struct nfs_server *server, return server->attr_bitmask[1] & FATTR4_WORD1_DACL; case NFS4ACL_SACL: return server->attr_bitmask[1] & FATTR4_WORD1_SACL; + case NFS4ACL_POSIXDEFAULT: + return server->attr_bitmask[2] & FATTR4_WORD2_POSIX_DEFAULT_ACL; + case NFS4ACL_POSIXACCESS: + return server->attr_bitmask[2] & FATTR4_WORD2_POSIX_ACCESS_ACL; } } diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index e787de158fd9..1c21a1aac56f 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -832,6 +832,8 @@ enum nfs4_acl_type { NFS4ACL_ACL, NFS4ACL_DACL, NFS4ACL_SACL, + NFS4ACL_POSIXDEFAULT, + NFS4ACL_POSIXACCESS, }; struct nfs_setaclargs { -- 2.49.0 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v2 7/8] Set SB_POSIXACL if the server supports the extension 2026-01-03 23:40 [PATCH v2 0/8] Add NFSv4.2 POSIX ACL support to the client rick.macklem ` (5 preceding siblings ...) 2026-01-03 23:40 ` [PATCH v2 6/8] Make nfs4_server_supports_acls() global rick.macklem @ 2026-01-03 23:40 ` rick.macklem 2026-01-05 22:00 ` Anna Schumaker 2026-01-03 23:40 ` [PATCH v2 8/8] Add support for the NFSv4.2 POSIX draft ACL attributes rick.macklem 7 siblings, 1 reply; 12+ messages in thread From: rick.macklem @ 2026-01-03 23:40 UTC (permalink / raw) To: linux-nfs; +Cc: Rick Macklem From: Rick Macklem <rmacklem@uoguelph.ca> Check to see if both the POSIX draft default ACL and POSIX draft access ACL are supported by the server. If so, set SB_POSIXACL. Signed-off-by: Rick Macklem <rmacklem@uoguelph.ca> --- fs/nfs/super.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 57d372db03b9..aa0f53c3d01d 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -1352,6 +1352,11 @@ int nfs_get_tree_common(struct fs_context *fc) goto error_splat_super; } + /* Set SB_POSIXACL if the server supports the NFSv4.2 extension. */ + if ((server->attr_bitmask[2] & FATTR4_WORD2_POSIX_DEFAULT_ACL) && + (server->attr_bitmask[2] & FATTR4_WORD2_POSIX_ACCESS_ACL)) + s->s_flags |= SB_POSIXACL; + s->s_flags |= SB_ACTIVE; error = 0; -- 2.49.0 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH v2 7/8] Set SB_POSIXACL if the server supports the extension 2026-01-03 23:40 ` [PATCH v2 7/8] Set SB_POSIXACL if the server supports the extension rick.macklem @ 2026-01-05 22:00 ` Anna Schumaker 2026-01-05 23:56 ` Rick Macklem 0 siblings, 1 reply; 12+ messages in thread From: Anna Schumaker @ 2026-01-05 22:00 UTC (permalink / raw) To: rick.macklem, linux-nfs; +Cc: Rick Macklem Hi Rick, On 1/3/26 6:40 PM, rick.macklem@gmail.com wrote: > From: Rick Macklem <rmacklem@uoguelph.ca> > > Check to see if both the POSIX draft default ACL and > POSIX draft access ACL are supported by the server. > If so, set SB_POSIXACL. > > Signed-off-by: Rick Macklem <rmacklem@uoguelph.ca> > --- > fs/nfs/super.c | 5 +++++ > 1 file changed, 5 insertions(+) > > diff --git a/fs/nfs/super.c b/fs/nfs/super.c > index 57d372db03b9..aa0f53c3d01d 100644 > --- a/fs/nfs/super.c > +++ b/fs/nfs/super.c > @@ -1352,6 +1352,11 @@ int nfs_get_tree_common(struct fs_context *fc) > goto error_splat_super; > } > > + /* Set SB_POSIXACL if the server supports the NFSv4.2 extension. */ > + if ((server->attr_bitmask[2] & FATTR4_WORD2_POSIX_DEFAULT_ACL) && > + (server->attr_bitmask[2] & FATTR4_WORD2_POSIX_ACCESS_ACL)) > + s->s_flags |= SB_POSIXACL; Just a heads up that server->attr_bitmask only exists if the kernel is configured with CONFIG_NFS_V4=y, so the compiler will complain about this: fs/nfs/super.c:1348:15: error: no member named 'attr_bitmask' in 'struct nfs_server' 1348 | if ((server->attr_bitmask[2] & FATTR4_WORD2_POSIX_DEFAULT_ACL) && | ~~~~~~ ^ fs/nfs/super.c:1349:15: error: no member named 'attr_bitmask' in 'struct nfs_server' 1349 | (server->attr_bitmask[2] & FATTR4_WORD2_POSIX_ACCESS_ACL)) | ~~~~~~ ^ 2 errors generated. You'll probably need to either move it into NFS v4 specific code or hide it behind and #ifdef. Thanks, Anna > + > s->s_flags |= SB_ACTIVE; > error = 0; > ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v2 7/8] Set SB_POSIXACL if the server supports the extension 2026-01-05 22:00 ` Anna Schumaker @ 2026-01-05 23:56 ` Rick Macklem 0 siblings, 0 replies; 12+ messages in thread From: Rick Macklem @ 2026-01-05 23:56 UTC (permalink / raw) To: Anna Schumaker; +Cc: linux-nfs, Rick Macklem On Mon, Jan 5, 2026 at 2:02 PM Anna Schumaker <anna.schumaker@oracle.com> wrote: > > Hi Rick, > > On 1/3/26 6:40 PM, rick.macklem@gmail.com wrote: > > From: Rick Macklem <rmacklem@uoguelph.ca> > > > > Check to see if both the POSIX draft default ACL and > > POSIX draft access ACL are supported by the server. > > If so, set SB_POSIXACL. > > > > Signed-off-by: Rick Macklem <rmacklem@uoguelph.ca> > > --- > > fs/nfs/super.c | 5 +++++ > > 1 file changed, 5 insertions(+) > > > > diff --git a/fs/nfs/super.c b/fs/nfs/super.c > > index 57d372db03b9..aa0f53c3d01d 100644 > > --- a/fs/nfs/super.c > > +++ b/fs/nfs/super.c > > @@ -1352,6 +1352,11 @@ int nfs_get_tree_common(struct fs_context *fc) > > goto error_splat_super; > > } > > > > + /* Set SB_POSIXACL if the server supports the NFSv4.2 extension. */ > > + if ((server->attr_bitmask[2] & FATTR4_WORD2_POSIX_DEFAULT_ACL) && > > + (server->attr_bitmask[2] & FATTR4_WORD2_POSIX_ACCESS_ACL)) > > + s->s_flags |= SB_POSIXACL; > > Just a heads up that server->attr_bitmask only exists if the kernel is configured > with CONFIG_NFS_V4=y, so the compiler will complain about this: > > fs/nfs/super.c:1348:15: error: no member named 'attr_bitmask' in 'struct nfs_server' > 1348 | if ((server->attr_bitmask[2] & FATTR4_WORD2_POSIX_DEFAULT_ACL) && > | ~~~~~~ ^ > fs/nfs/super.c:1349:15: error: no member named 'attr_bitmask' in 'struct nfs_server' > 1349 | (server->attr_bitmask[2] & FATTR4_WORD2_POSIX_ACCESS_ACL)) > | ~~~~~~ ^ > 2 errors generated. > > You'll probably need to either move it into NFS v4 specific code or hide it behind > and #ifdef. I think hiding it behind an #ifdef is the obvious solution. (Why would anyone not want NFSv4;-) (I cannot see how the NFSv4 specific code gets called when the superblock gets set up. I know that the generic superblock code cannot call anything in the NFSv4 code. Already made that mistake and ended up with a cycle in the module dependencies.) I can repost the patch in a couple of weeks. (I have limited access to the Linux system I run at home until end of March.) If you happen to be inspired to do so, you are welcome to fix it. Thanks for letting me know, rick > > Thanks, > Anna > > > + > > s->s_flags |= SB_ACTIVE; > > error = 0; > > > ^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v2 8/8] Add support for the NFSv4.2 POSIX draft ACL attributes 2026-01-03 23:40 [PATCH v2 0/8] Add NFSv4.2 POSIX ACL support to the client rick.macklem ` (6 preceding siblings ...) 2026-01-03 23:40 ` [PATCH v2 7/8] Set SB_POSIXACL if the server supports the extension rick.macklem @ 2026-01-03 23:40 ` rick.macklem 7 siblings, 0 replies; 12+ messages in thread From: rick.macklem @ 2026-01-03 23:40 UTC (permalink / raw) To: linux-nfs; +Cc: Rick Macklem From: Rick Macklem <rmacklem@uoguelph.ca> The internet draft "POSIX Draft ACL support for Network File System Version 4, Minor Version 2" describes four new attributes that are extensions to the NFSv4.2 protocol. These new attributes provide support for POSIX draft ACLs without any need for mapping to/from NFSv4 ACLs. This extension allows the getfacl(1)/setfacl(1) commands to work over an NFSv4.2 mount where the client and server support the extension. This patch adds new procedures for getting/setting POSIX draft ACLs, along with the XDR encoding/decoding needed for the attributes. Signed-off-by: Rick Macklem <rmacklem@uoguelph.ca> --- fs/nfs/nfs42proc.c | 304 +++++++++++++++++++++ fs/nfs/nfs42xdr.c | 642 +++++++++++++++++++++++++++++++++++++++++++++ fs/nfs/nfs4_fs.h | 7 + fs/nfs/nfs4proc.c | 12 +- fs/nfs/nfs4xdr.c | 2 + 5 files changed, 965 insertions(+), 2 deletions(-) diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c index d537fb0c230e..52a06e031fce 100644 --- a/fs/nfs/nfs42proc.c +++ b/fs/nfs/nfs42proc.c @@ -11,10 +11,12 @@ #include <linux/nfs_xdr.h> #include <linux/nfs_fs.h> #include "nfs4_fs.h" +#include "nfs.h" #include "nfs42.h" #include "iostat.h" #include "pnfs.h" #include "nfs4session.h" +#include "nfs4idmap.h" #include "internal.h" #include "delegation.h" #include "nfs4trace.h" @@ -1638,6 +1640,308 @@ ssize_t nfs42_proc_listxattrs(struct inode *inode, void *buf, return err; } +static int _nfs4_proc_getposixacl(struct nfs42_getposixaclargs *arg, + struct nfs42_getposixaclres *res, + struct rpc_message *msg, + struct nfs_server *server, + struct inode *inode) +{ + struct nfs4_exception exception = { + .interruptible = true, + }; + int err; + do { + err = nfs4_call_sync(server->client, server, msg, + &arg->seq_args, &res->seq_res, 0); + err = nfs4_handle_exception(server, err, + &exception); + } while (exception.retry); + return err; +} + +struct posix_acl *nfs4_get_posixacl(struct inode *inode, int type, bool rcu) +{ + struct nfs_server *server = NFS_SERVER(inode); + struct page *pages[NFS4_ACL_MAXPAGES] = { }; + struct nfs42_getposixaclargs args = { + .fh = NFS_FH(inode), + /* The xdr layer may allocate pages here. */ + .pages = pages, + }; + struct nfs42_getposixaclres res = { + .server = server, + }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETPOSIXACL], + .rpc_argp = &args, + .rpc_resp = &res, + }; + int status, count; + + if (rcu) + return ERR_PTR(-ECHILD); + + /* + * Check that NFS4ACL_POSIXDEFAULT and NFS4ACL_POSIXACCESS + * attributes are supported by the server. + * We get acl_trueform and return EOPNOTSUPP if the acl_trueform + * is not POSIX_DRAFT_ACL. This allows the case where the + * acl_trueform's scope is file object to work when the acl_trueform + * is not POSIX_DRAFT_ACL. + */ + if (!nfs4_server_supports_acls(server, NFS4ACL_POSIXDEFAULT) || + !nfs4_server_supports_acls(server, NFS4ACL_POSIXACCESS)) + return ERR_PTR(-EOPNOTSUPP); + + status = nfs_revalidate_inode(inode, NFS_INO_INVALID_CHANGE); + if (status < 0) + return ERR_PTR(status); + + /* + * Only get the access acl when explicitly requested: We don't + * need it for access decisions, and only some applications use + * it. Applications which request the access acl first are not + * penalized from this optimization. + */ + if (type == ACL_TYPE_ACCESS) + args.mask |= NFS_ACLCNT|NFS_ACL; + if (S_ISDIR(inode->i_mode)) + args.mask |= NFS_DFACLCNT|NFS_DFACL; + if (args.mask == 0) + return NULL; + + if (args.mask & NFS_ACL) + nfs34_prepare_get_acl(&inode->i_acl); + if (args.mask & NFS_DFACL) + nfs34_prepare_get_acl(&inode->i_default_acl); + + status = _nfs4_proc_getposixacl(&args, &res, &msg, server, inode); + + /* pages may have been allocated at the xdr layer. */ + for (count = 0; count < NFS4_ACL_MAXPAGES && args.pages[count]; count++) + __free_page(args.pages[count]); + + switch (status) { + case 0: + break; + case -EPFNOSUPPORT: + case -EPROTONOSUPPORT: + fallthrough; + case -ENOTSUPP: + status = -EOPNOTSUPP; + goto getout; + default: + goto getout; + } + if ((args.mask & res.mask) != args.mask) { + status = -EIO; + goto getout; + } + + if (res.acl_access != NULL) { + if ((posix_acl_equiv_mode(res.acl_access, NULL) == 0) || + res.acl_access->a_count == 0) { + posix_acl_release(res.acl_access); + res.acl_access = NULL; + } + } + + if (res.mask & NFS_ACL) + nfs34_complete_get_acl(&inode->i_acl, res.acl_access); + else + forget_cached_acl(inode, ACL_TYPE_ACCESS); + + if (res.mask & NFS_DFACL) + nfs34_complete_get_acl(&inode->i_default_acl, res.acl_default); + else + forget_cached_acl(inode, ACL_TYPE_DEFAULT); + + if (type == ACL_TYPE_ACCESS) { + posix_acl_release(res.acl_default); + return res.acl_access; + } else { + posix_acl_release(res.acl_access); + return res.acl_default; + } + +getout: + nfs34_abort_get_acl(&inode->i_acl); + nfs34_abort_get_acl(&inode->i_default_acl); + posix_acl_release(res.acl_access); + posix_acl_release(res.acl_default); + return ERR_PTR(status); +} + +static int _nfs4_set_posixacl(struct inode *inode, struct posix_acl *acl, + struct posix_acl *dfacl) +{ + struct nfs_server *server = NFS_SERVER(inode); + struct page *pages[NFS4_ACL_MAXPAGES]; + struct nfs42_setposixaclargs args = { + .server = NFS_SERVER(inode), + .fh = NFS_FH(inode), + .inode = inode, + .mask = NFS_ACL, + .acl_access = acl, + }; + struct nfs42_setposixaclres res = { + .server = server, + }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETPOSIXACL], + .rpc_argp = &args, + .rpc_resp = &res, + }; + struct nfs4_exception exception = { + .interruptible = true, + }; + struct nfs_xdr_putpage_desc desc = { + .pages = pages, + .max_npages = NFS4_ACL_MAXPAGES, + }; + size_t argslen; + int idmax, status = 0; + + if (acl == NULL && (!S_ISDIR(inode->i_mode) || dfacl == NULL)) + goto out; + + status = -EOPNOTSUPP; + /* + * Check that NFS4ACL_POSIXDEFAULT and NFS4ACL_POSIXACCESS + * attributes are supported by the server. + * We get acl_trueform and return EOPNOTSUPP if the acl_trueform + * is not POSIX_DRAFT_ACL. This allows the case where the + * acl_trueform's scope is file object to work when the acl_trueform + * is not POSIX_DRAFT_ACL. + */ + if (!nfs4_server_supports_acls(server, NFS4ACL_POSIXDEFAULT) || + !nfs4_server_supports_acls(server, NFS4ACL_POSIXACCESS)) + goto out; + + idmax = (XDR_QUADLEN(IDMAP_NAMESZ) << 2); + argslen = 0; + status = -ENOSPC; + if (acl != NULL) { + if (acl->a_count > NFS_ACL_MAX_ENTRIES) + goto out; + argslen += ((1 + (3 * acl->a_count)) << 2); + if (acl->a_count > 4) + argslen += (acl->a_count - 4) * idmax; + } + if (dfacl != NULL && dfacl->a_count > NFS_ACL_MAX_ENTRIES) + goto out; + if (S_ISDIR(inode->i_mode)) { + args.mask |= NFS_DFACL; + args.acl_default = dfacl; + if (dfacl != NULL) { + argslen += ((1 + (3 * dfacl->a_count)) << 2); + if (dfacl->a_count > 4) + argslen += (dfacl->a_count - 4) * idmax; + } else { + argslen += 4; + } + } + + do { + /* + * We do not know how many pages will be needed for a large ACL, + * so additional pages are allocated, as required. + */ + if (argslen > NFS4_ACL_INLINE_BUFSIZE) { + ssize_t ret, size; + + status = -ENOMEM; + size = 0; + if (args.mask & NFS_DFACL) + size = nfs42_encode_posixacl(server, &desc, + dfacl); + if (size < 0) + goto out_freepages; + if ((args.mask & NFS_ACL) && size >= 0) { + ret = nfs42_encode_posixacl(server, &desc, acl); + if (ret < 0) + goto out_freepages; + size += ret; + } + args.len = size; + args.pages = desc.pages; + } + + status = nfs4_call_sync(server->client, server, &msg, + &args.seq_args, &res.seq_res, 0); + status = nfs4_handle_exception(server, status, &exception); + if (exception.retry) { + /* Reset to beginning of page array. */ + desc.page_pos = 0; + desc.p = NULL; + desc.endp = NULL; + } + } while (exception.retry); + nfs_access_zap_cache(inode); + nfs_zap_acl_cache(inode); + + switch (status) { + case 0: + break; + case -EPFNOSUPPORT: + case -EPROTONOSUPPORT: + dprintk("NFS_V4_ACL SETACL RPC not supported" + "(will not retry)\n"); + server->caps &= ~NFS_CAP_ACLS; + fallthrough; + case -ENOTSUPP: + status = -EOPNOTSUPP; + } +out_freepages: + if (desc.npages > 0) + nfs_xdr_putpage_cleanup(&desc); +out: + return status; +} + +int nfs4_set_posixacl(struct mnt_idmap *idmap, struct dentry *dentry, + struct posix_acl *acl, int type) +{ + struct posix_acl *orig = acl, *dfacl = NULL, *alloc; + struct inode *inode = d_inode(dentry); + int status; + + if (S_ISDIR(inode->i_mode)) { + switch(type) { + case ACL_TYPE_ACCESS: + alloc = get_inode_acl(inode, ACL_TYPE_DEFAULT); + if (IS_ERR(alloc)) + goto fail; + dfacl = alloc; + break; + case ACL_TYPE_DEFAULT: + alloc = get_inode_acl(inode, ACL_TYPE_ACCESS); + if (IS_ERR(alloc)) + goto fail; + dfacl = acl; + acl = alloc; + } + } + + if (acl == NULL) { + alloc = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); + if (IS_ERR(alloc)) + goto fail; + acl = alloc; + } + status = _nfs4_set_posixacl(inode, acl, dfacl); +out: + if (acl != orig) + posix_acl_release(acl); + if (dfacl != orig) + posix_acl_release(dfacl); + return status; + +fail: + status = PTR_ERR(alloc); + goto out; +} + int nfs42_proc_removexattr(struct inode *inode, const char *name) { struct nfs4_exception exception = { }; diff --git a/fs/nfs/nfs42xdr.c b/fs/nfs/nfs42xdr.c index e10d83ba835e..3c92cdbceb0e 100644 --- a/fs/nfs/nfs42xdr.c +++ b/fs/nfs/nfs42xdr.c @@ -269,6 +269,33 @@ decode_putfh_maxsz + \ decode_removexattr_maxsz) +#define encode_getposixacl_maxsz (encode_getattr_maxsz) +#define decode_getposixacl_maxsz (op_decode_hdr_maxsz + \ + nfs4_fattr_bitmap_maxsz + \ + XDR_QUADLEN(NFS4_ACL_INLINE_BUFSIZE) + \ + pagepad_maxsz) +#define encode_setposixacl_maxsz (op_encode_hdr_maxsz + \ + encode_stateid_maxsz + \ + nfs4_fattr_bitmap_maxsz + 1 + \ + XDR_QUADLEN(NFS4_ACL_INLINE_BUFSIZE)) +#define decode_setposixacl_maxsz (decode_setattr_maxsz) +#define NFS4_enc_getposixacl_sz (compound_encode_hdr_maxsz + \ + encode_sequence_maxsz + \ + encode_putfh_maxsz + \ + encode_getposixacl_maxsz) +#define NFS4_dec_getposixacl_sz (compound_decode_hdr_maxsz + \ + decode_sequence_maxsz + \ + decode_putfh_maxsz + \ + decode_getposixacl_maxsz) +#define NFS4_enc_setposixacl_sz (compound_encode_hdr_maxsz + \ + encode_sequence_maxsz + \ + encode_putfh_maxsz + \ + encode_setposixacl_maxsz) +#define NFS4_dec_setposixacl_sz (compound_decode_hdr_maxsz + \ + decode_sequence_maxsz + \ + decode_putfh_maxsz + \ + decode_setposixacl_maxsz) + /* * These values specify the maximum amount of data that is not * associated with the extended attribute name or extended @@ -1797,6 +1824,621 @@ static int nfs4_xdr_dec_listxattrs(struct rpc_rqst *rqstp, return status; } +static int +nfsacl4_posix_tagtotype(u32 tag) +{ + int type; + + switch(tag) { + case ACL_USER_OBJ: + type = POSIXACE4_TAG_USER_OBJ; + break; + case ACL_GROUP_OBJ: + type = POSIXACE4_TAG_GROUP_OBJ; + break; + case ACL_USER: + type = POSIXACE4_TAG_USER; + break; + case ACL_GROUP: + type = POSIXACE4_TAG_GROUP; + break; + case ACL_MASK: + type = POSIXACE4_TAG_MASK; + break; + case ACL_OTHER: + type = POSIXACE4_TAG_OTHER; + break; + default: + return -EINVAL; + } + return type; +} + +static int xdr_nfs4ace_stream_encode(struct xdr_stream *xdr, + const struct nfs_server *server, + struct posix_acl_entry *acep) +{ + char owner[IDMAP_NAMESZ]; + int len, size, type; + + type = nfsacl4_posix_tagtotype(acep->e_tag); + if (type < 0) + return -EINVAL; + if (xdr_stream_encode_u32(xdr, type) < 0) + return -EINVAL; + if (xdr_stream_encode_u32(xdr, acep->e_perm) < 0) + return -EINVAL; + size = 2 * XDR_UNIT; + switch(acep->e_tag) { + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_MASK: + case ACL_OTHER: + if (xdr_stream_encode_u32(xdr, 0) < 0) + return -EINVAL; + size += XDR_UNIT; + break; + case ACL_USER: + len = nfs_map_uid_to_name(server, acep->e_uid, owner, + IDMAP_NAMESZ); + if (len < 0) { + dprintk("nfs: couldn't resolve uid %d to str\n", + from_kuid(&init_user_ns, acep->e_uid)); + return -EINVAL; + } + if (xdr_stream_encode_opaque(xdr, owner, len) < 0) + return -EINVAL; + size += XDR_UNIT + (XDR_QUADLEN(len) << 2); + break; + case ACL_GROUP: + len = nfs_map_gid_to_group(server, acep->e_gid, owner, + IDMAP_NAMESZ); + if (len < 0) { + dprintk("nfs: couldn't resolve gid %d to str\n", + from_kgid(&init_user_ns, acep->e_gid)); + return -EINVAL; + } + if (xdr_stream_encode_opaque(xdr, owner, len) < 0) + return -EINVAL; + size += XDR_UNIT + (XDR_QUADLEN(len) << 2); + break; + default: + return -EINVAL; + } + return size; +} + +static int encode_stream_posixacl(struct xdr_stream *xdr, struct posix_acl *acl, + const struct nfs_server *server) +{ + unsigned int cnt; + int ret, size; + + if (acl == NULL) { + if (xdr_stream_encode_u32(xdr, 0) < 0) + return -EINVAL; + return XDR_UNIT; + } + if (acl->a_count > NFS_ACL_MAX_ENTRIES) + return -EINVAL; + if (xdr_stream_encode_u32(xdr, acl->a_count) < 0) + return -EINVAL; + size = XDR_UNIT; + + for (cnt = 0; cnt < acl->a_count; cnt++) { + ret = xdr_nfs4ace_stream_encode(xdr, server, + &acl->a_entries[cnt]); + if (ret < 0) + return ret; + size += ret; + } + + return size; +} + +static bool nfs_xdr_putpage_bytes(struct nfs_xdr_putpage_desc *desc, + void *bytes, size_t len) +{ + size_t tmp, xfer; + + while (len > 0) { + if (desc->p == desc->endp) { + /* Need to move on to the next page. */ + if (desc->page_pos == desc->npages) { + /* Needs a new page. */ + if (desc->npages == desc->max_npages) + return false; + desc->pages[desc->npages] = + alloc_page(GFP_KERNEL); + if (desc->pages[desc->npages] == NULL) + return false; + desc->npages++; + } + desc->p = page_address(desc->pages[desc->page_pos]); + desc->endp = desc->p + PAGE_SIZE; + desc->page_pos++; + } + tmp = desc->endp - desc->p; + xfer = (tmp < len) ? tmp : len; + memcpy(desc->p, bytes, xfer); + bytes += xfer; + desc->p += xfer; + len -= xfer; + } + return true; +} + +static bool nfs_xdr_putpage_word(struct nfs_xdr_putpage_desc *desc, u32 val) +{ + __be32 beval; + + beval = cpu_to_be32(val); + return nfs_xdr_putpage_bytes(desc, &beval, sizeof(beval)); +} + +void nfs_xdr_putpage_cleanup(struct nfs_xdr_putpage_desc *desc) +{ + + while (desc->npages != 0) { + desc->npages--; + __free_page(desc->pages[desc->npages]); + } +} + +static ssize_t xdr_nfs4ace_encode(const struct nfs_server *server, + struct nfs_xdr_putpage_desc *desc, struct posix_acl_entry *acep) +{ + char owner[IDMAP_NAMESZ]; + ssize_t len, size; + int type; + + type = nfsacl4_posix_tagtotype(acep->e_tag); + if (type < 0) + return -EINVAL; + if (!nfs_xdr_putpage_word(desc, type)) + return -EINVAL; + if (!nfs_xdr_putpage_word(desc, acep->e_perm)) + return -EINVAL; + size = 2 * XDR_UNIT; + switch(acep->e_tag) { + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_MASK: + case ACL_OTHER: + if (!nfs_xdr_putpage_word(desc, 0)) + return -EINVAL; + size += XDR_UNIT; + break; + case ACL_USER: + len = nfs_map_uid_to_name(server, acep->e_uid, owner, + IDMAP_NAMESZ); + if (len < 0) { + dprintk("nfs: couldn't resolve uid %d to string\n", + from_kuid(&init_user_ns, acep->e_uid)); + return -EINVAL; + } + if (!nfs_xdr_putpage_word(desc, len)) + return -EINVAL; + size += XDR_UNIT; + while (len & 3) + owner[len++] = '\0'; + if (!nfs_xdr_putpage_bytes(desc, owner, len)) + return -EINVAL; + size += len; + break; + case ACL_GROUP: + len = nfs_map_gid_to_group(server, acep->e_gid, owner, + IDMAP_NAMESZ); + if (len < 0) { + dprintk("nfs: couldn't resolve gid %d to string\n", + from_kgid(&init_user_ns, acep->e_gid)); + return -EINVAL; + } + if (!nfs_xdr_putpage_word(desc, len)) + return -EINVAL; + size += XDR_UNIT; + while (len & 3) + owner[len++] = '\0'; + if (!nfs_xdr_putpage_bytes(desc, owner, len)) + return -EINVAL; + size += len; + break; + default: + return -EINVAL; + } + return size; +} + +ssize_t nfs42_encode_posixacl(const struct nfs_server *server, + struct nfs_xdr_putpage_desc *desc, struct posix_acl *acl) +{ + unsigned int cnt; + ssize_t ret, size; + + if (acl == NULL) { + if (!nfs_xdr_putpage_word(desc, 0)) + return -EINVAL; + return XDR_UNIT; + } + if (acl->a_count > NFS_ACL_MAX_ENTRIES) + return -EINVAL; + if (!nfs_xdr_putpage_word(desc, acl->a_count)) + return -EINVAL; + size = XDR_UNIT; + + for (cnt = 0; cnt < acl->a_count; cnt++) { + ret = xdr_nfs4ace_encode(server, desc, &acl->a_entries[cnt]); + if (ret < 0) + return ret; + size += ret; + } + + return size; +} + +static void encode_setposixacl(struct rpc_rqst *req, struct xdr_stream *xdr, + const struct nfs42_setposixaclargs *arg, + const struct nfs_server *server, + struct compound_hdr *hdr) +{ + uint32_t bitmap[3]; + __be32 *sizep; + ssize_t ret, size; + + bitmap[0] = 0; + bitmap[1] = 0; + bitmap[2] = 0; + if (arg->mask & NFS_ACL) + bitmap[2] |= FATTR4_WORD2_POSIX_ACCESS_ACL; + if (arg->mask & NFS_DFACL) + bitmap[2] |= FATTR4_WORD2_POSIX_DEFAULT_ACL; + + encode_op_hdr(xdr, OP_SETATTR, decode_setposixacl_maxsz, hdr); + encode_nfs4_stateid(xdr, &zero_stateid); + xdr_encode_bitmap4(xdr, bitmap, ARRAY_SIZE(bitmap)); + sizep = reserve_space(xdr, 4); + if (sizep != NULL) { + size = 0; + if (arg->len > 0) { + xdr_write_pages(xdr, arg->pages, 0, arg->len); + size = arg->len; + } else { + if (arg->mask & NFS_DFACL) + size = encode_stream_posixacl(xdr, + arg->acl_default, server); + if ((arg->mask & NFS_ACL) && size >= 0) { + ret = encode_stream_posixacl(xdr, + arg->acl_access, server); + if (ret > 0) + size += ret; + } + } + if (size >= 0) + *sizep = cpu_to_be32(size); + } +} + +/* + * Encode a GETPOSIXACL request + */ +static void nfs4_xdr_enc_getposixacl(struct rpc_rqst *req, + struct xdr_stream *xdr, const void *data) +{ + const struct nfs42_getposixaclargs *args = data; + struct compound_hdr hdr = { + .minorversion = nfs4_xdr_minorversion(&args->seq_args), + }; + uint32_t bitmask[3]; + int getacl_cnt; + + bitmask[0] = 0; + bitmask[1] = 0; + bitmask[2] = FATTR4_WORD2_ACL_TRUEFORM; + getacl_cnt = 0; + if (args->mask & (NFS_ACLCNT|NFS_ACL)) { + bitmask[2] |= FATTR4_WORD2_POSIX_ACCESS_ACL; + getacl_cnt++; + } + if (args->mask & (NFS_DFACLCNT|NFS_DFACL)) { + bitmask[2] |= FATTR4_WORD2_POSIX_DEFAULT_ACL; + getacl_cnt++; + } + encode_compound_hdr(xdr, req, &hdr); + encode_sequence(xdr, &args->seq_args, &hdr); + encode_putfh(xdr, args->fh, &hdr); + encode_getattr(xdr, bitmask, NULL, 3, &hdr); + + if (getacl_cnt > 0) { + rpc_prepare_reply_pages(req, args->pages, 0, + (NFS4_ACL_MAXPAGES * getacl_cnt) << + PAGE_SHIFT, NFS4_dec_getposixacl_sz - + pagepad_maxsz); + req->rq_rcv_buf.flags |= XDRBUF_SPARSE_PAGES; + } + encode_nops(&hdr); +} + +/* + * Encode a SETPOSIXACL request + */ +static void nfs4_xdr_enc_setposixacl(struct rpc_rqst *req, + struct xdr_stream *xdr, const void *data) +{ + const struct nfs42_setposixaclargs *args = data; + struct compound_hdr hdr = { + .minorversion = nfs4_xdr_minorversion(&args->seq_args), + }; + + encode_compound_hdr(xdr, req, &hdr); + encode_sequence(xdr, &args->seq_args, &hdr); + encode_putfh(xdr, args->fh, &hdr); + encode_setposixacl(req, xdr, args, args->server, &hdr); + encode_nops(&hdr); +} + +static bool +nfsacl4_posix_xdrtotag(struct xdr_stream *xdr, u32 *tag) +{ + u32 type; + int ret; + + ret = xdr_stream_decode_u32(xdr, &type); + if (ret < 0) + return false; + switch(type) { + case POSIXACE4_TAG_USER_OBJ: + *tag = ACL_USER_OBJ; + break; + case POSIXACE4_TAG_GROUP_OBJ: + *tag = ACL_GROUP_OBJ; + break; + case POSIXACE4_TAG_USER: + *tag = ACL_USER; + break; + case POSIXACE4_TAG_GROUP: + *tag = ACL_GROUP; + break; + case POSIXACE4_TAG_MASK: + *tag = ACL_MASK; + break; + case POSIXACE4_TAG_OTHER: + *tag = ACL_OTHER; + break; + default: + return false; + } + return true; +} + +struct nfsacl4_decode_desc { + unsigned int array_len; + unsigned int count; + struct posix_acl *acl; +}; + +static ssize_t +xdr_nfs4ace_decode(struct xdr_stream *xdr, const struct nfs_server *server, + struct nfsacl4_decode_desc *desc) +{ + struct posix_acl_entry *entry; + char *owner; + kuid_t uid; + kgid_t gid; + u32 val; + ssize_t ret; + + if (!desc->acl) { + desc->acl = posix_acl_alloc(desc->array_len, GFP_KERNEL); + if (!desc->acl) + return -ENOMEM; + desc->count = 0; + } + + entry = &desc->acl->a_entries[desc->count++]; + if (!nfsacl4_posix_xdrtotag(xdr, &val)) + return -EBADMSG; + entry->e_tag = val; + ret = xdr_stream_decode_u32(xdr, &val); + if (ret < 0) + return -EBADMSG; + if (val & ~S_IRWXO) + return -EINVAL; + entry->e_perm = val; + ret = xdr_stream_decode_opaque_inline(xdr, (void **)&owner, + IDMAP_NAMESZ); + if (ret < 0) + return -EBADMSG; + + switch(entry->e_tag) { + case ACL_USER: + if (ret == 0) + return -EBADMSG; + if (nfs_map_name_to_uid(server, owner, ret, &uid) == 0) + entry->e_uid = uid; + else + return -EINVAL; + break; + case ACL_GROUP: + if (ret == 0) + return -EBADMSG; + if (nfs_map_group_to_gid(server, owner, ret, &gid) == 0) + entry->e_gid = gid; + else + return -EINVAL; + } + + return (XDR_QUADLEN(ret) << 2) + 3 * XDR_UNIT; +} + +static ssize_t nfs_stream_decode_acl4(struct xdr_stream *xdr, + const struct nfs_server *server, unsigned int *aclcnt, + struct posix_acl **pacl) +{ + struct nfsacl4_decode_desc nfsacl_desc; + u32 entries, i; + ssize_t ret, retlen; + + ret = xdr_stream_decode_u32(xdr, &entries); + if (ret < 0) + return -EBADMSG; + if (entries > NFS_ACL_MAX_ENTRIES) + return -EINVAL; + retlen = XDR_UNIT; + + nfsacl_desc.array_len = entries; + nfsacl_desc.count = 0; + nfsacl_desc.acl = NULL; + for (i = 0; i < entries; i++) { + ret = xdr_nfs4ace_decode(xdr, server, &nfsacl_desc); + if (ret < 0) + return ret; + retlen += ret; + } + + if (pacl) { + if (posix_acl_from_nfsacl(nfsacl_desc.acl) != 0) { + posix_acl_release(nfsacl_desc.acl); + return -EINVAL; + } + *pacl = nfsacl_desc.acl; + } + if (aclcnt) + *aclcnt = entries; + return retlen; +} + +static int decode_getposixacl(struct xdr_stream *xdr, + struct nfs42_getposixaclres *res, + const struct nfs_server *server) +{ + uint32_t bitmap[3] = {0}; + u32 attrlen, attrsize, trueform; + char scratch_buf[IDMAP_NAMESZ]; + int status; + + status = decode_op_hdr(xdr, OP_GETATTR); + if (status < 0) + goto xdr_error; + + status = decode_attr_bitmap(xdr, bitmap); + if (status < 0) + goto xdr_error; + + if (bitmap[0] || bitmap[1] || + (bitmap[2] & ~(FATTR4_WORD2_POSIX_ACCESS_ACL | + FATTR4_WORD2_POSIX_DEFAULT_ACL | + FATTR4_WORD2_ACL_TRUEFORM))) { + status = -EBADMSG; + goto xdr_error; + } + + status = xdr_stream_decode_u32(xdr, &attrlen); + if (status < 0) + goto xdr_error; + + trueform = ACL_MODEL_NFS4; + if (bitmap[2] & FATTR4_WORD2_ACL_TRUEFORM) { + status = xdr_stream_decode_u32(xdr, &trueform); + if (status < 0) + goto xdr_error; + attrsize = XDR_UNIT; + } + + /* + * For a ACL_MODEL_NFS4 true form, return EOPNOTSUPP. + * Hopefully this error can be used by getfacl(1) to indicate + * that nfs4_getfacl(1) should be used. + */ + if (trueform == ACL_MODEL_NFS4) { + status = -EOPNOTSUPP; + goto xdr_error; + } + + xdr_set_scratch_buffer(xdr, &scratch_buf, sizeof(scratch_buf)); + res->mask = 0; + if (bitmap[2] & FATTR4_WORD2_POSIX_DEFAULT_ACL) { + status = nfs_stream_decode_acl4(xdr, server, + &res->acl_default_count, + &res->acl_default); + if (status < 0) + goto xdr_error2; + attrsize += status; + res->mask |= NFS_DFACL|NFS_DFACLCNT; + } + if (bitmap[2] & FATTR4_WORD2_POSIX_ACCESS_ACL) { + status = nfs_stream_decode_acl4(xdr, server, + &res->acl_access_count, + &res->acl_access); + if (status < 0) + goto xdr_error2; + attrsize += status; + res->mask |= NFS_ACL|NFS_ACLCNT; + } + status = 0; + + if (attrlen != attrsize) + status = -EBADMSG; +xdr_error2: + xdr_reset_scratch_buffer(xdr); +xdr_error: + dprintk("%s: xdr returned %d\n", __func__, -status); + return status; +} + +/* + * Decode GETPOSIXACL response + */ +static int +nfs4_xdr_dec_getposixacl(struct rpc_rqst *rqstp, struct xdr_stream *xdr, + void *data) +{ + struct nfs42_getposixaclres *res = data; + struct compound_hdr hdr; + int status; + + status = decode_compound_hdr(xdr, &hdr); + if (status) + goto out; + status = decode_sequence(xdr, &res->seq_res, rqstp); + if (status) + goto out; + status = decode_putfh(xdr); + if (status) + goto out; + status = decode_getposixacl(xdr, res, res->server); + +out: + return status; +} + +/* + * Decode SETPOSIXACL response + */ +static int nfs4_xdr_dec_setposixacl(struct rpc_rqst *rqstp, + struct xdr_stream *xdr, + void *data) +{ + struct nfs42_setposixaclres *res = data; + struct compound_hdr hdr; + int status; + + status = decode_compound_hdr(xdr, &hdr); + if (status) + goto out; + status = decode_sequence(xdr, &res->seq_res, rqstp); + if (status) + goto out; + status = decode_putfh(xdr); + if (status) + goto out; + status = decode_setattr(xdr); + if (status) + goto out; +out: + return status; +} + + /* * Decode REMOVEXATTR request */ diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 19e3398d50f7..54da0854ae02 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -660,6 +660,13 @@ extern void nfs4_xattr_cache_set_list(struct inode *inode, const char *buf, extern ssize_t nfs4_xattr_cache_list(struct inode *inode, char *buf, ssize_t buflen); extern void nfs4_xattr_cache_zap(struct inode *inode); +extern struct posix_acl *nfs4_get_posixacl(struct inode *inode, int type, + bool rcu); +extern int nfs4_set_posixacl(struct mnt_idmap *idmap, struct dentry *dentry, + struct posix_acl *acl, int type); +extern ssize_t nfs42_encode_posixacl(const struct nfs_server *server, + struct nfs_xdr_putpage_desc *desc, struct posix_acl *acl); +extern void nfs_xdr_putpage_cleanup(struct nfs_xdr_putpage_desc *desc); #else static inline void nfs4_xattr_cache_zap(struct inode *inode) { diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 3057622ed61a..f5d2f80e77e8 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -3955,7 +3955,7 @@ static void nfs4_close_context(struct nfs_open_context *ctx, int is_sync) #define FATTR4_WORD1_NFS40_MASK (2*FATTR4_WORD1_MOUNTED_ON_FILEID - 1UL) #define FATTR4_WORD2_NFS41_MASK (2*FATTR4_WORD2_SUPPATTR_EXCLCREAT - 1UL) -#define FATTR4_WORD2_NFS42_MASK (2*FATTR4_WORD2_OPEN_ARGUMENTS - 1UL) +#define FATTR4_WORD2_NFS42_MASK (2*FATTR4_WORD2_POSIX_ACCESS_ACL - 1UL) #define FATTR4_WORD2_NFS42_TIME_DELEG_MASK \ (FATTR4_WORD2_TIME_DELEG_MODIFY|FATTR4_WORD2_TIME_DELEG_ACCESS) @@ -4024,7 +4024,10 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f case 2: res.attr_bitmask[2] &= FATTR4_WORD2_NFS42_MASK; bitmask[2] = (FATTR4_WORD2_SUPPATTR_EXCLCREAT | - FATTR4_WORD2_OPEN_ARGUMENTS) & + FATTR4_WORD2_OPEN_ARGUMENTS | + FATTR4_WORD2_ACL_TRUEFORM | + FATTR4_WORD2_POSIX_DEFAULT_ACL | + FATTR4_WORD2_POSIX_ACCESS_ACL) & res.attr_bitmask[2]; } memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask)); @@ -6141,6 +6144,7 @@ static void nfs4_set_cached_acl(struct inode *inode, struct nfs4_cached_acl *acl static void nfs4_zap_acl_attr(struct inode *inode) { nfs4_set_cached_acl(inode, NULL); + forget_all_cached_acls(inode); } static ssize_t nfs4_read_cached_acl(struct inode *inode, char *buf, @@ -11045,6 +11049,8 @@ static const struct inode_operations nfs4_dir_inode_operations = { .getattr = nfs_getattr, .setattr = nfs_setattr, .listxattr = nfs4_listxattr, + .get_inode_acl = nfs4_get_posixacl, + .set_acl = nfs4_set_posixacl, }; static const struct inode_operations nfs4_file_inode_operations = { @@ -11052,6 +11058,8 @@ static const struct inode_operations nfs4_file_inode_operations = { .getattr = nfs_getattr, .setattr = nfs_setattr, .listxattr = nfs4_listxattr, + .get_inode_acl = nfs4_get_posixacl, + .set_acl = nfs4_set_posixacl, }; static struct nfs_server *nfs4_clone_server(struct nfs_server *source, diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index b6fe30577fab..549c81f2c196 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -7842,6 +7842,8 @@ const struct rpc_procinfo nfs4_procedures[] = { PROC42(REMOVEXATTR, enc_removexattr, dec_removexattr), PROC42(READ_PLUS, enc_read_plus, dec_read_plus), PROC42(ZERO_RANGE, enc_zero_range, dec_zero_range), + PROC42(GETPOSIXACL, enc_getposixacl, dec_getposixacl), + PROC42(SETPOSIXACL, enc_setposixacl, dec_setposixacl), }; static unsigned int nfs_version4_counts[ARRAY_SIZE(nfs4_procedures)]; -- 2.49.0 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v2 7/8] Set SB_POSIXACL if the server supports the extension @ 2026-01-14 1:01 rick.macklem 0 siblings, 0 replies; 12+ messages in thread From: rick.macklem @ 2026-01-14 1:01 UTC (permalink / raw) To: linux-nfs; +Cc: Rick Macklem From: Rick Macklem <rmacklem@uoguelph.ca> Check to see if both the POSIX draft default ACL and POSIX draft access ACL are supported by the server. If so, set SB_POSIXACL. Signed-off-by: Rick Macklem <rmacklem@uoguelph.ca> --- fs/nfs/super.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 57d372db03b9..04c40c9d783a 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -1352,6 +1352,13 @@ int nfs_get_tree_common(struct fs_context *fc) goto error_splat_super; } +#ifdef CONFIG_NFS_V4_2 + /* Set SB_POSIXACL if the server supports the NFSv4.2 extension. */ + if ((server->attr_bitmask[2] & FATTR4_WORD2_POSIX_DEFAULT_ACL) && + (server->attr_bitmask[2] & FATTR4_WORD2_POSIX_ACCESS_ACL)) + s->s_flags |= SB_POSIXACL; +#endif + s->s_flags |= SB_ACTIVE; error = 0; -- 2.49.0 ^ permalink raw reply related [flat|nested] 12+ messages in thread
end of thread, other threads:[~2026-01-14 1:02 UTC | newest] Thread overview: 12+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-01-03 23:40 [PATCH v2 0/8] Add NFSv4.2 POSIX ACL support to the client rick.macklem 2026-01-03 23:40 ` [PATCH v2 1/8] Add definitions for the POSIX draft ACL attributes rick.macklem 2026-01-03 23:40 ` [PATCH v2 2/8] Add entries to the predefined client operations enum rick.macklem 2026-01-03 23:40 ` [PATCH v2 3/8] Add new entries for handling POSIX draft ACLs rick.macklem 2026-01-03 23:40 ` [PATCH v2 4/8] Make posix_acl_from_nfsacl() global rick.macklem 2026-01-03 23:40 ` [PATCH v2 5/8] Make three functions global and move them to acl.c rick.macklem 2026-01-03 23:40 ` [PATCH v2 6/8] Make nfs4_server_supports_acls() global rick.macklem 2026-01-03 23:40 ` [PATCH v2 7/8] Set SB_POSIXACL if the server supports the extension rick.macklem 2026-01-05 22:00 ` Anna Schumaker 2026-01-05 23:56 ` Rick Macklem 2026-01-03 23:40 ` [PATCH v2 8/8] Add support for the NFSv4.2 POSIX draft ACL attributes rick.macklem -- strict thread matches above, loose matches on Subject: below -- 2026-01-14 1:01 [PATCH v2 7/8] Set SB_POSIXACL if the server supports the extension rick.macklem
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox