From patchwork Thu Aug 30 21:55:06 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Waiman Long X-Patchwork-Id: 10582919 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 5BA3F5A4 for ; Thu, 30 Aug 2018 21:55:37 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4C62C2BE90 for ; Thu, 30 Aug 2018 21:55:37 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 3FE0B2C24B; Thu, 30 Aug 2018 21:55:37 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_NONE autolearn=unavailable version=3.3.1 Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 93F4F2C24A for ; Thu, 30 Aug 2018 21:55:36 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id D4D276B5395; Thu, 30 Aug 2018 17:55:30 -0400 (EDT) Delivered-To: linux-mm-outgoing@kvack.org Received: by kanga.kvack.org (Postfix, from userid 40) id C5D496B5397; Thu, 30 Aug 2018 17:55:30 -0400 (EDT) X-Original-To: int-list-linux-mm@kvack.org X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id AB15C6B5398; Thu, 30 Aug 2018 17:55:30 -0400 (EDT) X-Original-To: linux-mm@kvack.org X-Delivered-To: linux-mm@kvack.org Received: from mail-qt0-f199.google.com (mail-qt0-f199.google.com [209.85.216.199]) by kanga.kvack.org (Postfix) with ESMTP id 6C6516B5395 for ; Thu, 30 Aug 2018 17:55:30 -0400 (EDT) Received: by mail-qt0-f199.google.com with SMTP id e14-v6so10379427qtp.17 for ; Thu, 30 Aug 2018 14:55:30 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-original-authentication-results:x-gm-message-state:from:to:cc :subject:date:message-id:in-reply-to:references; bh=pDthHmUayMvAyYA01Z0SVkDMqF47g0eC4R9HaxByrIs=; b=VyxOZllAJu2tKjAJ8z5w+iiTiUVPfFIUNPHTdLL/uAIMJAFqekgfQFo7Hb4YM58GDM VJHUe9pFdakpWuC+LsaYs1cN5AMiZOLC/9ViDVe+eFnE/FjogN1JzV7vpgi14XTmBYbj smwLZeJGLfAYobvmKnL87XLIBe+0/3GS/A9fXW/EFp1ODqL04117KnSyd/VeaIS0mEnd hLPXNCboKMqT/Y3U2EyfrATB7yD1igjfCtWolInkuGSkcUhAkRQEC2+EJUakhV+GT6x2 0r6zUEbhfmuTTR8V7zLHa51g1ETEfulzxdlQ+1CneIx0CW5wnJveiCXGgSHjDLtex6eO gBkg== X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of longman@redhat.com designates 66.187.233.73 as permitted sender) smtp.mailfrom=longman@redhat.com; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com X-Gm-Message-State: APzg51BGaVeBPlEh5l9iJw0D9+MJpa2TJCHOZKF/cn5aLkNEGnPVRYSd DGbBIJgRPjrnmxZUpOB63Fr+1wqaZIjTJNkbfh7mbK9pAWJO1b3Dq4D6pIu3DKT3yuvRNZ7dmfK TkLFSP7qZOL6Q/EEoDm0tfyY7nft4n/UqKYnUtprWlJYx/caHxnnG4Vjn26p1msFJ5Q== X-Received: by 2002:ac8:2204:: with SMTP id o4-v6mr13394189qto.332.1535666130205; Thu, 30 Aug 2018 14:55:30 -0700 (PDT) X-Google-Smtp-Source: ANB0VdZeoZ7E3gbh+l+p+u4JqX4UBdhQ4/oJFKBjjQb+BUwpFrUKE/0PEjDHzfAQy9dIW0KIZGgX X-Received: by 2002:ac8:2204:: with SMTP id o4-v6mr13394158qto.332.1535666129343; Thu, 30 Aug 2018 14:55:29 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1535666129; cv=none; d=google.com; s=arc-20160816; b=mV2gdlN5b2wLHOzQANdsSj7Zi/jbhhNHKMnamHb+bWjwPUPR7/P9R7O6i7wUYJfn9L fN3QDh97yCXDyTwdDFLDsJixeP2fiEIIRqvAlV8BH7KweAybRuFnIJOSu6xjsWQE+T/C 0Q7HtYCKG6f4b1N1sXk/nMYMyAgSIsOdZ4aLoUN29Eo9b3TaPjPcd2/q7LTamfQD3BYk cimtKysRzfAhehdml8pczw6Ioz6CImNbP+zi8ir0pu9WwiSLMCx2dvxHeyoGaeQcJUkH QR7yHFURXXxCQE6QkJPSWVs5dX9UCuMrnNl5kjkFFgxbgHVZGk9ffqssNXaqF35OU/RD g1Fg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=pDthHmUayMvAyYA01Z0SVkDMqF47g0eC4R9HaxByrIs=; b=GJg/aQOrlySoVTwvKq/69xAbSTcGCXCZnzUj53qCWp1s2lFJcFxZUoEoKlIsd5Um1w OQWBUiRKhWf3osbTIfH5FEUwyTPi2/aF1sjhSUyzL0iqKdQec9wY1u6ciribeL6CWuMv rV7KR5dKTgZd8Fxt8GYRLlsaR7yss2picDCGLCsEjWrVDblYueq1yMHHgTO70wFm0xXF y4EEifO1aBEbINrfdUvAGgTlxfMDhIKauezt4FWc/LO+in4qKZYkvZOp9hhDcE4cQ0iW 7mfSuMHaZxUHD4XiDa99wkXk7bJ+gXfKDsTuPRJWgXYZnOS+Umw5oHa11xu+rUIAEiri dRkQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of longman@redhat.com designates 66.187.233.73 as permitted sender) smtp.mailfrom=longman@redhat.com; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: from mx1.redhat.com (mx3-rdu2.redhat.com. [66.187.233.73]) by mx.google.com with ESMTPS id z74-v6si6504328qkg.148.2018.08.30.14.55.29 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 30 Aug 2018 14:55:29 -0700 (PDT) Received-SPF: pass (google.com: domain of longman@redhat.com designates 66.187.233.73 as permitted sender) client-ip=66.187.233.73; Authentication-Results: mx.google.com; spf=pass (google.com: domain of longman@redhat.com designates 66.187.233.73 as permitted sender) smtp.mailfrom=longman@redhat.com; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id E44BE8151D46; Thu, 30 Aug 2018 21:55:28 +0000 (UTC) Received: from llong.com (dhcp-17-8.bos.redhat.com [10.18.17.8]) by smtp.corp.redhat.com (Postfix) with ESMTP id 5FD892157F4B; Thu, 30 Aug 2018 21:55:28 +0000 (UTC) From: Waiman Long To: Alexander Viro , Jonathan Corbet Cc: linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-mm@kvack.org, linux-doc@vger.kernel.org, "Luis R. Rodriguez" , Kees Cook , Linus Torvalds , Jan Kara , "Paul E. McKenney" , Andrew Morton , Ingo Molnar , Miklos Szeredi , Matthew Wilcox , Larry Woodman , James Bottomley , "Wangkai (Kevin C)" , Michal Hocko , Waiman Long Subject: [PATCH v2 3/4] fs/dcache: Track & report number of negative dentries Date: Thu, 30 Aug 2018 17:55:06 -0400 Message-Id: <1535666107-25699-4-git-send-email-longman@redhat.com> In-Reply-To: <1535666107-25699-1-git-send-email-longman@redhat.com> References: <1535666107-25699-1-git-send-email-longman@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Thu, 30 Aug 2018 21:55:29 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Thu, 30 Aug 2018 21:55:29 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'longman@redhat.com' RCPT:'' X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: X-Virus-Scanned: ClamAV using ClamSMTP The current dentry number tracking code doesn't distinguish between positive & negative dentries. It just reports the total number of dentries in the LRU lists. As excessive number of negative dentries can have an impact on system performance, it will be wise to track the number of positive and negative dentries separately. This patch adds tracking for the total number of negative dentries in the system LRU lists and reports it in the 7th field in the /proc/sys/fs/dentry-state file. The number, however, does not include negative dentries that are in flight but not in the LRU yet as well as those in the shrinker lists. The number of positive dentries in the LRU lists can be roughly found by subtracting the number of negative dentries from the unused count. Signed-off-by: Waiman Long --- Documentation/sysctl/fs.txt | 22 ++++++++++++++-------- fs/dcache.c | 31 +++++++++++++++++++++++++++++++ include/linux/dcache.h | 5 +++-- kernel/sysctl.c | 2 +- 4 files changed, 49 insertions(+), 11 deletions(-) diff --git a/Documentation/sysctl/fs.txt b/Documentation/sysctl/fs.txt index 819caf8..21679d0 100644 --- a/Documentation/sysctl/fs.txt +++ b/Documentation/sysctl/fs.txt @@ -56,26 +56,32 @@ of any kernel data structures. dentry-state: -From linux/fs/dentry.c: +From linux/include/linux/dcache.h: -------------------------------------------------------------- -struct { +struct dentry_stat_t dentry_stat { int nr_dentry; int nr_unused; int age_limit; /* age in seconds */ int want_pages; /* pages requested by system */ int dummy[2]; -} dentry_stat = {0, 0, 45, 0,}; --------------------------------------------------------------- + int nr_negative; /* # of unused negative dentries */ +}; +-------------------------------------------------------------- + +Dentries are dynamically allocated and deallocated. + +nr_dentry shows the total number of dentries allocated (active ++ unused). nr_unused shows the number of dentries that are not +actively used, but are saved in the LRU list for future reuse. -Dentries are dynamically allocated and deallocated, and -nr_dentry seems to be 0 all the time. Hence it's safe to -assume that only nr_unused, age_limit and want_pages are -used. Nr_unused seems to be exactly what its name says. Age_limit is the age in seconds after which dcache entries can be reclaimed when memory is short and want_pages is nonzero when shrink_dcache_pages() has been called and the dcache isn't pruned yet. +nr_negative shows the number of unused dentries that are also +negative dentries which do not mapped to actual files. + ============================================================== dquot-max & dquot-nr: diff --git a/fs/dcache.c b/fs/dcache.c index cb515f1..c1cc956 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -119,6 +119,7 @@ struct dentry_stat_t dentry_stat = { static DEFINE_PER_CPU(long, nr_dentry); static DEFINE_PER_CPU(long, nr_dentry_unused); +static DEFINE_PER_CPU(long, nr_dentry_negative); #if defined(CONFIG_SYSCTL) && defined(CONFIG_PROC_FS) @@ -152,11 +153,22 @@ static long get_nr_dentry_unused(void) return sum < 0 ? 0 : sum; } +static long get_nr_dentry_negative(void) +{ + int i; + long sum = 0; + + for_each_possible_cpu(i) + sum += per_cpu(nr_dentry_negative, i); + return sum < 0 ? 0 : sum; +} + int proc_nr_dentry(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { dentry_stat.nr_dentry = get_nr_dentry(); dentry_stat.nr_unused = get_nr_dentry_unused(); + dentry_stat.nr_negative = get_nr_dentry_negative(); return proc_doulongvec_minmax(table, write, buffer, lenp, ppos); } #endif @@ -331,6 +343,8 @@ static inline void __d_clear_type_and_inode(struct dentry *dentry) flags &= ~(DCACHE_ENTRY_TYPE | DCACHE_FALLTHRU); WRITE_ONCE(dentry->d_flags, flags); dentry->d_inode = NULL; + if (dentry->d_flags & DCACHE_LRU_LIST) + this_cpu_inc(nr_dentry_negative); } static void dentry_free(struct dentry *dentry) @@ -385,6 +399,10 @@ static void dentry_unlink_inode(struct dentry * dentry) * The per-cpu "nr_dentry_unused" counters are updated with * the DCACHE_LRU_LIST bit. * + * The per-cpu "nr_dentry_negative" counters are only updated + * when deleted or added to the per-superblock LRU list, not + * on the shrink list. + * * These helper functions make sure we always follow the * rules. d_lock must be held by the caller. */ @@ -394,6 +412,8 @@ static void d_lru_add(struct dentry *dentry) D_FLAG_VERIFY(dentry, 0); dentry->d_flags |= DCACHE_LRU_LIST; this_cpu_inc(nr_dentry_unused); + if (d_is_negative(dentry)) + this_cpu_inc(nr_dentry_negative); WARN_ON_ONCE(!list_lru_add(&dentry->d_sb->s_dentry_lru, &dentry->d_lru)); } @@ -402,6 +422,8 @@ static void d_lru_del(struct dentry *dentry) D_FLAG_VERIFY(dentry, DCACHE_LRU_LIST); dentry->d_flags &= ~DCACHE_LRU_LIST; this_cpu_dec(nr_dentry_unused); + if (d_is_negative(dentry)) + this_cpu_dec(nr_dentry_negative); WARN_ON_ONCE(!list_lru_del(&dentry->d_sb->s_dentry_lru, &dentry->d_lru)); } @@ -432,6 +454,8 @@ static void d_lru_isolate(struct list_lru_one *lru, struct dentry *dentry) D_FLAG_VERIFY(dentry, DCACHE_LRU_LIST); dentry->d_flags &= ~DCACHE_LRU_LIST; this_cpu_dec(nr_dentry_unused); + if (d_is_negative(dentry)) + this_cpu_dec(nr_dentry_negative); list_lru_isolate(lru, &dentry->d_lru); } @@ -440,6 +464,8 @@ static void d_lru_shrink_move(struct list_lru_one *lru, struct dentry *dentry, { D_FLAG_VERIFY(dentry, DCACHE_LRU_LIST); dentry->d_flags |= DCACHE_SHRINK_LIST; + if (d_is_negative(dentry)) + this_cpu_dec(nr_dentry_negative); list_lru_isolate_move(lru, &dentry->d_lru, list); } @@ -1836,6 +1862,11 @@ static void __d_instantiate(struct dentry *dentry, struct inode *inode) WARN_ON(d_in_lookup(dentry)); spin_lock(&dentry->d_lock); + /* + * Decrement negative dentry count if it was in the LRU list. + */ + if (dentry->d_flags & DCACHE_LRU_LIST) + this_cpu_dec(nr_dentry_negative); hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry); raw_write_seqcount_begin(&dentry->d_seq); __d_set_inode_and_type(dentry, inode, add_flags); diff --git a/include/linux/dcache.h b/include/linux/dcache.h index ef4b70f..619a249 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -62,9 +62,10 @@ struct qstr { struct dentry_stat_t { long nr_dentry; long nr_unused; - long age_limit; /* age in seconds */ - long want_pages; /* pages requested by system */ + long age_limit; /* age in seconds */ + long want_pages; /* pages requested by system */ long dummy[2]; + long nr_negative; /* # of unused negative dentries */ }; extern struct dentry_stat_t dentry_stat; diff --git a/kernel/sysctl.c b/kernel/sysctl.c index cc02050..77ff61c 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1708,7 +1708,7 @@ static int sysrq_sysctl_handler(struct ctl_table *table, int write, { .procname = "dentry-state", .data = &dentry_stat, - .maxlen = 6*sizeof(long), + .maxlen = 7*sizeof(long), .mode = 0444, .proc_handler = proc_nr_dentry, },