From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
To: linux-kernel@vger.kernel.org
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
stable@vger.kernel.org,
Trond Myklebust <trond.myklebust@hammerspace.com>,
Qian Lu <luqia@amazon.com>
Subject: [PATCH 4.19 04/32] NFS: Refactor nfs_lookup_revalidate()
Date: Fri, 2 Aug 2019 11:39:38 +0200 [thread overview]
Message-ID: <20190802092103.084716627@linuxfoundation.org> (raw)
In-Reply-To: <20190802092101.913646560@linuxfoundation.org>
From: Trond Myklebust <trond.myklebust@hammerspace.com>
commit 5ceb9d7fdaaf6d8ced6cd7861cf1deb9cd93fa47 upstream.
Refactor the code in nfs_lookup_revalidate() as a stepping stone towards
optimising and fixing nfs4_lookup_revalidate().
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: Qian Lu <luqia@amazon.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
fs/nfs/dir.c | 222 +++++++++++++++++++++++++++++++++--------------------------
1 file changed, 126 insertions(+), 96 deletions(-)
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -1072,6 +1072,100 @@ int nfs_neg_need_reval(struct inode *dir
return !nfs_check_verifier(dir, dentry, flags & LOOKUP_RCU);
}
+static int
+nfs_lookup_revalidate_done(struct inode *dir, struct dentry *dentry,
+ struct inode *inode, int error)
+{
+ switch (error) {
+ case 1:
+ dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) is valid\n",
+ __func__, dentry);
+ return 1;
+ case 0:
+ nfs_mark_for_revalidate(dir);
+ if (inode && S_ISDIR(inode->i_mode)) {
+ /* Purge readdir caches. */
+ nfs_zap_caches(inode);
+ /*
+ * We can't d_drop the root of a disconnected tree:
+ * its d_hash is on the s_anon list and d_drop() would hide
+ * it from shrink_dcache_for_unmount(), leading to busy
+ * inodes on unmount and further oopses.
+ */
+ if (IS_ROOT(dentry))
+ return 1;
+ }
+ dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) is invalid\n",
+ __func__, dentry);
+ return 0;
+ }
+ dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) lookup returned error %d\n",
+ __func__, dentry, error);
+ return error;
+}
+
+static int
+nfs_lookup_revalidate_negative(struct inode *dir, struct dentry *dentry,
+ unsigned int flags)
+{
+ int ret = 1;
+ if (nfs_neg_need_reval(dir, dentry, flags)) {
+ if (flags & LOOKUP_RCU)
+ return -ECHILD;
+ ret = 0;
+ }
+ return nfs_lookup_revalidate_done(dir, dentry, NULL, ret);
+}
+
+static int
+nfs_lookup_revalidate_delegated(struct inode *dir, struct dentry *dentry,
+ struct inode *inode)
+{
+ nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
+ return nfs_lookup_revalidate_done(dir, dentry, inode, 1);
+}
+
+static int
+nfs_lookup_revalidate_dentry(struct inode *dir, struct dentry *dentry,
+ struct inode *inode)
+{
+ struct nfs_fh *fhandle;
+ struct nfs_fattr *fattr;
+ struct nfs4_label *label;
+ int ret;
+
+ ret = -ENOMEM;
+ fhandle = nfs_alloc_fhandle();
+ fattr = nfs_alloc_fattr();
+ label = nfs4_label_alloc(NFS_SERVER(inode), GFP_KERNEL);
+ if (fhandle == NULL || fattr == NULL || IS_ERR(label))
+ goto out;
+
+ ret = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, label);
+ if (ret < 0) {
+ if (ret == -ESTALE || ret == -ENOENT)
+ ret = 0;
+ goto out;
+ }
+ ret = 0;
+ if (nfs_compare_fh(NFS_FH(inode), fhandle))
+ goto out;
+ if (nfs_refresh_inode(inode, fattr) < 0)
+ goto out;
+
+ nfs_setsecurity(inode, fattr, label);
+ nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
+
+ /* set a readdirplus hint that we had a cache miss */
+ nfs_force_use_readdirplus(dir);
+ ret = 1;
+out:
+ nfs_free_fattr(fattr);
+ nfs_free_fhandle(fhandle);
+ nfs4_label_free(label);
+ return nfs_lookup_revalidate_done(dir, dentry, inode, ret);
+}
+
/*
* This is called every time the dcache has a lookup hit,
* and we should check whether we can really trust that
@@ -1083,58 +1177,36 @@ int nfs_neg_need_reval(struct inode *dir
* If the parent directory is seen to have changed, we throw out the
* cached dentry and do a new lookup.
*/
-static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
+static int
+nfs_do_lookup_revalidate(struct inode *dir, struct dentry *dentry,
+ unsigned int flags)
{
- struct inode *dir;
struct inode *inode;
- struct dentry *parent;
- struct nfs_fh *fhandle = NULL;
- struct nfs_fattr *fattr = NULL;
- struct nfs4_label *label = NULL;
int error;
- if (flags & LOOKUP_RCU) {
- parent = READ_ONCE(dentry->d_parent);
- dir = d_inode_rcu(parent);
- if (!dir)
- return -ECHILD;
- } else {
- parent = dget_parent(dentry);
- dir = d_inode(parent);
- }
nfs_inc_stats(dir, NFSIOS_DENTRYREVALIDATE);
inode = d_inode(dentry);
- if (!inode) {
- if (nfs_neg_need_reval(dir, dentry, flags)) {
- if (flags & LOOKUP_RCU)
- return -ECHILD;
- goto out_bad;
- }
- goto out_valid;
- }
+ if (!inode)
+ return nfs_lookup_revalidate_negative(dir, dentry, flags);
if (is_bad_inode(inode)) {
- if (flags & LOOKUP_RCU)
- return -ECHILD;
dfprintk(LOOKUPCACHE, "%s: %pd2 has dud inode\n",
__func__, dentry);
goto out_bad;
}
if (NFS_PROTO(dir)->have_delegation(inode, FMODE_READ))
- goto out_set_verifier;
+ return nfs_lookup_revalidate_delegated(dir, dentry, inode);
/* Force a full look up iff the parent directory has changed */
if (!(flags & (LOOKUP_EXCL | LOOKUP_REVAL)) &&
nfs_check_verifier(dir, dentry, flags & LOOKUP_RCU)) {
error = nfs_lookup_verify_inode(inode, flags);
if (error) {
- if (flags & LOOKUP_RCU)
- return -ECHILD;
if (error == -ESTALE)
- goto out_zap_parent;
- goto out_error;
+ nfs_zap_caches(dir);
+ goto out_bad;
}
nfs_advise_use_readdirplus(dir);
goto out_valid;
@@ -1146,81 +1218,39 @@ static int nfs_lookup_revalidate(struct
if (NFS_STALE(inode))
goto out_bad;
- error = -ENOMEM;
- fhandle = nfs_alloc_fhandle();
- fattr = nfs_alloc_fattr();
- if (fhandle == NULL || fattr == NULL)
- goto out_error;
-
- label = nfs4_label_alloc(NFS_SERVER(inode), GFP_NOWAIT);
- if (IS_ERR(label))
- goto out_error;
-
trace_nfs_lookup_revalidate_enter(dir, dentry, flags);
- error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, label);
+ error = nfs_lookup_revalidate_dentry(dir, dentry, inode);
trace_nfs_lookup_revalidate_exit(dir, dentry, flags, error);
- if (error == -ESTALE || error == -ENOENT)
- goto out_bad;
- if (error)
- goto out_error;
- if (nfs_compare_fh(NFS_FH(inode), fhandle))
- goto out_bad;
- if ((error = nfs_refresh_inode(inode, fattr)) != 0)
- goto out_bad;
-
- nfs_setsecurity(inode, fattr, label);
-
- nfs_free_fattr(fattr);
- nfs_free_fhandle(fhandle);
- nfs4_label_free(label);
+ return error;
+out_valid:
+ return nfs_lookup_revalidate_done(dir, dentry, inode, 1);
+out_bad:
+ if (flags & LOOKUP_RCU)
+ return -ECHILD;
+ return nfs_lookup_revalidate_done(dir, dentry, inode, 0);
+}
- /* set a readdirplus hint that we had a cache miss */
- nfs_force_use_readdirplus(dir);
+static int
+nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
+{
+ struct dentry *parent;
+ struct inode *dir;
+ int ret;
-out_set_verifier:
- nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
- out_valid:
if (flags & LOOKUP_RCU) {
+ parent = READ_ONCE(dentry->d_parent);
+ dir = d_inode_rcu(parent);
+ if (!dir)
+ return -ECHILD;
+ ret = nfs_do_lookup_revalidate(dir, dentry, flags);
if (parent != READ_ONCE(dentry->d_parent))
return -ECHILD;
- } else
+ } else {
+ parent = dget_parent(dentry);
+ ret = nfs_do_lookup_revalidate(d_inode(parent), dentry, flags);
dput(parent);
- dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) is valid\n",
- __func__, dentry);
- return 1;
-out_zap_parent:
- nfs_zap_caches(dir);
- out_bad:
- WARN_ON(flags & LOOKUP_RCU);
- nfs_free_fattr(fattr);
- nfs_free_fhandle(fhandle);
- nfs4_label_free(label);
- nfs_mark_for_revalidate(dir);
- if (inode && S_ISDIR(inode->i_mode)) {
- /* Purge readdir caches. */
- nfs_zap_caches(inode);
- /*
- * We can't d_drop the root of a disconnected tree:
- * its d_hash is on the s_anon list and d_drop() would hide
- * it from shrink_dcache_for_unmount(), leading to busy
- * inodes on unmount and further oopses.
- */
- if (IS_ROOT(dentry))
- goto out_valid;
}
- dput(parent);
- dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) is invalid\n",
- __func__, dentry);
- return 0;
-out_error:
- WARN_ON(flags & LOOKUP_RCU);
- nfs_free_fattr(fattr);
- nfs_free_fhandle(fhandle);
- nfs4_label_free(label);
- dput(parent);
- dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) lookup returned error %d\n",
- __func__, dentry, error);
- return error;
+ return ret;
}
/*
next prev parent reply other threads:[~2019-08-02 9:56 UTC|newest]
Thread overview: 43+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-08-02 9:39 [PATCH 4.19 00/32] 4.19.64-stable review Greg Kroah-Hartman
2019-08-02 9:39 ` [PATCH 4.19 01/32] hv_sock: Add support for delayed close Greg Kroah-Hartman
2019-08-02 9:39 ` [PATCH 4.19 02/32] vsock: correct removal of socket from the list Greg Kroah-Hartman
2019-08-02 9:39 ` [PATCH 4.19 03/32] NFS: Fix dentry revalidation on NFSv4 lookup Greg Kroah-Hartman
2019-08-02 9:39 ` Greg Kroah-Hartman [this message]
2019-08-02 9:39 ` [PATCH 4.19 05/32] NFSv4: Fix lookup revalidate of regular files Greg Kroah-Hartman
2019-08-02 9:39 ` [PATCH 4.19 06/32] usb: dwc2: Disable all EPs on disconnect Greg Kroah-Hartman
2019-08-02 9:39 ` [PATCH 4.19 07/32] usb: dwc2: Fix disable " Greg Kroah-Hartman
2019-08-02 9:39 ` [PATCH 4.19 08/32] arm64: compat: Provide definition for COMPAT_SIGMINSTKSZ Greg Kroah-Hartman
2019-08-02 9:39 ` [PATCH 4.19 09/32] binder: fix possible UAF when freeing buffer Greg Kroah-Hartman
2019-08-02 9:39 ` [PATCH 4.19 10/32] ISDN: hfcsusb: checking idx of ep configuration Greg Kroah-Hartman
2019-08-02 9:39 ` [PATCH 4.19 11/32] media: au0828: fix null dereference in error path Greg Kroah-Hartman
2019-08-02 9:39 ` [PATCH 4.19 12/32] ath10k: Change the warning message string Greg Kroah-Hartman
2019-08-02 9:39 ` [PATCH 4.19 13/32] media: cpia2_usb: first wake up, then free in disconnect Greg Kroah-Hartman
2019-08-02 9:39 ` [PATCH 4.19 14/32] media: pvrusb2: use a different format for warnings Greg Kroah-Hartman
2019-08-02 9:39 ` [PATCH 4.19 15/32] NFS: Cleanup if nfs_match_client is interrupted Greg Kroah-Hartman
2019-08-02 9:39 ` [PATCH 4.19 16/32] media: radio-raremono: change devm_k*alloc to k*alloc Greg Kroah-Hartman
2019-08-02 9:39 ` [PATCH 4.19 17/32] iommu/vt-d: Dont queue_iova() if there is no flush queue Greg Kroah-Hartman
2019-08-03 21:34 ` Pavel Machek
2019-08-06 22:47 ` Dmitry Safonov
2019-08-06 23:16 ` Dmitry Safonov
2019-08-02 9:39 ` [PATCH 4.19 18/32] iommu/iova: Fix compilation error with !CONFIG_IOMMU_IOVA Greg Kroah-Hartman
2019-08-02 9:39 ` [PATCH 4.19 19/32] Bluetooth: hci_uart: check for missing tty operations Greg Kroah-Hartman
2019-08-02 9:39 ` [PATCH 4.19 20/32] vhost: introduce vhost_exceeds_weight() Greg Kroah-Hartman
2019-08-02 9:39 ` [PATCH 4.19 21/32] vhost_net: fix possible infinite loop Greg Kroah-Hartman
2019-08-03 21:49 ` Pavel Machek
2019-08-05 4:17 ` Jason Wang
2019-08-02 9:39 ` [PATCH 4.19 22/32] vhost: vsock: add weight support Greg Kroah-Hartman
2019-08-02 9:39 ` [PATCH 4.19 23/32] vhost: scsi: " Greg Kroah-Hartman
2019-08-02 9:39 ` [PATCH 4.19 24/32] sched/fair: Dont free p->numa_faults with concurrent readers Greg Kroah-Hartman
2019-08-02 9:39 ` [PATCH 4.19 25/32] sched/fair: Use RCU accessors consistently for ->numa_group Greg Kroah-Hartman
2019-08-02 9:40 ` [PATCH 4.19 26/32] /proc/<pid>/cmdline: remove all the special cases Greg Kroah-Hartman
2019-08-02 9:40 ` [PATCH 4.19 27/32] /proc/<pid>/cmdline: add back the setproctitle() special case Greg Kroah-Hartman
2019-08-02 9:40 ` [PATCH 4.19 28/32] drivers/pps/pps.c: clear offset flags in PPS_SETPARAMS ioctl Greg Kroah-Hartman
2019-08-02 9:40 ` [PATCH 4.19 29/32] Fix allyesconfig output Greg Kroah-Hartman
2019-08-02 9:40 ` [PATCH 4.19 30/32] ceph: hold i_ceph_lock when removing caps for freeing inode Greg Kroah-Hartman
2019-08-02 9:40 ` [PATCH 4.19 31/32] block, scsi: Change the preempt-only flag into a counter Greg Kroah-Hartman
2019-08-02 9:40 ` [PATCH 4.19 32/32] scsi: core: Avoid that a kernel warning appears during system resume Greg Kroah-Hartman
2019-08-02 23:22 ` [PATCH 4.19 00/32] 4.19.64-stable review shuah
2019-08-03 5:46 ` Naresh Kamboju
2019-08-03 9:58 ` Pavel Machek
2019-08-03 10:34 ` Greg Kroah-Hartman
2019-08-03 15:59 ` Guenter Roeck
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=20190802092103.084716627@linuxfoundation.org \
--to=gregkh@linuxfoundation.org \
--cc=linux-kernel@vger.kernel.org \
--cc=luqia@amazon.com \
--cc=stable@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