From: Mike Snitzer <snitzer@kernel.org>
To: Chuck Lever <chuck.lever@oracle.com>,
Jeff Layton <jlayton@kernel.org>,
Trond Myklebust <trond.myklebust@hammerspace.com>,
Anna Schumaker <anna.schumaker@oracle.com>
Cc: linux-nfs@vger.kernel.org
Subject: [RFC PATCH 10/11] NFSv4: add reexport support for GETACL nfs4_acl passthru
Date: Thu, 19 Feb 2026 17:13:51 -0500 [thread overview]
Message-ID: <20260219221352.40554-11-snitzer@kernel.org> (raw)
In-Reply-To: <20260219221352.40554-1-snitzer@kernel.org>
From: Mike Snitzer <snitzer@hammerspace.com>
Wire up the export_operations .getacl hook and use the upper layer
provided nfs4_acl's pages in the call to NFSPROC4_CLNT_GETACL.
In this reexporting case (e.g. 4.1 reexporting 4.2),
__nfs4_get_acl_uncached() is always used because the NFSv4 client's
cache is designed to reply with the buffer that gets generated from
the ACL's pages. So the frontend client (4.1) will cache the ACL
returned by the backend (4.2) client.
Signed-off-by: Mike Snitzer <snitzer@hammerspace.com>
---
fs/nfs/export.c | 10 ++++++
fs/nfs/nfs4proc.c | 79 ++++++++++++++++++++++++++++-------------
include/linux/nfs_xdr.h | 1 +
3 files changed, 65 insertions(+), 25 deletions(-)
diff --git a/fs/nfs/export.c b/fs/nfs/export.c
index 9a90eee3e433..6623eb13f4e6 100644
--- a/fs/nfs/export.c
+++ b/fs/nfs/export.c
@@ -161,11 +161,21 @@ static int nfs_set_nfs4_acl(struct inode *inode, struct nfs4_acl *acl)
return rpc_ops->set_nfs4_acl(inode, acl);
}
+static int nfs_get_nfs4_acl(struct inode *inode, struct nfs4_acl *acl)
+{
+ const struct nfs_rpc_ops *rpc_ops = NFS_SERVER(inode)->nfs_client->rpc_ops;
+
+ if (rpc_ops->get_nfs4_acl == NULL)
+ return -EOPNOTSUPP;
+ return rpc_ops->get_nfs4_acl(inode, acl);
+}
+
const struct export_operations nfs_export_ops = {
.encode_fh = nfs_encode_fh,
.fh_to_dentry = nfs_fh_to_dentry,
.get_parent = nfs_get_parent,
.setacl = nfs_set_nfs4_acl,
+ .getacl = nfs_get_nfs4_acl,
.flags = EXPORT_OP_NOWCC |
EXPORT_OP_NOSUBTREECHK |
EXPORT_OP_CLOSE_BEFORE_UNLINK |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index f97ef2d41e35..480c06b69296 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -6099,7 +6099,8 @@ static void nfs4_write_cached_acl(struct inode *inode, struct page **pages,
* the server, this time with the input buf of the required size.
*/
static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf,
- size_t buflen, enum nfs4_acl_type type)
+ size_t buflen, enum nfs4_acl_type type,
+ struct nfs4_acl *acl)
{
struct page **pages;
struct nfs_getaclargs args = {
@@ -6123,26 +6124,29 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf,
if (buflen == 0)
buflen = server->rsize;
- npages = DIV_ROUND_UP(buflen, PAGE_SIZE) + 1;
- pages = kmalloc_array(npages, sizeof(struct page *), GFP_KERNEL);
- if (!pages)
- return -ENOMEM;
+ if (!acl) {
+ npages = DIV_ROUND_UP(buflen, PAGE_SIZE) + 1;
+ pages = kmalloc_array(npages, sizeof(struct page *), GFP_KERNEL);
+ if (!pages)
+ return -ENOMEM;
+ for (i = 0; i < npages; i++) {
+ pages[i] = alloc_page(GFP_KERNEL);
+ if (!pages[i])
+ goto out_free;
+ }
+ args.acl_len = npages * PAGE_SIZE;
+ } else {
+ npages = DIV_ROUND_UP(buflen, PAGE_SIZE);
+ pages = acl->pages;
+ }
args.acl_pages = pages;
- for (i = 0; i < npages; i++) {
- pages[i] = alloc_page(GFP_KERNEL);
- if (!pages[i])
- goto out_free;
- }
-
/* for decoding across pages */
res.acl_scratch = folio_alloc(GFP_KERNEL, 0);
if (!res.acl_scratch)
goto out_free;
- args.acl_len = npages * PAGE_SIZE;
-
dprintk("%s buf %p buflen %zu npages %d args.acl_len %zu\n",
__func__, buf, buflen, npages, args.acl_len);
ret = nfs4_call_sync(NFS_SERVER(inode)->client, NFS_SERVER(inode),
@@ -6158,8 +6162,18 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf,
ret = -ERANGE;
goto out_free;
}
- nfs4_write_cached_acl(inode, pages, res.acl_data_offset, res.acl_len,
- type);
+
+ if (!acl) {
+ nfs4_write_cached_acl(inode, pages, res.acl_data_offset,
+ res.acl_len, type);
+ } else {
+ if (res.acl_len > buflen) {
+ ret = -ERANGE;
+ goto out_free;
+ }
+ acl->len = res.acl_len;
+ acl->pgbase = res.acl_data_offset;
+ }
if (buf) {
if (res.acl_len > buflen) {
ret = -ERANGE;
@@ -6170,23 +6184,26 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf,
out_ok:
ret = res.acl_len;
out_free:
- while (--i >= 0)
- __free_page(pages[i]);
+ if (!acl) {
+ while (--i >= 0)
+ __free_page(pages[i]);
+ kfree(pages);
+ }
if (res.acl_scratch)
folio_put(res.acl_scratch);
- kfree(pages);
return ret;
}
static ssize_t nfs4_get_acl_uncached(struct inode *inode, void *buf,
- size_t buflen, enum nfs4_acl_type type)
+ size_t buflen, enum nfs4_acl_type type,
+ struct nfs4_acl *acl)
{
struct nfs4_exception exception = {
.interruptible = true,
};
ssize_t ret;
do {
- ret = __nfs4_get_acl_uncached(inode, buf, buflen, type);
+ ret = __nfs4_get_acl_uncached(inode, buf, buflen, type, acl);
trace_nfs4_get_acl(inode, ret);
if (ret >= 0)
break;
@@ -6196,7 +6213,7 @@ static ssize_t nfs4_get_acl_uncached(struct inode *inode, void *buf,
}
static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen,
- enum nfs4_acl_type type)
+ enum nfs4_acl_type type, struct nfs4_acl *acl)
{
struct nfs_server *server = NFS_SERVER(inode);
int ret;
@@ -6210,12 +6227,23 @@ static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen,
return ret;
if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_ACL)
nfs_zap_acl_cache(inode);
+ /* Must get ACL if @acl != NULL, frontend NFS layer will cache it */
+ if (acl != NULL)
+ goto get_acl_uncached;
ret = nfs4_read_cached_acl(inode, buf, buflen, type);
if (ret != -ENOENT)
/* -ENOENT is returned if there is no ACL or if there is an ACL
* but no cached acl data, just the acl length */
return ret;
- return nfs4_get_acl_uncached(inode, buf, buflen, type);
+get_acl_uncached:
+ return nfs4_get_acl_uncached(inode, buf, buflen, type, acl);
+}
+
+static int nfs4_get_nfs4_acl(struct inode *inode, struct nfs4_acl *acl)
+{
+ if (!nfs4_server_supports_acls(NFS_SERVER(inode), acl->type))
+ return -EOPNOTSUPP;
+ return nfs4_proc_get_acl(inode, NULL, acl->len, acl->type, acl);
}
static int __nfs4_proc_set_acl(struct inode *inode, const void *buf,
@@ -7977,7 +8005,7 @@ static int nfs4_xattr_get_nfs4_acl(const struct xattr_handler *handler,
struct dentry *unused, struct inode *inode,
const char *key, void *buf, size_t buflen)
{
- return nfs4_proc_get_acl(inode, buf, buflen, NFS4ACL_ACL);
+ return nfs4_proc_get_acl(inode, buf, buflen, NFS4ACL_ACL, NULL);
}
static bool nfs4_xattr_list_nfs4_acl(struct dentry *dentry)
@@ -8001,7 +8029,7 @@ static int nfs4_xattr_get_nfs4_dacl(const struct xattr_handler *handler,
struct dentry *unused, struct inode *inode,
const char *key, void *buf, size_t buflen)
{
- return nfs4_proc_get_acl(inode, buf, buflen, NFS4ACL_DACL);
+ return nfs4_proc_get_acl(inode, buf, buflen, NFS4ACL_DACL, NULL);
}
static bool nfs4_xattr_list_nfs4_dacl(struct dentry *dentry)
@@ -8024,7 +8052,7 @@ static int nfs4_xattr_get_nfs4_sacl(const struct xattr_handler *handler,
struct dentry *unused, struct inode *inode,
const char *key, void *buf, size_t buflen)
{
- return nfs4_proc_get_acl(inode, buf, buflen, NFS4ACL_SACL);
+ return nfs4_proc_get_acl(inode, buf, buflen, NFS4ACL_SACL, NULL);
}
static bool nfs4_xattr_list_nfs4_sacl(struct dentry *dentry)
@@ -11041,6 +11069,7 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
.enable_swap = nfs4_enable_swap,
.disable_swap = nfs4_disable_swap,
.set_nfs4_acl = nfs4_set_nfs4_acl,
+ .get_nfs4_acl = nfs4_get_nfs4_acl,
};
static const struct xattr_handler nfs4_xattr_nfs4_acl_handler = {
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 47cb3b140640..4be2a40c7fc5 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -1848,6 +1848,7 @@ struct nfs_rpc_ops {
void (*enable_swap)(struct inode *inode);
void (*disable_swap)(struct inode *inode);
int (*set_nfs4_acl)(struct inode *, struct nfs4_acl *);
+ int (*get_nfs4_acl)(struct inode *, struct nfs4_acl *);
};
/*
--
2.44.0
next prev parent reply other threads:[~2026-02-19 22:14 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-19 22:13 [RFC PATCH 00/11] NFS/NFSD: nfs4_acl passthru for NFSv4 reexport Mike Snitzer
2026-02-19 22:13 ` [RFC PATCH 01/11] exportfs: add ability to advertise NFSv4 ACL passthru support Mike Snitzer
2026-02-19 22:13 ` [RFC PATCH 02/11] NFSD: factor out nfsd_supports_nfs4_acl() to nfsd/acl.h Mike Snitzer
2026-02-19 22:13 ` [RFC PATCH 03/11] NFS/NFSD: data structure enablement for nfs4_acl passthru support Mike Snitzer
2026-02-19 22:13 ` [RFC PATCH 04/11] NFSD: prepare to support SETACL nfs4_acl passthru Mike Snitzer
2026-02-19 22:13 ` [RFC PATCH 05/11] NFSD: add NFS4 reexport support for " Mike Snitzer
2026-02-19 22:13 ` [RFC PATCH 06/11] NFSD: add NFS4 reexport support for GETACL " Mike Snitzer
2026-02-19 22:13 ` [RFC PATCH 07/11] NFSD: add NFS4ACL_DACL and NFS4ACL_SACL passthru support Mike Snitzer
2026-02-19 22:13 ` [RFC PATCH 08/11] NFSD: avoid extra nfs4_acl passthru work unless needed Mike Snitzer
2026-02-19 22:13 ` [RFC PATCH 09/11] NFSv4: add reexport support for SETACL nfs4_acl passthru Mike Snitzer
2026-02-19 22:13 ` Mike Snitzer [this message]
2026-02-19 22:13 ` [RFC PATCH 11/11] NFSv4: set EXPORT_OP_NFSV4_ACL_PASSTHRU flag Mike Snitzer
2026-02-19 22:21 ` [RFC PATCH 00/11] NFS/NFSD: nfs4_acl passthru for NFSv4 reexport Chuck Lever
2026-02-19 23:07 ` Mike Snitzer
2026-02-20 15:46 ` Chuck Lever
2026-02-19 23:57 ` Trond Myklebust
2026-02-20 15:33 ` Chuck Lever
2026-02-22 17:53 ` Chuck Lever
2026-02-22 19:39 ` Mike Snitzer
2026-02-22 20:31 ` Chuck Lever
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260219221352.40554-11-snitzer@kernel.org \
--to=snitzer@kernel.org \
--cc=anna.schumaker@oracle.com \
--cc=chuck.lever@oracle.com \
--cc=jlayton@kernel.org \
--cc=linux-nfs@vger.kernel.org \
--cc=trond.myklebust@hammerspace.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox