From patchwork Fri Feb 12 20:14:39 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Daniel Walker (danielwa)" X-Patchwork-Id: 8297171 Return-Path: X-Original-To: patchwork-linux-fsdevel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id F010EC02AA for ; Fri, 12 Feb 2016 20:14:59 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id DF00320435 for ; Fri, 12 Feb 2016 20:14:58 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id C04FB20121 for ; Fri, 12 Feb 2016 20:14:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1750890AbcBLUOn (ORCPT ); Fri, 12 Feb 2016 15:14:43 -0500 Received: from alln-iport-7.cisco.com ([173.37.142.94]:9277 "EHLO alln-iport-7.cisco.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750714AbcBLUOm (ORCPT ); Fri, 12 Feb 2016 15:14:42 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=cisco.com; i=@cisco.com; l=6536; q=dns/txt; s=iport; t=1455308082; x=1456517682; h=from:to:cc:subject:date:message-id; bh=+kVN3cfAhegvL94PUDsooLjQwTWPFsx1bzqYpT4WuVk=; b=Pk7nOfqQoePEXtYY/88wI5B3E/ePm+MT/eqRLDEtfy5fdU1392mVpeiv EWvNgaEpY8wqKu5MbIjP2v8kRdVfXQjsMm26Lm9ne2+7k8cnku3Mf23xQ AOKzT/GPKjzLMB5pdnUFG/nHEGT8bK/8mVXrTdA1L0AYm1+3Xcy/TDsjk 0=; X-IronPort-AV: E=Sophos;i="5.22,437,1449532800"; d="scan'208";a="237881918" Received: from alln-core-7.cisco.com ([173.36.13.140]) by alln-iport-7.cisco.com with ESMTP/TLS/DHE-RSA-AES256-SHA; 12 Feb 2016 20:14:41 +0000 Received: from zorba.cisco.com ([10.21.172.23]) by alln-core-7.cisco.com (8.14.5/8.14.5) with ESMTP id u1CKEeIB028979; Fri, 12 Feb 2016 20:14:40 GMT From: Daniel Walker To: Alexander Viro Cc: Khalid Mughal , xe-kernel@external.cisco.com, dave.hansen@intel.com, hannes@cmpxchg.org, riel@redhat.com, Jonathan Corbet , linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-mm@kvack.org Subject: [PATCH] kernel: fs: drop_caches: add dds drop_caches_count Date: Fri, 12 Feb 2016 12:14:39 -0800 Message-Id: <1455308080-27238-1-git-send-email-danielwa@cisco.com> X-Mailer: git-send-email 2.5.0 X-Auto-Response-Suppress: DR, OOF, AutoReply Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org X-Spam-Status: No, score=-14.6 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY, USER_IN_DEF_DKIM_WL autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Khalid Mughal Currently there is no way to figure out the droppable pagecache size from the meminfo output. The MemFree size can shrink during normal system operation, when some of the memory pages get cached and is reflected in "Cached" field. Similarly for file operations some of the buffer memory gets cached and it is reflected in "Buffers" field. The kernel automatically reclaims all this cached & buffered memory, when it is needed elsewhere on the system. The only way to manually reclaim this memory is by writing 1 to /proc/sys/vm/drop_caches. But this can have performance impact. Since it discards cached objects, it may cause high CPU & I/O utilization to recreate the dropped objects during heavy system load. This patch computes the droppable pagecache count, using same algorithm as "vm/drop_caches". It is non-destructive and does not drop any pages. Therefore it does not have any impact on system performance. The computation does not include the size of reclaimable slab. Cc: xe-kernel@external.cisco.com Cc: dave.hansen@intel.com Cc: hannes@cmpxchg.org Cc: riel@redhat.com Signed-off-by: Khalid Mughal Signed-off-by: Daniel Walker --- Documentation/sysctl/vm.txt | 12 +++++++ fs/drop_caches.c | 80 +++++++++++++++++++++++++++++++++++++++++++-- include/linux/mm.h | 3 ++ kernel/sysctl.c | 7 ++++ 4 files changed, 100 insertions(+), 2 deletions(-) diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt index 89a887c..13a501c 100644 --- a/Documentation/sysctl/vm.txt +++ b/Documentation/sysctl/vm.txt @@ -29,6 +29,7 @@ Currently, these files are in /proc/sys/vm: - dirty_ratio - dirty_writeback_centisecs - drop_caches +- drop_caches_count - extfrag_threshold - hugepages_treat_as_movable - hugetlb_shm_group @@ -224,6 +225,17 @@ with your system. To disable them, echo 4 (bit 3) into drop_caches. ============================================================== +drop_caches_count + +The amount of droppable pagecache (in kilobytes). Reading this file +performs same calculation as writing 1 to /proc/sys/vm/drop_caches. +The actual pages are not dropped during computation of this value. + +To read the value: + cat /proc/sys/vm/drop_caches_count + +============================================================== + extfrag_threshold This parameter affects whether the kernel will compact memory or direct diff --git a/fs/drop_caches.c b/fs/drop_caches.c index d72d52b..0cb2186 100644 --- a/fs/drop_caches.c +++ b/fs/drop_caches.c @@ -8,12 +8,73 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include + #include "internal.h" /* A global variable is a bit ugly, but it keeps the code simple */ + int sysctl_drop_caches; +unsigned int sysctl_drop_caches_count; + +static int is_page_droppable(struct page *page) +{ + struct address_space *mapping = page_mapping(page); + + if (!mapping) + return 0; + if (PageDirty(page)) + return 0; + if (PageWriteback(page)) + return 0; + if (page_mapped(page)) + return 0; + if (page->mapping != mapping) + return 0; + if (page_has_private(page)) + return 0; + return 1; +} + +static unsigned long count_unlocked_pages(struct address_space *mapping) +{ + struct pagevec pvec; + pgoff_t start = 0; + pgoff_t end = -1; + unsigned long count = 0; + int i; + int rc; + + pagevec_init(&pvec, 0); + while (start <= end && pagevec_lookup(&pvec, mapping, start, + min(end - start, (pgoff_t)PAGEVEC_SIZE - 1) + 1)) { + for (i = 0; i < pagevec_count(&pvec); i++) { + struct page *page = pvec.pages[i]; + start = page->index; + if (start > end) + break; + if (!trylock_page(page)) + continue; + WARN_ON(page->index != start); + rc = is_page_droppable(page); + unlock_page(page); + count += rc; + } + pagevec_release(&pvec); + cond_resched(); + start++; + } + return count; +} -static void drop_pagecache_sb(struct super_block *sb, void *unused) +static void drop_pagecache_sb(struct super_block *sb, void *count) { struct inode *inode, *toput_inode = NULL; @@ -29,7 +90,11 @@ static void drop_pagecache_sb(struct super_block *sb, void *unused) spin_unlock(&inode->i_lock); spin_unlock(&sb->s_inode_list_lock); - invalidate_mapping_pages(inode->i_mapping, 0, -1); + if (count) + sysctl_drop_caches_count += count_unlocked_pages(inode->i_mapping); + else + invalidate_mapping_pages(inode->i_mapping, 0, -1); + iput(toput_inode); toput_inode = inode; @@ -67,3 +132,14 @@ int drop_caches_sysctl_handler(struct ctl_table *table, int write, } return 0; } + +int drop_caches_count_sysctl_handler(struct ctl_table *table, int write, + void __user *buffer, size_t *length, loff_t *ppos) +{ + int ret = 0; + sysctl_drop_caches_count = nr_blockdev_pages(); + iterate_supers(drop_pagecache_sb, &sysctl_drop_caches_count); + sysctl_drop_caches_count <<= (PAGE_SHIFT - 10); /* count in KBytes */ + ret = proc_dointvec_minmax(table, write, buffer, length, ppos); + return ret; +} diff --git a/include/linux/mm.h b/include/linux/mm.h index f1cd22f..02ebd41 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -2220,8 +2220,11 @@ static inline int in_gate_area(struct mm_struct *mm, unsigned long addr) #ifdef CONFIG_SYSCTL extern int sysctl_drop_caches; +extern unsigned int sysctl_drop_caches_count; int drop_caches_sysctl_handler(struct ctl_table *, int, void __user *, size_t *, loff_t *); +int drop_caches_count_sysctl_handler(struct ctl_table *, int, + void __user *, size_t *, loff_t *); #endif void drop_slab(void); diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 97715fd..c043175 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1356,6 +1356,13 @@ static struct ctl_table vm_table[] = { .extra1 = &one, .extra2 = &four, }, + { + .procname = "drop_caches_count", + .data = &sysctl_drop_caches_count, + .maxlen = sizeof(unsigned int), + .mode = 0444, + .proc_handler = drop_caches_count_sysctl_handler, + }, #ifdef CONFIG_COMPACTION { .procname = "compact_memory",