From: NeilBrown <neilb@suse.de>
To: Christoph Hellwig <hch@infradead.org>,
Josef Bacik <josef@toxicpanda.com>,
"J. Bruce Fields" <bfields@fieldses.org>,
Chuck Lever <chuck.lever@oracle.com>, Chris Mason <clm@fb.com>,
David Sterba <dsterba@suse.com>,
Alexander Viro <viro@zeniv.linux.org.uk>
Cc: linux-fsdevel@vger.kernel.org, linux-nfs@vger.kernel.org,
linux-btrfs@vger.kernel.org
Subject: [PATCH 06/11] nfsd: include a vfsmount in struct svc_fh
Date: Wed, 28 Jul 2021 08:37:45 +1000 [thread overview]
Message-ID: <162742546552.32498.8097200286954882080.stgit@noble.brown> (raw)
In-Reply-To: <162742539595.32498.13687924366155737575.stgit@noble.brown>
A future patch will allow exportfs_decode_fh{,_raw} to return a
different vfsmount than the one passed. This is specifically for btrfs,
but would be useful for any filesystem that presents as multiple volumes
(i.e. different st_dev, each with their own st_ino number-space).
For nfsd, this means that the mnt in the svc_export may not apply to all
filehandles reached from that export. So svc_fh needs to store a
distinct vfsmount as well.
For now, fs->fh_mnt == fh->fh_export->ex_path.mnt, but that will change.
Changes include:
fh_compose()
nfsd_lookup_dentry()
now take a *path instead of a *dentry
nfsd4_encode_fattr()
nfsd4_encode_fattr_to_buf()
now take a *vfsmount as well as a *dentry
nfsd_cross_mnt() now takes a *path instead of a **dentry
to pass in, and get back, the mnt and dentry.
nfsd_lookup_parent() used to take a *dentry and a **dentry.
now it just takes a *path. This is the *path that as passed
to nfsd_lookup_dentry().
Signed-off-by: NeilBrown <neilb@suse.de>
---
fs/nfsd/export.c | 4 +-
fs/nfsd/nfs3xdr.c | 22 +++++----
fs/nfsd/nfs4proc.c | 9 ++--
fs/nfsd/nfs4xdr.c | 55 +++++++++++-----------
fs/nfsd/nfsfh.c | 30 +++++++-----
fs/nfsd/nfsfh.h | 3 +
fs/nfsd/nfsproc.c | 5 ++
fs/nfsd/vfs.c | 133 ++++++++++++++++++++++++++++------------------------
fs/nfsd/vfs.h | 10 ++--
fs/nfsd/xdr4.h | 2 -
10 files changed, 150 insertions(+), 123 deletions(-)
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 9421dae22737..e506cbe78b4f 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -1003,7 +1003,7 @@ exp_rootfh(struct net *net, struct auth_domain *clp, char *name,
* fh must be initialized before calling fh_compose
*/
fh_init(&fh, maxsize);
- if (fh_compose(&fh, exp, path.dentry, NULL))
+ if (fh_compose(&fh, exp, &path, NULL))
err = -EINVAL;
else
err = 0;
@@ -1178,7 +1178,7 @@ exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp)
exp = rqst_find_fsidzero_export(rqstp);
if (IS_ERR(exp))
return nfserrno(PTR_ERR(exp));
- rv = fh_compose(fhp, exp, exp->ex_path.dentry, NULL);
+ rv = fh_compose(fhp, exp, &exp->ex_path, NULL);
exp_put(exp);
return rv;
}
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 0a5ebc52e6a9..67af0c5c1543 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -1089,36 +1089,38 @@ compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp,
const char *name, int namlen, u64 ino)
{
struct svc_export *exp;
- struct dentry *dparent, *dchild;
+ struct dentry *dparent;
+ struct path child;
__be32 rv = nfserr_noent;
dparent = cd->fh.fh_dentry;
exp = cd->fh.fh_export;
+ child.mnt = cd->fh.fh_mnt;
if (isdotent(name, namlen)) {
if (namlen == 2) {
- dchild = dget_parent(dparent);
+ child.dentry = dget_parent(dparent);
/*
* Don't return filehandle for ".." if we're at
* the filesystem or export root:
*/
- if (dchild == dparent)
+ if (child.dentry == dparent)
goto out;
if (dparent == exp->ex_path.dentry)
goto out;
} else
- dchild = dget(dparent);
+ child.dentry = dget(dparent);
} else
- dchild = lookup_positive_unlocked(name, dparent, namlen);
- if (IS_ERR(dchild))
+ child.dentry = lookup_positive_unlocked(name, dparent, namlen);
+ if (IS_ERR(child.dentry))
return rv;
- if (d_mountpoint(dchild))
+ if (d_mountpoint(child.dentry))
goto out;
- if (dchild->d_inode->i_ino != ino)
+ if (child.dentry->d_inode->i_ino != ino)
goto out;
- rv = fh_compose(fhp, exp, dchild, &cd->fh);
+ rv = fh_compose(fhp, exp, &child, &cd->fh);
out:
- dput(dchild);
+ dput(child.dentry);
return rv;
}
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 486c5dba4b65..743b9315cd3e 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -902,7 +902,7 @@ nfsd4_secinfo(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
{
struct nfsd4_secinfo *secinfo = &u->secinfo;
struct svc_export *exp;
- struct dentry *dentry;
+ struct path path;
__be32 err;
err = fh_verify(rqstp, &cstate->current_fh, S_IFDIR, NFSD_MAY_EXEC);
@@ -910,16 +910,16 @@ nfsd4_secinfo(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
return err;
err = nfsd_lookup_dentry(rqstp, &cstate->current_fh,
secinfo->si_name, secinfo->si_namelen,
- &exp, &dentry);
+ &exp, &path);
if (err)
return err;
fh_unlock(&cstate->current_fh);
- if (d_really_is_negative(dentry)) {
+ if (d_really_is_negative(path.dentry)) {
exp_put(exp);
err = nfserr_noent;
} else
secinfo->si_exp = exp;
- dput(dentry);
+ path_put(&path);
if (cstate->minorversion)
/* See rfc 5661 section 2.6.3.1.1.8 */
fh_put(&cstate->current_fh);
@@ -1930,6 +1930,7 @@ _nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
p = buf;
status = nfsd4_encode_fattr_to_buf(&p, count, &cstate->current_fh,
cstate->current_fh.fh_export,
+ cstate->current_fh.fh_mnt,
cstate->current_fh.fh_dentry,
verify->ve_bmval,
rqstp, 0);
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 7abeccb975b2..21c277fa28ae 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -2823,9 +2823,9 @@ nfsd4_encode_bitmap(struct xdr_stream *xdr, u32 bmval0, u32 bmval1, u32 bmval2)
*/
static __be32
nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
- struct svc_export *exp,
- struct dentry *dentry, u32 *bmval,
- struct svc_rqst *rqstp, int ignore_crossmnt)
+ struct svc_export *exp,
+ struct vfsmount *mnt, struct dentry *dentry,
+ u32 *bmval, struct svc_rqst *rqstp, int ignore_crossmnt)
{
u32 bmval0 = bmval[0];
u32 bmval1 = bmval[1];
@@ -2851,7 +2851,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
struct nfsd4_compoundres *resp = rqstp->rq_resp;
u32 minorversion = resp->cstate.minorversion;
struct path path = {
- .mnt = exp->ex_path.mnt,
+ .mnt = mnt,
.dentry = dentry,
};
struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
@@ -2882,7 +2882,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
if (!tempfh)
goto out;
fh_init(tempfh, NFS4_FHSIZE);
- status = fh_compose(tempfh, exp, dentry, NULL);
+ status = fh_compose(tempfh, exp, &path, NULL);
if (status)
goto out;
fhp = tempfh;
@@ -3274,13 +3274,12 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
p = xdr_reserve_space(xdr, 8);
if (!p)
- goto out_resource;
+ goto out_resource;
/*
* Get parent's attributes if not ignoring crossmount
* and this is the root of a cross-mounted filesystem.
*/
- if (ignore_crossmnt == 0 &&
- dentry == exp->ex_path.mnt->mnt_root) {
+ if (ignore_crossmnt == 0 && dentry == mnt->mnt_root) {
err = get_parent_attributes(exp, &parent_stat);
if (err)
goto out_nfserr;
@@ -3380,17 +3379,18 @@ static void svcxdr_init_encode_from_buffer(struct xdr_stream *xdr,
}
__be32 nfsd4_encode_fattr_to_buf(__be32 **p, int words,
- struct svc_fh *fhp, struct svc_export *exp,
- struct dentry *dentry, u32 *bmval,
- struct svc_rqst *rqstp, int ignore_crossmnt)
+ struct svc_fh *fhp, struct svc_export *exp,
+ struct vfsmount *mnt, struct dentry *dentry,
+ u32 *bmval, struct svc_rqst *rqstp,
+ int ignore_crossmnt)
{
struct xdr_buf dummy;
struct xdr_stream xdr;
__be32 ret;
svcxdr_init_encode_from_buffer(&xdr, &dummy, *p, words << 2);
- ret = nfsd4_encode_fattr(&xdr, fhp, exp, dentry, bmval, rqstp,
- ignore_crossmnt);
+ ret = nfsd4_encode_fattr(&xdr, fhp, exp, mnt, dentry, bmval, rqstp,
+ ignore_crossmnt);
*p = xdr.p;
return ret;
}
@@ -3409,14 +3409,16 @@ nfsd4_encode_dirent_fattr(struct xdr_stream *xdr, struct nfsd4_readdir *cd,
const char *name, int namlen)
{
struct svc_export *exp = cd->rd_fhp->fh_export;
- struct dentry *dentry;
+ struct path path;
__be32 nfserr;
int ignore_crossmnt = 0;
- dentry = lookup_positive_unlocked(name, cd->rd_fhp->fh_dentry, namlen);
- if (IS_ERR(dentry))
- return nfserrno(PTR_ERR(dentry));
+ path.dentry = lookup_positive_unlocked(name, cd->rd_fhp->fh_dentry,
+ namlen);
+ if (IS_ERR(path.dentry))
+ return nfserrno(PTR_ERR(path.dentry));
+ path.mnt = mntget(cd->rd_fhp->fh_mnt);
exp_get(exp);
/*
* In the case of a mountpoint, the client may be asking for
@@ -3425,7 +3427,7 @@ nfsd4_encode_dirent_fattr(struct xdr_stream *xdr, struct nfsd4_readdir *cd,
* we will not follow the cross mount and will fill the attribtutes
* directly from the mountpoint dentry.
*/
- if (nfsd_mountpoint(dentry, exp)) {
+ if (nfsd_mountpoint(path.dentry, exp)) {
int err;
if (!(exp->ex_flags & NFSEXP_V4ROOT)
@@ -3434,11 +3436,11 @@ nfsd4_encode_dirent_fattr(struct xdr_stream *xdr, struct nfsd4_readdir *cd,
goto out_encode;
}
/*
- * Why the heck aren't we just using nfsd_lookup??
+ * Why the heck aren't we just using nfsd_lookup_dentry??
* Different "."/".." handling? Something else?
* At least, add a comment here to explain....
*/
- err = nfsd_cross_mnt(cd->rd_rqstp, &dentry, &exp);
+ err = nfsd_cross_mnt(cd->rd_rqstp, &path, &exp);
if (err) {
nfserr = nfserrno(err);
goto out_put;
@@ -3446,13 +3448,13 @@ nfsd4_encode_dirent_fattr(struct xdr_stream *xdr, struct nfsd4_readdir *cd,
nfserr = check_nfsd_access(exp, cd->rd_rqstp);
if (nfserr)
goto out_put;
-
}
out_encode:
- nfserr = nfsd4_encode_fattr(xdr, NULL, exp, dentry, cd->rd_bmval,
- cd->rd_rqstp, ignore_crossmnt);
+ nfserr = nfsd4_encode_fattr(xdr, NULL, exp, path.mnt, path.dentry,
+ cd->rd_bmval, cd->rd_rqstp,
+ ignore_crossmnt);
out_put:
- dput(dentry);
+ path_put(&path);
exp_put(exp);
return nfserr;
}
@@ -3651,8 +3653,9 @@ nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
struct svc_fh *fhp = getattr->ga_fhp;
struct xdr_stream *xdr = resp->xdr;
- return nfsd4_encode_fattr(xdr, fhp, fhp->fh_export, fhp->fh_dentry,
- getattr->ga_bmval, resp->rqstp, 0);
+ return nfsd4_encode_fattr(xdr, fhp, fhp->fh_export,
+ fhp->fh_mnt, fhp->fh_dentry,
+ getattr->ga_bmval, resp->rqstp, 0);
}
static __be32
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index c475d2271f9c..0bf7ac13ae50 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -299,6 +299,7 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp)
}
fhp->fh_dentry = dentry;
+ fhp->fh_mnt = mntget(exp->ex_path.mnt);
fhp->fh_export = exp;
switch (rqstp->rq_vers) {
@@ -556,7 +557,7 @@ static void set_version_and_fsid_type(struct svc_fh *fhp, struct svc_export *exp
}
__be32
-fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry,
+fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct path *path,
struct svc_fh *ref_fh)
{
/* ref_fh is a reference file handle.
@@ -567,13 +568,13 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry,
*
*/
- struct inode * inode = d_inode(dentry);
+ struct inode * inode = d_inode(path->dentry);
dev_t ex_dev = exp_sb(exp)->s_dev;
dprintk("nfsd: fh_compose(exp %02x:%02x/%ld %pd2, ino=%ld)\n",
MAJOR(ex_dev), MINOR(ex_dev),
(long) d_inode(exp->ex_path.dentry)->i_ino,
- dentry,
+ path->dentry,
(inode ? inode->i_ino : 0));
/* Choose filehandle version and fsid type based on
@@ -590,14 +591,15 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry,
if (fhp->fh_locked || fhp->fh_dentry) {
printk(KERN_ERR "fh_compose: fh %pd2 not initialized!\n",
- dentry);
+ path->dentry);
}
if (fhp->fh_maxsize < NFS_FHSIZE)
printk(KERN_ERR "fh_compose: called with maxsize %d! %pd2\n",
fhp->fh_maxsize,
- dentry);
+ path->dentry);
- fhp->fh_dentry = dget(dentry); /* our internal copy */
+ fhp->fh_dentry = dget(path->dentry); /* our internal copy */
+ fhp->fh_mnt = mntget(path->mnt);
fhp->fh_export = exp_get(exp);
if (fhp->fh_handle.fh_version == 0xca) {
@@ -609,9 +611,9 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry,
fhp->fh_handle.ofh_xdev = fhp->fh_handle.ofh_dev;
fhp->fh_handle.ofh_xino =
ino_t_to_u32(d_inode(exp->ex_path.dentry)->i_ino);
- fhp->fh_handle.ofh_dirino = ino_t_to_u32(parent_ino(dentry));
+ fhp->fh_handle.ofh_dirino = ino_t_to_u32(parent_ino(path->dentry));
if (inode)
- _fh_update_old(dentry, exp, &fhp->fh_handle);
+ _fh_update_old(path->dentry, exp, &fhp->fh_handle);
} else {
fhp->fh_handle.fh_size =
key_len(fhp->fh_handle.fh_fsid_type) + 4;
@@ -624,7 +626,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry,
exp->ex_fsid, exp->ex_uuid);
if (inode)
- _fh_update(fhp, exp, dentry);
+ _fh_update(fhp, exp, path->dentry);
if (fhp->fh_handle.fh_fileid_type == FILEID_INVALID) {
fh_put(fhp);
return nfserr_opnotsupp;
@@ -675,8 +677,10 @@ fh_update(struct svc_fh *fhp)
void
fh_put(struct svc_fh *fhp)
{
- struct dentry * dentry = fhp->fh_dentry;
- struct svc_export * exp = fhp->fh_export;
+ struct dentry *dentry = fhp->fh_dentry;
+ struct svc_export *exp = fhp->fh_export;
+ struct vfsmount *mnt = fhp->fh_mnt;
+
if (dentry) {
fh_unlock(fhp);
fhp->fh_dentry = NULL;
@@ -684,6 +688,10 @@ fh_put(struct svc_fh *fhp)
fh_clear_wcc(fhp);
}
fh_drop_write(fhp);
+ if (mnt) {
+ mntput(mnt);
+ fhp->fh_mnt = NULL;
+ }
if (exp) {
exp_put(exp);
fhp->fh_export = NULL;
diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h
index 6106697adc04..26c02209babd 100644
--- a/fs/nfsd/nfsfh.h
+++ b/fs/nfsd/nfsfh.h
@@ -31,6 +31,7 @@ static inline ino_t u32_to_ino_t(__u32 uino)
typedef struct svc_fh {
struct knfsd_fh fh_handle; /* FH data */
int fh_maxsize; /* max size for fh_handle */
+ struct vfsmount * fh_mnt; /* mnt, possibly of subvol */
struct dentry * fh_dentry; /* validated dentry */
struct svc_export * fh_export; /* export pointer */
@@ -171,7 +172,7 @@ extern char * SVCFH_fmt(struct svc_fh *fhp);
* Function prototypes
*/
__be32 fh_verify(struct svc_rqst *, struct svc_fh *, umode_t, int);
-__be32 fh_compose(struct svc_fh *, struct svc_export *, struct dentry *, struct svc_fh *);
+__be32 fh_compose(struct svc_fh *, struct svc_export *, struct path *, struct svc_fh *);
__be32 fh_update(struct svc_fh *);
void fh_put(struct svc_fh *);
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
index 60d7c59e7935..245199b0e630 100644
--- a/fs/nfsd/nfsproc.c
+++ b/fs/nfsd/nfsproc.c
@@ -268,6 +268,7 @@ nfsd_proc_create(struct svc_rqst *rqstp)
struct iattr *attr = &argp->attrs;
struct inode *inode;
struct dentry *dchild;
+ struct path path;
int type, mode;
int hosterr;
dev_t rdev = 0, wanted = new_decode_dev(attr->ia_size);
@@ -298,7 +299,9 @@ nfsd_proc_create(struct svc_rqst *rqstp)
goto out_unlock;
}
fh_init(newfhp, NFS_FHSIZE);
- resp->status = fh_compose(newfhp, dirfhp->fh_export, dchild, dirfhp);
+ path.mnt = dirfhp->fh_mnt;
+ path.dentry = dchild;
+ resp->status = fh_compose(newfhp, dirfhp->fh_export, &path, dirfhp);
if (!resp->status && d_really_is_negative(dchild))
resp->status = nfserr_noent;
dput(dchild);
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 7c32edcfd2e9..c0c6920f25a4 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -49,27 +49,26 @@
#define NFSDDBG_FACILITY NFSDDBG_FILEOP
-/*
- * Called from nfsd_lookup and encode_dirent. Check if we have crossed
+/*
+ * Called from nfsd_lookup and encode_dirent. Check if we have crossed
* a mount point.
- * Returns -EAGAIN or -ETIMEDOUT leaving *dpp and *expp unchanged,
- * or nfs_ok having possibly changed *dpp and *expp
+ * Returns -EAGAIN or -ETIMEDOUT leaving *path and *expp unchanged,
+ * or nfs_ok having possibly changed *path and *expp
*/
int
-nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
- struct svc_export **expp)
+nfsd_cross_mnt(struct svc_rqst *rqstp, struct path *path_parent,
+ struct svc_export **expp)
{
struct svc_export *exp = *expp, *exp2 = NULL;
- struct dentry *dentry = *dpp;
- struct path path = {.mnt = mntget(exp->ex_path.mnt),
- .dentry = dget(dentry)};
+ struct path path = {.mnt = mntget(path_parent->mnt),
+ .dentry = dget(path_parent->dentry)};
int err = 0;
err = follow_down(&path, 0);
if (err < 0)
goto out;
- if (path.mnt == exp->ex_path.mnt && path.dentry == dentry &&
- nfsd_mountpoint(dentry, exp) == 2) {
+ if (path.mnt == path_parent->mnt && path.dentry == path_parent->dentry &&
+ nfsd_mountpoint(path.dentry, exp) == 2) {
/* This is only a mountpoint in some other namespace */
path_put(&path);
goto out;
@@ -93,19 +92,14 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
if (nfsd_v4client(rqstp) ||
(exp->ex_flags & NFSEXP_CROSSMOUNT) || EX_NOHIDE(exp2)) {
/* successfully crossed mount point */
- /*
- * This is subtle: path.dentry is *not* on path.mnt
- * at this point. The only reason we are safe is that
- * original mnt is pinned down by exp, so we should
- * put path *before* putting exp
- */
- *dpp = path.dentry;
- path.dentry = dentry;
+ path_put(path_parent);
+ *path_parent = path;
+ exp_put(exp);
*expp = exp2;
- exp2 = exp;
+ } else {
+ path_put(&path);
+ exp_put(exp2);
}
- path_put(&path);
- exp_put(exp2);
out:
return err;
}
@@ -121,27 +115,30 @@ static void follow_to_parent(struct path *path)
path->dentry = dp;
}
-static int nfsd_lookup_parent(struct svc_rqst *rqstp, struct dentry *dparent, struct svc_export **exp, struct dentry **dentryp)
+static int nfsd_lookup_parent(struct svc_rqst *rqstp, struct svc_export **exp,
+ struct path *path)
{
+ struct path path2;
struct svc_export *exp2;
- struct path path = {.mnt = mntget((*exp)->ex_path.mnt),
- .dentry = dget(dparent)};
- follow_to_parent(&path);
-
- exp2 = rqst_exp_parent(rqstp, &path);
+ path2 = *path;
+ path_get(&path2);
+ follow_to_parent(&path2);
+ exp2 = rqst_exp_parent(rqstp, path);
if (PTR_ERR(exp2) == -ENOENT) {
- *dentryp = dget(dparent);
+ /* leave path unchanged */
+ path_put(&path2);
+ return 0;
} else if (IS_ERR(exp2)) {
- path_put(&path);
+ path_put(&path2);
return PTR_ERR(exp2);
} else {
- *dentryp = dget(path.dentry);
+ path_put(path);
+ *path = path2;
exp_put(*exp);
*exp = exp2;
+ return 0;
}
- path_put(&path);
- return 0;
}
/*
@@ -172,29 +169,32 @@ int nfsd_mountpoint(struct dentry *dentry, struct svc_export *exp)
__be32
nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp,
const char *name, unsigned int len,
- struct svc_export **exp_ret, struct dentry **dentry_ret)
+ struct svc_export **exp_ret, struct path *ret)
{
struct svc_export *exp;
struct dentry *dparent;
- struct dentry *dentry;
int host_err;
dprintk("nfsd: nfsd_lookup(fh %s, %.*s)\n", SVCFH_fmt(fhp), len,name);
dparent = fhp->fh_dentry;
+ ret->mnt = mntget(fhp->fh_mnt);
exp = exp_get(fhp->fh_export);
/* Lookup the name, but don't follow links */
if (isdotent(name, len)) {
if (len==1)
- dentry = dget(dparent);
+ ret->dentry = dget(dparent);
else if (dparent != exp->ex_path.dentry)
- dentry = dget_parent(dparent);
+ ret->dentry = dget_parent(dparent);
else if (!EX_NOHIDE(exp) && !nfsd_v4client(rqstp))
- dentry = dget(dparent); /* .. == . just like at / */
+ ret->dentry = dget(dparent); /* .. == . just like at / */
else {
- /* checking mountpoint crossing is very different when stepping up */
- host_err = nfsd_lookup_parent(rqstp, dparent, &exp, &dentry);
+ /* checking mountpoint crossing is very different when
+ * stepping up
+ */
+ ret->dentry = dget(dparent);
+ host_err = nfsd_lookup_parent(rqstp, &exp, ret);
if (host_err)
goto out_nfserr;
}
@@ -205,11 +205,13 @@ nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp,
* need to take the child's i_mutex:
*/
fh_lock_nested(fhp, I_MUTEX_PARENT);
- dentry = lookup_one_len(name, dparent, len);
- host_err = PTR_ERR(dentry);
- if (IS_ERR(dentry))
+ ret->dentry = lookup_one_len(name, dparent, len);
+ host_err = PTR_ERR(ret->dentry);
+ if (IS_ERR(ret->dentry)) {
+ ret->dentry = NULL;
goto out_nfserr;
- if (nfsd_mountpoint(dentry, exp)) {
+ }
+ if (nfsd_mountpoint(ret->dentry, exp)) {
/*
* We don't need the i_mutex after all. It's
* still possible we could open this (regular
@@ -219,18 +221,16 @@ nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp,
* and a mountpoint won't be renamed:
*/
fh_unlock(fhp);
- if ((host_err = nfsd_cross_mnt(rqstp, &dentry, &exp))) {
- dput(dentry);
+ if ((host_err = nfsd_cross_mnt(rqstp, ret, &exp)))
goto out_nfserr;
- }
}
}
- *dentry_ret = dentry;
*exp_ret = exp;
return 0;
out_nfserr:
exp_put(exp);
+ path_put(ret);
return nfserrno(host_err);
}
@@ -251,13 +251,13 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
unsigned int len, struct svc_fh *resfh)
{
struct svc_export *exp;
- struct dentry *dentry;
+ struct path path;
__be32 err;
err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_EXEC);
if (err)
return err;
- err = nfsd_lookup_dentry(rqstp, fhp, name, len, &exp, &dentry);
+ err = nfsd_lookup_dentry(rqstp, fhp, name, len, &exp, &path);
if (err)
return err;
err = check_nfsd_access(exp, rqstp);
@@ -267,11 +267,11 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
* Note: we compose the file handle now, but as the
* dentry may be negative, it may need to be updated.
*/
- err = fh_compose(resfh, exp, dentry, fhp);
- if (!err && d_really_is_negative(dentry))
+ err = fh_compose(resfh, exp, &path, fhp);
+ if (!err && d_really_is_negative(path.dentry))
err = nfserr_noent;
out:
- dput(dentry);
+ path_put(&path);
exp_put(exp);
return err;
}
@@ -740,7 +740,7 @@ __nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type,
__be32 err;
int host_err = 0;
- path.mnt = fhp->fh_export->ex_path.mnt;
+ path.mnt = fhp->fh_mnt;
path.dentry = fhp->fh_dentry;
inode = d_inode(path.dentry);
@@ -1350,6 +1350,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
int type, dev_t rdev, struct svc_fh *resfhp)
{
struct dentry *dentry, *dchild = NULL;
+ struct path path;
__be32 err;
int host_err;
@@ -1371,7 +1372,9 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
host_err = PTR_ERR(dchild);
if (IS_ERR(dchild))
return nfserrno(host_err);
- err = fh_compose(resfhp, fhp->fh_export, dchild, fhp);
+ path.mnt = fhp->fh_mnt;
+ path.dentry = dchild;
+ err = fh_compose(resfhp, fhp->fh_export, &path, fhp);
/*
* We unconditionally drop our ref to dchild as fh_compose will have
* already grabbed its own ref for it.
@@ -1390,11 +1393,12 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
*/
__be32
do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
- char *fname, int flen, struct iattr *iap,
- struct svc_fh *resfhp, int createmode, u32 *verifier,
- bool *truncp, bool *created)
+ char *fname, int flen, struct iattr *iap,
+ struct svc_fh *resfhp, int createmode, u32 *verifier,
+ bool *truncp, bool *created)
{
struct dentry *dentry, *dchild = NULL;
+ struct path path;
struct inode *dirp;
__be32 err;
int host_err;
@@ -1436,7 +1440,9 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
goto out;
}
- err = fh_compose(resfhp, fhp->fh_export, dchild, fhp);
+ path.mnt = fhp->fh_mnt;
+ path.dentry = dchild;
+ err = fh_compose(resfhp, fhp->fh_export, &path, fhp);
if (err)
goto out;
@@ -1569,7 +1575,7 @@ nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp)
if (unlikely(err))
return err;
- path.mnt = fhp->fh_export->ex_path.mnt;
+ path.mnt = fhp->fh_mnt;
path.dentry = fhp->fh_dentry;
if (unlikely(!d_is_symlink(path.dentry)))
@@ -1600,6 +1606,7 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
struct svc_fh *resfhp)
{
struct dentry *dentry, *dnew;
+ struct path pathnew;
__be32 err, cerr;
int host_err;
@@ -1633,7 +1640,9 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
fh_drop_write(fhp);
- cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp);
+ pathnew.mnt = fhp->fh_mnt;
+ pathnew.dentry = dnew;
+ cerr = fh_compose(resfhp, fhp->fh_export, &pathnew, fhp);
dput(dnew);
if (err==0) err = cerr;
out:
@@ -2107,7 +2116,7 @@ nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat, in
err = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP | access);
if (!err) {
struct path path = {
- .mnt = fhp->fh_export->ex_path.mnt,
+ .mnt = fhp->fh_mnt,
.dentry = fhp->fh_dentry,
};
if (vfs_statfs(&path, stat))
diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h
index b21b76e6b9a8..52f587716208 100644
--- a/fs/nfsd/vfs.h
+++ b/fs/nfsd/vfs.h
@@ -42,13 +42,13 @@ struct nfsd_file;
typedef int (*nfsd_filldir_t)(void *, const char *, int, loff_t, u64, unsigned);
/* nfsd/vfs.c */
-int nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
+int nfsd_cross_mnt(struct svc_rqst *rqstp, struct path *,
struct svc_export **expp);
__be32 nfsd_lookup(struct svc_rqst *, struct svc_fh *,
const char *, unsigned int, struct svc_fh *);
__be32 nfsd_lookup_dentry(struct svc_rqst *, struct svc_fh *,
const char *, unsigned int,
- struct svc_export **, struct dentry **);
+ struct svc_export **, struct path *);
__be32 nfsd_setattr(struct svc_rqst *, struct svc_fh *,
struct iattr *, int, time64_t);
int nfsd_mountpoint(struct dentry *, struct svc_export *);
@@ -138,7 +138,7 @@ static inline int fh_want_write(struct svc_fh *fh)
if (fh->fh_want_write)
return 0;
- ret = mnt_want_write(fh->fh_export->ex_path.mnt);
+ ret = mnt_want_write(fh->fh_mnt);
if (!ret)
fh->fh_want_write = true;
return ret;
@@ -148,13 +148,13 @@ static inline void fh_drop_write(struct svc_fh *fh)
{
if (fh->fh_want_write) {
fh->fh_want_write = false;
- mnt_drop_write(fh->fh_export->ex_path.mnt);
+ mnt_drop_write(fh->fh_mnt);
}
}
static inline __be32 fh_getattr(const struct svc_fh *fh, struct kstat *stat)
{
- struct path p = {.mnt = fh->fh_export->ex_path.mnt,
+ struct path p = {.mnt = fh->fh_mnt,
.dentry = fh->fh_dentry};
return nfserrno(vfs_getattr(&p, stat, STATX_BASIC_STATS,
AT_STATX_SYNC_AS_STAT));
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index 3e4052e3bd50..8934db5113ac 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -763,7 +763,7 @@ void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *);
void nfsd4_encode_replay(struct xdr_stream *xdr, struct nfsd4_op *op);
__be32 nfsd4_encode_fattr_to_buf(__be32 **p, int words,
struct svc_fh *fhp, struct svc_export *exp,
- struct dentry *dentry,
+ struct vfsmount *mnt, struct dentry *dentry,
u32 *bmval, struct svc_rqst *, int ignore_crossmnt);
extern __be32 nfsd4_setclientid(struct svc_rqst *rqstp,
struct nfsd4_compound_state *, union nfsd4_op_u *u);
next prev parent reply other threads:[~2021-07-27 22:43 UTC|newest]
Thread overview: 122+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-07-27 22:37 [PATCH/RFC 00/11] expose btrfs subvols in mount table correctly NeilBrown
2021-07-27 22:37 ` [PATCH 07/11] exportfs: Allow filehandle lookup to cross internal mount points NeilBrown
2021-07-28 10:13 ` Amir Goldstein
2021-07-29 0:28 ` NeilBrown
2021-07-29 5:27 ` Amir Goldstein
2021-08-06 7:52 ` Miklos Szeredi
2021-08-06 8:08 ` Amir Goldstein
2021-08-06 8:18 ` Miklos Szeredi
2021-07-28 19:17 ` J. Bruce Fields
2021-07-28 22:25 ` NeilBrown
2021-07-27 22:37 ` [PATCH 04/11] VFS: export lookup_mnt() NeilBrown
2021-07-30 0:31 ` Al Viro
2021-07-30 5:33 ` NeilBrown
2021-07-27 22:37 ` [PATCH 01/11] VFS: show correct dev num in mountinfo NeilBrown
2021-07-30 0:25 ` Al Viro
2021-07-30 5:28 ` NeilBrown
2021-07-30 5:54 ` Miklos Szeredi
2021-07-30 6:13 ` NeilBrown
2021-07-30 7:18 ` Miklos Szeredi
2021-07-30 7:33 ` NeilBrown
2021-07-30 7:59 ` Miklos Szeredi
2021-08-02 4:18 ` A Third perspective on BTRFS nfsd subvol dev/inode number issues NeilBrown
2021-08-02 5:25 ` Al Viro
2021-08-02 5:40 ` NeilBrown
2021-08-02 7:54 ` Amir Goldstein
2021-08-02 13:53 ` Josef Bacik
2021-08-03 22:29 ` Qu Wenruo
2021-08-02 14:47 ` Frank Filz
2021-08-02 21:24 ` NeilBrown
2021-08-02 7:15 ` Martin Steigerwald
2021-08-02 21:40 ` NeilBrown
2021-08-02 12:39 ` J. Bruce Fields
2021-08-02 20:32 ` Patrick Goetz
2021-08-02 20:41 ` J. Bruce Fields
2021-08-02 21:10 ` NeilBrown
2021-08-02 21:50 ` J. Bruce Fields
2021-08-02 21:59 ` NeilBrown
2021-08-02 22:14 ` J. Bruce Fields
2021-08-02 22:36 ` NeilBrown
2021-08-03 0:15 ` J. Bruce Fields
2021-07-27 22:37 ` [PATCH 03/11] VFS: pass lookup_flags into follow_down() NeilBrown
2021-07-27 22:37 ` [PATCH 11/11] btrfs: use automount to bind-mount all subvol roots NeilBrown
2021-07-28 8:37 ` kernel test robot
2021-07-28 8:37 ` [RFC PATCH] btrfs: btrfs_mountpoint_expiry_timeout can be static kernel test robot
2021-07-28 13:12 ` [PATCH 11/11] btrfs: use automount to bind-mount all subvol roots Christian Brauner
2021-07-29 0:43 ` NeilBrown
2021-07-29 14:38 ` Christian Brauner
2021-07-31 6:25 ` [btrfs] 5874902268: xfstests.btrfs.202.fail kernel test robot
2021-07-27 22:37 ` NeilBrown [this message]
2021-07-27 22:37 ` [PATCH 10/11] btrfs: introduce mapping function from location to inum NeilBrown
2021-07-27 22:37 ` [PATCH 02/11] VFS: allow d_automount to create in-place bind-mount NeilBrown
2021-07-27 22:37 ` [PATCH 09/11] nfsd: Allow filehandle lookup to cross internal mount points NeilBrown
2021-07-28 19:15 ` J. Bruce Fields
2021-07-28 22:29 ` NeilBrown
2021-07-30 0:42 ` Al Viro
2021-07-30 5:43 ` NeilBrown
2021-07-27 22:37 ` [PATCH 08/11] nfsd: change get_parent_attributes() to nfsd_get_mounted_on() NeilBrown
2021-07-27 22:37 ` [PATCH 05/11] VFS: new function: mount_is_internal() NeilBrown
2021-07-28 2:16 ` Al Viro
2021-07-28 3:32 ` NeilBrown
2021-07-30 0:34 ` Al Viro
2021-07-28 2:19 ` [PATCH/RFC 00/11] expose btrfs subvols in mount table correctly Al Viro
2021-07-28 4:58 ` Wang Yugui
2021-07-28 6:04 ` Wang Yugui
2021-07-28 7:01 ` NeilBrown
2021-07-28 12:26 ` Neal Gompa
2021-07-28 19:14 ` J. Bruce Fields
2021-07-29 1:29 ` Zygo Blaxell
2021-07-29 1:43 ` NeilBrown
2021-07-29 23:20 ` Zygo Blaxell
2021-07-28 22:50 ` NeilBrown
2021-07-29 2:37 ` Zygo Blaxell
2021-07-29 3:36 ` NeilBrown
2021-07-29 23:20 ` Zygo Blaxell
2021-07-30 2:36 ` NeilBrown
2021-07-30 5:25 ` Qu Wenruo
2021-07-30 5:31 ` Qu Wenruo
2021-07-30 5:53 ` Amir Goldstein
2021-07-30 6:00 ` NeilBrown
2021-07-30 6:09 ` Qu Wenruo
2021-07-30 5:58 ` NeilBrown
2021-07-30 6:23 ` Qu Wenruo
2021-07-30 6:53 ` NeilBrown
2021-07-30 7:09 ` Qu Wenruo
2021-07-30 18:15 ` Zygo Blaxell
2021-07-30 15:17 ` J. Bruce Fields
2021-07-30 15:48 ` Josef Bacik
2021-07-30 16:25 ` Forza
2021-07-30 17:43 ` Zygo Blaxell
2021-07-30 5:28 ` Amir Goldstein
2021-07-28 13:43 ` g.btrfs
2021-07-29 1:39 ` NeilBrown
2021-07-29 9:28 ` Graham Cobb
2021-07-28 7:06 ` NeilBrown
2021-07-28 9:36 ` Wang Yugui
2021-07-28 19:35 ` J. Bruce Fields
2021-07-28 21:30 ` Josef Bacik
2021-07-30 0:13 ` Al Viro
2021-07-30 6:08 ` NeilBrown
2021-08-13 1:45 ` [PATCH] VFS/BTRFS/NFSD: provide more unique inode number for btrfs export NeilBrown
2021-08-13 14:55 ` Josef Bacik
2021-08-15 7:39 ` Goffredo Baroncelli
2021-08-15 19:35 ` Roman Mamedov
2021-08-15 21:03 ` Goffredo Baroncelli
2021-08-15 21:53 ` NeilBrown
2021-08-17 19:34 ` Goffredo Baroncelli
2021-08-17 21:39 ` NeilBrown
2021-08-18 17:24 ` Goffredo Baroncelli
2021-08-15 22:17 ` NeilBrown
2021-08-19 8:01 ` Amir Goldstein
2021-08-20 3:21 ` NeilBrown
2021-08-20 6:23 ` Amir Goldstein
2021-08-23 4:05 ` [PATCH v2] BTRFS/NFSD: " NeilBrown
2021-08-18 14:54 ` [PATCH] VFS/BTRFS/NFSD: " Wang Yugui
2021-08-18 21:46 ` NeilBrown
2021-08-19 2:19 ` Zygo Blaxell
2021-08-20 2:54 ` NeilBrown
2021-08-22 19:29 ` Zygo Blaxell
2021-08-23 5:51 ` NeilBrown
2021-08-23 23:22 ` NeilBrown
2021-08-25 2:06 ` Zygo Blaxell
2021-08-23 0:57 ` Wang Yugui
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=162742546552.32498.8097200286954882080.stgit@noble.brown \
--to=neilb@suse.de \
--cc=bfields@fieldses.org \
--cc=chuck.lever@oracle.com \
--cc=clm@fb.com \
--cc=dsterba@suse.com \
--cc=hch@infradead.org \
--cc=josef@toxicpanda.com \
--cc=linux-btrfs@vger.kernel.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-nfs@vger.kernel.org \
--cc=viro@zeniv.linux.org.uk \
/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;
as well as URLs for NNTP newsgroup(s).