The filecache infrastructure will only handle S_IFREG files at the
moment. Directory delegations will require adding support for opening
S_IFDIR inodes.
Plumb a "type" argument into nfsd_file_do_acquire() and have all of the
existing callers set it to S_IFREG. Add a new nfsd_file_acquire_dir()
wrapper that nfsd can call to request a nfsd_file that holds a directory
open.
For now, there is no need for a fsnotify_mark for directories, as
CB_NOTIFY is not yet supported. Change nfsd_file_do_acquire() to avoid
allocating one for non-S_IFREG inodes.
Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
fs/nfsd/filecache.c | 57 ++++++++++++++++++++++++++++++++++++++++-------------
fs/nfsd/filecache.h | 2 ++
fs/nfsd/vfs.c | 5 +++--
fs/nfsd/vfs.h | 2 +-
4 files changed, 49 insertions(+), 17 deletions(-)
diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c
index a238b6725008a5c2988bd3da874d1f34ee778437..93798575b8075c63f95cd415b6d24df706ada0f6 100644
--- a/fs/nfsd/filecache.c
+++ b/fs/nfsd/filecache.c
@@ -1086,7 +1086,7 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct net *net,
struct auth_domain *client,
struct svc_fh *fhp,
unsigned int may_flags, struct file *file,
- struct nfsd_file **pnf, bool want_gc)
+ umode_t type, bool want_gc, struct nfsd_file **pnf)
{
unsigned char need = may_flags & NFSD_FILE_MAY_MASK;
struct nfsd_file *new, *nf;
@@ -1097,13 +1097,13 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct net *net,
int ret;
retry:
- if (rqstp) {
- status = fh_verify(rqstp, fhp, S_IFREG,
+ if (rqstp)
+ status = fh_verify(rqstp, fhp, type,
may_flags|NFSD_MAY_OWNER_OVERRIDE);
- } else {
- status = fh_verify_local(net, cred, client, fhp, S_IFREG,
+ else
+ status = fh_verify_local(net, cred, client, fhp, type,
may_flags|NFSD_MAY_OWNER_OVERRIDE);
- }
+
if (status != nfs_ok)
return status;
inode = d_inode(fhp->fh_dentry);
@@ -1176,15 +1176,18 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct net *net,
open_file:
trace_nfsd_file_alloc(nf);
- nf->nf_mark = nfsd_file_mark_find_or_create(inode);
- if (nf->nf_mark) {
+
+ if (type == S_IFREG)
+ nf->nf_mark = nfsd_file_mark_find_or_create(inode);
+
+ if (type != S_IFREG || nf->nf_mark) {
if (file) {
get_file(file);
nf->nf_file = file;
status = nfs_ok;
trace_nfsd_file_opened(nf, status);
} else {
- ret = nfsd_open_verified(fhp, may_flags, &nf->nf_file);
+ ret = nfsd_open_verified(fhp, type, may_flags, &nf->nf_file);
if (ret == -EOPENSTALE && stale_retry) {
stale_retry = false;
nfsd_file_unhash(nf);
@@ -1246,7 +1249,7 @@ nfsd_file_acquire_gc(struct svc_rqst *rqstp, struct svc_fh *fhp,
unsigned int may_flags, struct nfsd_file **pnf)
{
return nfsd_file_do_acquire(rqstp, SVC_NET(rqstp), NULL, NULL,
- fhp, may_flags, NULL, pnf, true);
+ fhp, may_flags, NULL, S_IFREG, true, pnf);
}
/**
@@ -1271,7 +1274,7 @@ nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
unsigned int may_flags, struct nfsd_file **pnf)
{
return nfsd_file_do_acquire(rqstp, SVC_NET(rqstp), NULL, NULL,
- fhp, may_flags, NULL, pnf, false);
+ fhp, may_flags, NULL, S_IFREG, false, pnf);
}
/**
@@ -1314,8 +1317,8 @@ nfsd_file_acquire_local(struct net *net, struct svc_cred *cred,
const struct cred *save_cred = get_current_cred();
__be32 beres;
- beres = nfsd_file_do_acquire(NULL, net, cred, client,
- fhp, may_flags, NULL, pnf, false);
+ beres = nfsd_file_do_acquire(NULL, net, cred, client, fhp, may_flags,
+ NULL, S_IFREG, false, pnf);
put_cred(revert_creds(save_cred));
return beres;
}
@@ -1344,7 +1347,33 @@ nfsd_file_acquire_opened(struct svc_rqst *rqstp, struct svc_fh *fhp,
struct nfsd_file **pnf)
{
return nfsd_file_do_acquire(rqstp, SVC_NET(rqstp), NULL, NULL,
- fhp, may_flags, file, pnf, false);
+ fhp, may_flags, file, S_IFREG, false, pnf);
+}
+
+/**
+ * nfsd_file_acquire_dir - Get a struct nfsd_file with an open directory
+ * @rqstp: the RPC transaction being executed
+ * @fhp: the NFS filehandle of the file to be opened
+ * @pnf: OUT: new or found "struct nfsd_file" object
+ *
+ * The nfsd_file_object returned by this API is reference-counted
+ * but not garbage-collected. The object is unhashed after the
+ * final nfsd_file_put(). This opens directories only, and only
+ * in O_RDONLY mode.
+ *
+ * Return values:
+ * %nfs_ok - @pnf points to an nfsd_file with its reference
+ * count boosted.
+ *
+ * On error, an nfsstat value in network byte order is returned.
+ */
+__be32
+nfsd_file_acquire_dir(struct svc_rqst *rqstp, struct svc_fh *fhp,
+ struct nfsd_file **pnf)
+{
+ return nfsd_file_do_acquire(rqstp, SVC_NET(rqstp), NULL, NULL, fhp,
+ NFSD_MAY_READ|NFSD_MAY_64BIT_COOKIE,
+ NULL, S_IFDIR, false, pnf);
}
/*
diff --git a/fs/nfsd/filecache.h b/fs/nfsd/filecache.h
index e3d6ca2b60308e5e91ba4bb32d935f54527d8bda..b383dbc5b9218d21a29b852572f80fab08de9fa9 100644
--- a/fs/nfsd/filecache.h
+++ b/fs/nfsd/filecache.h
@@ -82,5 +82,7 @@ __be32 nfsd_file_acquire_opened(struct svc_rqst *rqstp, struct svc_fh *fhp,
__be32 nfsd_file_acquire_local(struct net *net, struct svc_cred *cred,
struct auth_domain *client, struct svc_fh *fhp,
unsigned int may_flags, struct nfsd_file **pnf);
+__be32 nfsd_file_acquire_dir(struct svc_rqst *rqstp, struct svc_fh *fhp,
+ struct nfsd_file **pnf);
int nfsd_file_cache_stats_show(struct seq_file *m, void *v);
#endif /* _FS_NFSD_FILECACHE_H */
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index eeb138569eba5df6de361cf6ba29604722e14af9..12c33223b612664dbb3b18b591e97fc708165763 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -959,15 +959,16 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type,
/**
* nfsd_open_verified - Open a regular file for the filecache
* @fhp: NFS filehandle of the file to open
+ * @type: S_IFMT inode type allowed (0 means any type is allowed)
* @may_flags: internal permission flags
* @filp: OUT: open "struct file *"
*
* Returns zero on success, or a negative errno value.
*/
int
-nfsd_open_verified(struct svc_fh *fhp, int may_flags, struct file **filp)
+nfsd_open_verified(struct svc_fh *fhp, umode_t type, int may_flags, struct file **filp)
{
- return __nfsd_open(fhp, S_IFREG, may_flags, filp);
+ return __nfsd_open(fhp, type, may_flags, filp);
}
/*
diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h
index fa46f8b5f132079e3a2c45e71ecf9cc43181f6b0..ded2900d423f80d33fb6c8b809bc5d9fc842ebfd 100644
--- a/fs/nfsd/vfs.h
+++ b/fs/nfsd/vfs.h
@@ -114,7 +114,7 @@ __be32 nfsd_setxattr(struct svc_rqst *rqstp, struct svc_fh *fhp,
int nfsd_open_break_lease(struct inode *, int);
__be32 nfsd_open(struct svc_rqst *, struct svc_fh *, umode_t,
int, struct file **);
-int nfsd_open_verified(struct svc_fh *fhp, int may_flags,
+int nfsd_open_verified(struct svc_fh *fhp, umode_t type, int may_flags,
struct file **filp);
__be32 nfsd_splice_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
struct file *file, loff_t offset,
--
2.51.0
On 10/17/25 7:32 AM, Jeff Layton wrote:
> The filecache infrastructure will only handle S_IFREG files at the
> moment. Directory delegations will require adding support for opening
> S_IFDIR inodes.
>
> Plumb a "type" argument into nfsd_file_do_acquire() and have all of the
> existing callers set it to S_IFREG. Add a new nfsd_file_acquire_dir()
> wrapper that nfsd can call to request a nfsd_file that holds a directory
> open.
>
> For now, there is no need for a fsnotify_mark for directories, as
> CB_NOTIFY is not yet supported. Change nfsd_file_do_acquire() to avoid
> allocating one for non-S_IFREG inodes.
>
> Signed-off-by: Jeff Layton <jlayton@kernel.org>
> ---
> fs/nfsd/filecache.c | 57 ++++++++++++++++++++++++++++++++++++++++-------------
> fs/nfsd/filecache.h | 2 ++
> fs/nfsd/vfs.c | 5 +++--
> fs/nfsd/vfs.h | 2 +-
> 4 files changed, 49 insertions(+), 17 deletions(-)
>
> diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c
> index a238b6725008a5c2988bd3da874d1f34ee778437..93798575b8075c63f95cd415b6d24df706ada0f6 100644
> --- a/fs/nfsd/filecache.c
> +++ b/fs/nfsd/filecache.c
> @@ -1086,7 +1086,7 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct net *net,
> struct auth_domain *client,
> struct svc_fh *fhp,
> unsigned int may_flags, struct file *file,
> - struct nfsd_file **pnf, bool want_gc)
> + umode_t type, bool want_gc, struct nfsd_file **pnf)
> {
> unsigned char need = may_flags & NFSD_FILE_MAY_MASK;
> struct nfsd_file *new, *nf;
> @@ -1097,13 +1097,13 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct net *net,
> int ret;
>
> retry:
> - if (rqstp) {
> - status = fh_verify(rqstp, fhp, S_IFREG,
> + if (rqstp)
> + status = fh_verify(rqstp, fhp, type,
> may_flags|NFSD_MAY_OWNER_OVERRIDE);
> - } else {
> - status = fh_verify_local(net, cred, client, fhp, S_IFREG,
> + else
> + status = fh_verify_local(net, cred, client, fhp, type,
> may_flags|NFSD_MAY_OWNER_OVERRIDE);
> - }
> +
> if (status != nfs_ok)
> return status;
> inode = d_inode(fhp->fh_dentry);
> @@ -1176,15 +1176,18 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct net *net,
>
> open_file:
> trace_nfsd_file_alloc(nf);
> - nf->nf_mark = nfsd_file_mark_find_or_create(inode);
> - if (nf->nf_mark) {
> +
> + if (type == S_IFREG)
> + nf->nf_mark = nfsd_file_mark_find_or_create(inode);
> +
> + if (type != S_IFREG || nf->nf_mark) {
> if (file) {
> get_file(file);
> nf->nf_file = file;
> status = nfs_ok;
> trace_nfsd_file_opened(nf, status);
> } else {
> - ret = nfsd_open_verified(fhp, may_flags, &nf->nf_file);
> + ret = nfsd_open_verified(fhp, type, may_flags, &nf->nf_file);
> if (ret == -EOPENSTALE && stale_retry) {
> stale_retry = false;
> nfsd_file_unhash(nf);
> @@ -1246,7 +1249,7 @@ nfsd_file_acquire_gc(struct svc_rqst *rqstp, struct svc_fh *fhp,
> unsigned int may_flags, struct nfsd_file **pnf)
> {
> return nfsd_file_do_acquire(rqstp, SVC_NET(rqstp), NULL, NULL,
> - fhp, may_flags, NULL, pnf, true);
> + fhp, may_flags, NULL, S_IFREG, true, pnf);
> }
>
> /**
> @@ -1271,7 +1274,7 @@ nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
> unsigned int may_flags, struct nfsd_file **pnf)
> {
> return nfsd_file_do_acquire(rqstp, SVC_NET(rqstp), NULL, NULL,
> - fhp, may_flags, NULL, pnf, false);
> + fhp, may_flags, NULL, S_IFREG, false, pnf);
> }
>
> /**
> @@ -1314,8 +1317,8 @@ nfsd_file_acquire_local(struct net *net, struct svc_cred *cred,
> const struct cred *save_cred = get_current_cred();
> __be32 beres;
>
> - beres = nfsd_file_do_acquire(NULL, net, cred, client,
> - fhp, may_flags, NULL, pnf, false);
> + beres = nfsd_file_do_acquire(NULL, net, cred, client, fhp, may_flags,
> + NULL, S_IFREG, false, pnf);
> put_cred(revert_creds(save_cred));
> return beres;
> }
> @@ -1344,7 +1347,33 @@ nfsd_file_acquire_opened(struct svc_rqst *rqstp, struct svc_fh *fhp,
> struct nfsd_file **pnf)
> {
> return nfsd_file_do_acquire(rqstp, SVC_NET(rqstp), NULL, NULL,
> - fhp, may_flags, file, pnf, false);
> + fhp, may_flags, file, S_IFREG, false, pnf);
> +}
> +
> +/**
> + * nfsd_file_acquire_dir - Get a struct nfsd_file with an open directory
> + * @rqstp: the RPC transaction being executed
> + * @fhp: the NFS filehandle of the file to be opened
> + * @pnf: OUT: new or found "struct nfsd_file" object
> + *
> + * The nfsd_file_object returned by this API is reference-counted
> + * but not garbage-collected. The object is unhashed after the
> + * final nfsd_file_put(). This opens directories only, and only
> + * in O_RDONLY mode.
> + *
> + * Return values:
> + * %nfs_ok - @pnf points to an nfsd_file with its reference
> + * count boosted.
> + *
> + * On error, an nfsstat value in network byte order is returned.
> + */
> +__be32
> +nfsd_file_acquire_dir(struct svc_rqst *rqstp, struct svc_fh *fhp,
> + struct nfsd_file **pnf)
> +{
> + return nfsd_file_do_acquire(rqstp, SVC_NET(rqstp), NULL, NULL, fhp,
> + NFSD_MAY_READ|NFSD_MAY_64BIT_COOKIE,
> + NULL, S_IFDIR, false, pnf);
> }
>
> /*
> diff --git a/fs/nfsd/filecache.h b/fs/nfsd/filecache.h
> index e3d6ca2b60308e5e91ba4bb32d935f54527d8bda..b383dbc5b9218d21a29b852572f80fab08de9fa9 100644
> --- a/fs/nfsd/filecache.h
> +++ b/fs/nfsd/filecache.h
> @@ -82,5 +82,7 @@ __be32 nfsd_file_acquire_opened(struct svc_rqst *rqstp, struct svc_fh *fhp,
> __be32 nfsd_file_acquire_local(struct net *net, struct svc_cred *cred,
> struct auth_domain *client, struct svc_fh *fhp,
> unsigned int may_flags, struct nfsd_file **pnf);
> +__be32 nfsd_file_acquire_dir(struct svc_rqst *rqstp, struct svc_fh *fhp,
> + struct nfsd_file **pnf);
> int nfsd_file_cache_stats_show(struct seq_file *m, void *v);
> #endif /* _FS_NFSD_FILECACHE_H */
> diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
> index eeb138569eba5df6de361cf6ba29604722e14af9..12c33223b612664dbb3b18b591e97fc708165763 100644
> --- a/fs/nfsd/vfs.c
> +++ b/fs/nfsd/vfs.c
> @@ -959,15 +959,16 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type,
> /**
> * nfsd_open_verified - Open a regular file for the filecache
> * @fhp: NFS filehandle of the file to open
> + * @type: S_IFMT inode type allowed (0 means any type is allowed)
> * @may_flags: internal permission flags
> * @filp: OUT: open "struct file *"
> *
> * Returns zero on success, or a negative errno value.
> */
> int
> -nfsd_open_verified(struct svc_fh *fhp, int may_flags, struct file **filp)
> +nfsd_open_verified(struct svc_fh *fhp, umode_t type, int may_flags, struct file **filp)
> {
> - return __nfsd_open(fhp, S_IFREG, may_flags, filp);
> + return __nfsd_open(fhp, type, may_flags, filp);
> }
>
> /*
> diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h
> index fa46f8b5f132079e3a2c45e71ecf9cc43181f6b0..ded2900d423f80d33fb6c8b809bc5d9fc842ebfd 100644
> --- a/fs/nfsd/vfs.h
> +++ b/fs/nfsd/vfs.h
> @@ -114,7 +114,7 @@ __be32 nfsd_setxattr(struct svc_rqst *rqstp, struct svc_fh *fhp,
> int nfsd_open_break_lease(struct inode *, int);
> __be32 nfsd_open(struct svc_rqst *, struct svc_fh *, umode_t,
> int, struct file **);
> -int nfsd_open_verified(struct svc_fh *fhp, int may_flags,
> +int nfsd_open_verified(struct svc_fh *fhp, umode_t type, int may_flags,
> struct file **filp);
> __be32 nfsd_splice_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
> struct file *file, loff_t offset,
>
Reviewed-by: Chuck Lever <chuck.lever@oracle.com>
These can probably go in via Christian's tree. I don't think there
are going to be conflicts between these and what's in nfsd-testing
now.
--
Chuck Lever
On Sat, 2025-10-18 at 15:33 -0400, Chuck Lever wrote:
> On 10/17/25 7:32 AM, Jeff Layton wrote:
> > The filecache infrastructure will only handle S_IFREG files at the
> > moment. Directory delegations will require adding support for opening
> > S_IFDIR inodes.
> >
> > Plumb a "type" argument into nfsd_file_do_acquire() and have all of the
> > existing callers set it to S_IFREG. Add a new nfsd_file_acquire_dir()
> > wrapper that nfsd can call to request a nfsd_file that holds a directory
> > open.
> >
> > For now, there is no need for a fsnotify_mark for directories, as
> > CB_NOTIFY is not yet supported. Change nfsd_file_do_acquire() to avoid
> > allocating one for non-S_IFREG inodes.
> >
> > Signed-off-by: Jeff Layton <jlayton@kernel.org>
> > ---
> > fs/nfsd/filecache.c | 57 ++++++++++++++++++++++++++++++++++++++++-------------
> > fs/nfsd/filecache.h | 2 ++
> > fs/nfsd/vfs.c | 5 +++--
> > fs/nfsd/vfs.h | 2 +-
> > 4 files changed, 49 insertions(+), 17 deletions(-)
> >
> > diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c
> > index a238b6725008a5c2988bd3da874d1f34ee778437..93798575b8075c63f95cd415b6d24df706ada0f6 100644
> > --- a/fs/nfsd/filecache.c
> > +++ b/fs/nfsd/filecache.c
> > @@ -1086,7 +1086,7 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct net *net,
> > struct auth_domain *client,
> > struct svc_fh *fhp,
> > unsigned int may_flags, struct file *file,
> > - struct nfsd_file **pnf, bool want_gc)
> > + umode_t type, bool want_gc, struct nfsd_file **pnf)
> > {
> > unsigned char need = may_flags & NFSD_FILE_MAY_MASK;
> > struct nfsd_file *new, *nf;
> > @@ -1097,13 +1097,13 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct net *net,
> > int ret;
> >
> > retry:
> > - if (rqstp) {
> > - status = fh_verify(rqstp, fhp, S_IFREG,
> > + if (rqstp)
> > + status = fh_verify(rqstp, fhp, type,
> > may_flags|NFSD_MAY_OWNER_OVERRIDE);
> > - } else {
> > - status = fh_verify_local(net, cred, client, fhp, S_IFREG,
> > + else
> > + status = fh_verify_local(net, cred, client, fhp, type,
> > may_flags|NFSD_MAY_OWNER_OVERRIDE);
> > - }
> > +
> > if (status != nfs_ok)
> > return status;
> > inode = d_inode(fhp->fh_dentry);
> > @@ -1176,15 +1176,18 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct net *net,
> >
> > open_file:
> > trace_nfsd_file_alloc(nf);
> > - nf->nf_mark = nfsd_file_mark_find_or_create(inode);
> > - if (nf->nf_mark) {
> > +
> > + if (type == S_IFREG)
> > + nf->nf_mark = nfsd_file_mark_find_or_create(inode);
> > +
> > + if (type != S_IFREG || nf->nf_mark) {
> > if (file) {
> > get_file(file);
> > nf->nf_file = file;
> > status = nfs_ok;
> > trace_nfsd_file_opened(nf, status);
> > } else {
> > - ret = nfsd_open_verified(fhp, may_flags, &nf->nf_file);
> > + ret = nfsd_open_verified(fhp, type, may_flags, &nf->nf_file);
> > if (ret == -EOPENSTALE && stale_retry) {
> > stale_retry = false;
> > nfsd_file_unhash(nf);
> > @@ -1246,7 +1249,7 @@ nfsd_file_acquire_gc(struct svc_rqst *rqstp, struct svc_fh *fhp,
> > unsigned int may_flags, struct nfsd_file **pnf)
> > {
> > return nfsd_file_do_acquire(rqstp, SVC_NET(rqstp), NULL, NULL,
> > - fhp, may_flags, NULL, pnf, true);
> > + fhp, may_flags, NULL, S_IFREG, true, pnf);
> > }
> >
> > /**
> > @@ -1271,7 +1274,7 @@ nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
> > unsigned int may_flags, struct nfsd_file **pnf)
> > {
> > return nfsd_file_do_acquire(rqstp, SVC_NET(rqstp), NULL, NULL,
> > - fhp, may_flags, NULL, pnf, false);
> > + fhp, may_flags, NULL, S_IFREG, false, pnf);
> > }
> >
> > /**
> > @@ -1314,8 +1317,8 @@ nfsd_file_acquire_local(struct net *net, struct svc_cred *cred,
> > const struct cred *save_cred = get_current_cred();
> > __be32 beres;
> >
> > - beres = nfsd_file_do_acquire(NULL, net, cred, client,
> > - fhp, may_flags, NULL, pnf, false);
> > + beres = nfsd_file_do_acquire(NULL, net, cred, client, fhp, may_flags,
> > + NULL, S_IFREG, false, pnf);
> > put_cred(revert_creds(save_cred));
> > return beres;
> > }
> > @@ -1344,7 +1347,33 @@ nfsd_file_acquire_opened(struct svc_rqst *rqstp, struct svc_fh *fhp,
> > struct nfsd_file **pnf)
> > {
> > return nfsd_file_do_acquire(rqstp, SVC_NET(rqstp), NULL, NULL,
> > - fhp, may_flags, file, pnf, false);
> > + fhp, may_flags, file, S_IFREG, false, pnf);
> > +}
> > +
> > +/**
> > + * nfsd_file_acquire_dir - Get a struct nfsd_file with an open directory
> > + * @rqstp: the RPC transaction being executed
> > + * @fhp: the NFS filehandle of the file to be opened
> > + * @pnf: OUT: new or found "struct nfsd_file" object
> > + *
> > + * The nfsd_file_object returned by this API is reference-counted
> > + * but not garbage-collected. The object is unhashed after the
> > + * final nfsd_file_put(). This opens directories only, and only
> > + * in O_RDONLY mode.
> > + *
> > + * Return values:
> > + * %nfs_ok - @pnf points to an nfsd_file with its reference
> > + * count boosted.
> > + *
> > + * On error, an nfsstat value in network byte order is returned.
> > + */
> > +__be32
> > +nfsd_file_acquire_dir(struct svc_rqst *rqstp, struct svc_fh *fhp,
> > + struct nfsd_file **pnf)
> > +{
> > + return nfsd_file_do_acquire(rqstp, SVC_NET(rqstp), NULL, NULL, fhp,
> > + NFSD_MAY_READ|NFSD_MAY_64BIT_COOKIE,
> > + NULL, S_IFDIR, false, pnf);
> > }
> >
> > /*
> > diff --git a/fs/nfsd/filecache.h b/fs/nfsd/filecache.h
> > index e3d6ca2b60308e5e91ba4bb32d935f54527d8bda..b383dbc5b9218d21a29b852572f80fab08de9fa9 100644
> > --- a/fs/nfsd/filecache.h
> > +++ b/fs/nfsd/filecache.h
> > @@ -82,5 +82,7 @@ __be32 nfsd_file_acquire_opened(struct svc_rqst *rqstp, struct svc_fh *fhp,
> > __be32 nfsd_file_acquire_local(struct net *net, struct svc_cred *cred,
> > struct auth_domain *client, struct svc_fh *fhp,
> > unsigned int may_flags, struct nfsd_file **pnf);
> > +__be32 nfsd_file_acquire_dir(struct svc_rqst *rqstp, struct svc_fh *fhp,
> > + struct nfsd_file **pnf);
> > int nfsd_file_cache_stats_show(struct seq_file *m, void *v);
> > #endif /* _FS_NFSD_FILECACHE_H */
> > diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
> > index eeb138569eba5df6de361cf6ba29604722e14af9..12c33223b612664dbb3b18b591e97fc708165763 100644
> > --- a/fs/nfsd/vfs.c
> > +++ b/fs/nfsd/vfs.c
> > @@ -959,15 +959,16 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type,
> > /**
> > * nfsd_open_verified - Open a regular file for the filecache
> > * @fhp: NFS filehandle of the file to open
> > + * @type: S_IFMT inode type allowed (0 means any type is allowed)
> > * @may_flags: internal permission flags
> > * @filp: OUT: open "struct file *"
> > *
> > * Returns zero on success, or a negative errno value.
> > */
> > int
> > -nfsd_open_verified(struct svc_fh *fhp, int may_flags, struct file **filp)
> > +nfsd_open_verified(struct svc_fh *fhp, umode_t type, int may_flags, struct file **filp)
> > {
> > - return __nfsd_open(fhp, S_IFREG, may_flags, filp);
> > + return __nfsd_open(fhp, type, may_flags, filp);
> > }
> >
> > /*
> > diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h
> > index fa46f8b5f132079e3a2c45e71ecf9cc43181f6b0..ded2900d423f80d33fb6c8b809bc5d9fc842ebfd 100644
> > --- a/fs/nfsd/vfs.h
> > +++ b/fs/nfsd/vfs.h
> > @@ -114,7 +114,7 @@ __be32 nfsd_setxattr(struct svc_rqst *rqstp, struct svc_fh *fhp,
> > int nfsd_open_break_lease(struct inode *, int);
> > __be32 nfsd_open(struct svc_rqst *, struct svc_fh *, umode_t,
> > int, struct file **);
> > -int nfsd_open_verified(struct svc_fh *fhp, int may_flags,
> > +int nfsd_open_verified(struct svc_fh *fhp, umode_t type, int may_flags,
> > struct file **filp);
> > __be32 nfsd_splice_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
> > struct file *file, loff_t offset,
> >
>
> Reviewed-by: Chuck Lever <chuck.lever@oracle.com>
>
> These can probably go in via Christian's tree. I don't think there
> are going to be conflicts between these and what's in nfsd-testing
> now.
That would work. I think I have at least one more respin of the VFS
bits before we merge anything anyway.
--
Jeff Layton <jlayton@kernel.org>
© 2016 - 2026 Red Hat, Inc.