From: Waiman Long <longman@redhat.com>
To: Alexander Viro <viro@zeniv.linux.org.uk>,
Jonathan Corbet <corbet@lwn.net>,
Luis Chamberlain <mcgrof@kernel.org>,
Kees Cook <keescook@chromium.org>,
Iurii Zaikin <yzaikin@google.com>
Cc: linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org,
linux-doc@vger.kernel.org,
Mauro Carvalho Chehab <mchehab+samsung@kernel.org>,
Eric Biggers <ebiggers@google.com>,
Dave Chinner <david@fromorbit.com>,
Eric Sandeen <sandeen@redhat.com>,
Waiman Long <longman@redhat.com>
Subject: [PATCH 10/11] fs/dcache: Kill off dentry as last resort
Date: Wed, 26 Feb 2020 11:14:03 -0500 [thread overview]
Message-ID: <20200226161404.14136-11-longman@redhat.com> (raw)
In-Reply-To: <20200226161404.14136-1-longman@redhat.com>
In the unlikely case that an out-of-control application is generating
negative dentries faster than what the negative dentry reclaim process
can get rid of, we will have to kill the negative dentry directly as
the last resort.
The current threshold for killing negative dentry is the maximum of 4
times dentry-dir-max and 10,000 within a directory.
On a 32-vcpu VM, a 30-thread parallel negative dentry generation problem
was run. Without this patch, the negative dentry reclaim process was
overwhelmed by the negative dentry generator and the number of negative
dentries kept growing. With this patch applied with a "dentry-dir-max"
of 10,000. The number of negative dentries never went beyond 40,000.
Signed-off-by: Waiman Long <longman@redhat.com>
---
fs/dcache.c | 37 +++++++++++++++++++++++++++++--------
1 file changed, 29 insertions(+), 8 deletions(-)
diff --git a/fs/dcache.c b/fs/dcache.c
index f470763e7fb8..fe48e00349c9 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -140,7 +140,7 @@ static int negative_dentry_dir_max __read_mostly;
static LLIST_HEAD(negative_reclaim_list);
static DEFINE_STATIC_KEY_FALSE(negative_reclaim_enable);
-static void negative_reclaim_check(struct dentry *parent);
+static void negative_reclaim_check(struct dentry *parent, struct dentry *child);
static void negative_reclaim_workfn(struct work_struct *work);
static DECLARE_WORK(negative_reclaim_work, negative_reclaim_workfn);
@@ -927,7 +927,7 @@ void dput(struct dentry *dentry)
*/
if (static_branch_unlikely(&negative_reclaim_enable) &&
neg_parent)
- negative_reclaim_check(neg_parent);
+ negative_reclaim_check(neg_parent, dentry);
return;
}
@@ -1548,10 +1548,12 @@ static void negative_reclaim_workfn(struct work_struct *work)
* Check the parent to see if it has too many negative dentries and queue
* it up for the negative dentry reclaim work function to handle it.
*/
-static void negative_reclaim_check(struct dentry *parent)
+static void negative_reclaim_check(struct dentry *parent, struct dentry *child)
__releases(rcu)
{
int limit = negative_dentry_dir_max;
+ int kill_threshold = max(4 * limit, 10000);
+ int ncnt = read_dentry_nnegative(parent);
struct reclaim_dentry *dentry_node;
if (!limit)
@@ -1560,16 +1562,16 @@ static void negative_reclaim_check(struct dentry *parent)
/*
* These checks are racy before spin_lock().
*/
- if (!can_reclaim_dentry(parent->d_flags) ||
- (parent->d_flags & DCACHE_RECLAIMING) ||
- (read_dentry_nnegative(parent) <= limit))
+ if ((!can_reclaim_dentry(parent->d_flags) ||
+ (parent->d_flags & DCACHE_RECLAIMING) || (ncnt <= limit)) &&
+ (ncnt < kill_threshold))
goto rcu_unlock_out;
spin_lock(&parent->d_lock);
+ ncnt = read_dentry_nnegative(parent);
if (!can_reclaim_dentry(parent->d_flags) ||
(parent->d_flags & DCACHE_RECLAIMING) ||
- (read_dentry_nnegative(parent) <= limit) ||
- !d_is_dir(parent))
+ (ncnt <= limit) || !d_is_dir(parent))
goto unlock_out;
dentry_node = kzalloc(sizeof(*dentry_node), GFP_NOWAIT);
@@ -1592,6 +1594,25 @@ static void negative_reclaim_check(struct dentry *parent)
return;
unlock_out:
+ /*
+ * In the unlikely case that an out-of-control application is
+ * generating negative dentries faster than what the negative
+ * dentry reclaim process can get rid of, we will have to kill
+ * the negative dentry directly as the last resort.
+ *
+ * N.B. __dentry_kill() releases both the parent and child's d_lock.
+ */
+ if (unlikely(ncnt >= kill_threshold)) {
+ spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED);
+ if (can_reclaim_dentry(child->d_flags) &&
+ !child->d_lockref.count && (child->d_parent == parent)) {
+ rcu_read_unlock();
+ __dentry_kill(child);
+ dput(parent);
+ return;
+ }
+ spin_unlock(&child->d_lock);
+ }
spin_unlock(&parent->d_lock);
rcu_unlock_out:
rcu_read_unlock();
--
2.18.1
next prev parent reply other threads:[~2020-02-26 16:15 UTC|newest]
Thread overview: 34+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-02-26 16:13 [PATCH 00/11] fs/dcache: Limit # of negative dentries Waiman Long
2020-02-26 16:13 ` [PATCH 01/11] fs/dcache: Fix incorrect accounting " Waiman Long
2020-02-26 16:13 ` [PATCH 02/11] fs/dcache: Simplify __dentry_kill() Waiman Long
2020-02-26 16:13 ` [PATCH 03/11] fs/dcache: Add a counter to track number of children Waiman Long
2020-02-26 16:13 ` [PATCH 04/11] fs/dcache: Add sysctl parameter dentry-dir-max Waiman Long
2020-02-26 16:13 ` [PATCH 05/11] fs/dcache: Reclaim excessive negative dentries in directories Waiman Long
2020-02-26 16:13 ` [PATCH 06/11] fs/dcache: directory opportunistically stores # of positive dentries Waiman Long
2020-02-26 16:14 ` [PATCH 07/11] fs/dcache: Add static key negative_reclaim_enable Waiman Long
2020-02-26 16:14 ` [PATCH 08/11] fs/dcache: Limit dentry reclaim count in negative_reclaim_workfn() Waiman Long
2020-02-26 16:14 ` [PATCH 09/11] fs/dcache: Don't allow small values for dentry-dir-max Waiman Long
2020-02-26 16:14 ` Waiman Long [this message]
2020-02-26 16:14 ` [PATCH 11/11] fs/dcache: Track # of negative dentries reclaimed & killed Waiman Long
2020-02-26 16:29 ` [PATCH 00/11] fs/dcache: Limit # of negative dentries Matthew Wilcox
2020-02-26 19:19 ` Waiman Long
2020-02-26 21:28 ` Matthew Wilcox
2020-02-26 21:28 ` Andreas Dilger
2020-02-26 21:45 ` Matthew Wilcox
2020-02-27 8:07 ` Dave Chinner
2020-02-27 9:55 ` Ian Kent
2020-02-28 3:34 ` Matthew Wilcox
2020-02-28 4:16 ` Ian Kent
2020-02-28 4:36 ` Ian Kent
2020-02-28 4:52 ` Al Viro
2020-02-28 4:22 ` Al Viro
2020-02-28 4:52 ` Ian Kent
2020-02-28 15:32 ` Waiman Long
2020-02-28 15:39 ` Matthew Wilcox
2020-02-28 19:32 ` Theodore Y. Ts'o
2020-02-27 19:04 ` Eric Sandeen
2020-02-27 22:39 ` Dave Chinner
2020-02-27 8:30 ` Dave Chinner
2020-02-28 15:47 ` Waiman Long
2020-03-15 3:46 ` Matthew Wilcox
2020-03-21 10:17 ` Konstantin Khlebnikov
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=20200226161404.14136-11-longman@redhat.com \
--to=longman@redhat.com \
--cc=corbet@lwn.net \
--cc=david@fromorbit.com \
--cc=ebiggers@google.com \
--cc=keescook@chromium.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mcgrof@kernel.org \
--cc=mchehab+samsung@kernel.org \
--cc=sandeen@redhat.com \
--cc=viro@zeniv.linux.org.uk \
--cc=yzaikin@google.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;
as well as URLs for NNTP newsgroup(s).