From patchwork Tue May 26 01:35:57 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chengguang Xu X-Patchwork-Id: 11569837 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id BB4EE739 for ; Tue, 26 May 2020 01:37:12 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9A12A207CB for ; Tue, 26 May 2020 01:37:12 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=mykernel.net header.i=cgxu519@mykernel.net header.b="fOxuspGi" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388447AbgEZBhL (ORCPT ); Mon, 25 May 2020 21:37:11 -0400 Received: from sender2-op-o12.zoho.com.cn ([163.53.93.243]:17137 "EHLO sender2-op-o12.zoho.com.cn" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2387794AbgEZBhL (ORCPT ); Mon, 25 May 2020 21:37:11 -0400 ARC-Seal: i=1; a=rsa-sha256; t=1590456977; cv=none; d=zoho.com.cn; s=zohoarc; b=kebxn3oeMU6m9o1J6r+1+15WCCAgG3YkxkL7wV2cdRZSn858nQxv/WcDvq9y/Jgi9k1pGZ1eDKYaQtOlPAG6tshkQQsreev480TgOGKRBXVkKcgBT3OqSeZxS+VzZc/yuHY49c21DT/x1KWpRPPcl/qyXi/AF8QU2waG4DCe7zA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com.cn; s=zohoarc; t=1590456977; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:MIME-Version:Message-ID:Subject:To; bh=W+BQC2GaJHDT2mZ2pan3p02uuV3yAycUAHrs51y9XMU=; b=e2yXPWJ6R9lt9OvLQNV41d+cxAUvOPJeMSruJJsW0fAwZI5sg54TUBEk9z708qnk4HMoPTvRhoujr1uFNI/0i0wzshc0PDs3YRJ0LcbgXJetcOt5nHFG0zARNvqZp6jV9DbQJM/Q/2y7+kr8+kBw3dSZHFXPUF30AqEbtAM4aV8= ARC-Authentication-Results: i=1; mx.zoho.com.cn; dkim=pass header.i=mykernel.net; spf=pass smtp.mailfrom=cgxu519@mykernel.net; dmarc=pass header.from= header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1590456977; s=zohomail; d=mykernel.net; i=cgxu519@mykernel.net; h=From:To:Cc:Message-ID:Subject:Date:MIME-Version:Content-Transfer-Encoding:Content-Type; bh=W+BQC2GaJHDT2mZ2pan3p02uuV3yAycUAHrs51y9XMU=; b=fOxuspGiZgH3Goq7eH+7aqR826RJAIbIcE40NdkhcbzXfio2+jF1GSU2Itk00Ddo a/k6WBT0yBiZzt2sXVORj9BbBFSKg7j0f8Kn7RMwocylPYyLHvHpS7SRxq+O4njtzMj 293VilV65aOHdZ44zrHAsLLsA2oSl4TouY7cM7uE= Received: from localhost.localdomain (218.18.229.179 [218.18.229.179]) by mx.zoho.com.cn with SMTPS id 1590456975196819.058477717145; Tue, 26 May 2020 09:36:15 +0800 (CST) From: Chengguang Xu To: miklos@szeredi.hu, amir73il@gmail.com, viro@zeniv.linux.org.uk Cc: raven@themaw.net, linux-fsdevel@vger.kernel.org, linux-unionfs@vger.kernel.org, Chengguang Xu Message-ID: <20200526013557.11121-1-cgxu519@mykernel.net> Subject: [RFC PATCH v4] ovl: drop negative dentry in upper layer Date: Tue, 26 May 2020 09:35:57 +0800 X-Mailer: git-send-email 2.20.1 MIME-Version: 1.0 X-ZohoCNMailClient: External Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org Negative dentries of upper layer are useless after construction of overlayfs' own dentry and may keep in the memory long time even after unmount of overlayfs instance. This patch tries to drop unnecessary negative dentry of upper layer to effectively reclaim memory. Signed-off-by: Chengguang Xu --- v1->v2: - Only drop negative dentry in slow path of lookup. v2->v3: - Drop negative dentry in vfs layer. - Rebase on latest linus-tree(5.7.0-rc5). v3->v4: - Check negative dentry with dentry lock. - Only drop negative dentry in upper layer. fs/overlayfs/namei.c | 45 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c index 723d17744758..47cc79ec8205 100644 --- a/fs/overlayfs/namei.c +++ b/fs/overlayfs/namei.c @@ -191,16 +191,46 @@ static bool ovl_is_opaquedir(struct dentry *dentry) return ovl_check_dir_xattr(dentry, OVL_XATTR_OPAQUE); } +static struct dentry *ovl_lookup_positive_unlocked(const char *name, + struct dentry *base, int len) +{ + struct dentry *dentry; + bool drop = false; + + dentry = lookup_one_len_unlocked(name, base, len); + if (!IS_ERR(dentry) && d_is_negative(dentry) && + dentry->d_lockref.count == 1) { + spin_lock(&dentry->d_lock); + /* Recheck condition under lock */ + if (d_is_negative(dentry) && dentry->d_lockref.count == 1) { + __d_drop(dentry); + drop = true; + } + spin_unlock(&dentry->d_lock); + + if (drop) { + dput(dentry); + dentry = ERR_PTR(-ENOENT); + } + } + + return dentry; +} + static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d, const char *name, unsigned int namelen, size_t prelen, const char *post, - struct dentry **ret) + struct dentry **ret, bool drop_negative) { struct dentry *this; int err; bool last_element = !post[0]; - this = lookup_positive_unlocked(name, base, namelen); + if (drop_negative) + this = ovl_lookup_positive_unlocked(name, base, namelen); + else + this = lookup_positive_unlocked(name, base, namelen); + if (IS_ERR(this)) { err = PTR_ERR(this); this = NULL; @@ -276,7 +306,7 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d, } static int ovl_lookup_layer(struct dentry *base, struct ovl_lookup_data *d, - struct dentry **ret) + struct dentry **ret, bool drop_negative) { /* Counting down from the end, since the prefix can change */ size_t rem = d->name.len - 1; @@ -285,7 +315,7 @@ static int ovl_lookup_layer(struct dentry *base, struct ovl_lookup_data *d, if (d->name.name[0] != '/') return ovl_lookup_single(base, d, d->name.name, d->name.len, - 0, "", ret); + 0, "", ret, drop_negative); while (!IS_ERR_OR_NULL(base) && d_can_lookup(base)) { const char *s = d->name.name + d->name.len - rem; @@ -298,7 +328,8 @@ static int ovl_lookup_layer(struct dentry *base, struct ovl_lookup_data *d, return -EIO; err = ovl_lookup_single(base, d, s, thislen, - d->name.len - rem, next, &base); + d->name.len - rem, next, &base, + drop_negative); dput(dentry); if (err) return err; @@ -830,7 +861,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, old_cred = ovl_override_creds(dentry->d_sb); upperdir = ovl_dentry_upper(dentry->d_parent); if (upperdir) { - err = ovl_lookup_layer(upperdir, &d, &upperdentry); + err = ovl_lookup_layer(upperdir, &d, &upperdentry, true); if (err) goto out; @@ -888,7 +919,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, else d.last = lower.layer->idx == roe->numlower; - err = ovl_lookup_layer(lower.dentry, &d, &this); + err = ovl_lookup_layer(lower.dentry, &d, &this, false); if (err) goto out_put;