From patchwork Wed Jan 3 19:39:27 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Christoph Lameter (Ampere)" X-Patchwork-Id: 10142899 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id C00826034B for ; Wed, 3 Jan 2018 19:47:39 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B1CCA28485 for ; Wed, 3 Jan 2018 19:47:39 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A650029139; Wed, 3 Jan 2018 19:47:39 +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=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 33D7F28485 for ; Wed, 3 Jan 2018 19:47:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751196AbeACTri (ORCPT ); Wed, 3 Jan 2018 14:47:38 -0500 Received: from resqmta-ch2-07v.sys.comcast.net ([69.252.207.39]:49796 "EHLO resqmta-ch2-07v.sys.comcast.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750996AbeACTrh (ORCPT ); Wed, 3 Jan 2018 14:47:37 -0500 X-Greylist: delayed 488 seconds by postgrey-1.27 at vger.kernel.org; Wed, 03 Jan 2018 14:47:37 EST Received: from resomta-ch2-02v.sys.comcast.net ([69.252.207.98]) by resqmta-ch2-07v.sys.comcast.net with ESMTP id WosUebRPHnGJAWosre0Ts7; Wed, 03 Jan 2018 19:39:29 +0000 Received: from gentwo.org ([98.222.162.64]) by resomta-ch2-02v.sys.comcast.net with SMTP id WospesqrpHuFaWospe9fIf; Wed, 03 Jan 2018 19:39:29 +0000 Received: by gentwo.org (Postfix, from userid 1001) id 450EC1160189; Wed, 3 Jan 2018 13:39:27 -0600 (CST) Received: from localhost (localhost [127.0.0.1]) by gentwo.org (Postfix) with ESMTP id 41B851160184; Wed, 3 Jan 2018 13:39:27 -0600 (CST) Date: Wed, 3 Jan 2018 13:39:27 -0600 (CST) From: Christopher Lameter X-X-Sender: cl@nuc-kabylake To: Dave Chinner cc: linux-mm@kvack.org, linux-fsdevel@vger.kernel.org, Matthew Wilcox , Christoph Hellwig , Mel Gorman , Pekka Enberg Subject: [RFC] Heuristic for inode/dentry fragmentation prevention Message-ID: User-Agent: Alpine 2.20 (DEB 67 2015-01-07) MIME-Version: 1.0 X-CMAE-Envelope: MS4wfODuL6kjCre0x7QEVfZ0dTch5Wiz0+SqAicQmFGWMn9KlIxZk6OzLBF+C2H6JxK5sSqeZ3n9SHOT5Wx3FLdQ02Qe4pEK9sz32N0Jv6LjrXKRtrjYoz86 t3lWr0tocv5uG1FZFM6A8fDD+Gg75qeozx5zchTawRYWF6I72ldLCobTYE39WRsPS6LryM0AiIG5SPNJgrNLN/7FeUBAj3ZoV2PMi6j7so/z9LBCMb3b1tfe r8gdp20iw8QQMllVF5wtdSfqoPom7qzHO4cbBXqeN5dg2Tgm6UWa80EBxaT8sUMSvlTEKdkULGnBqz69SFgd+Sqqsja40Q23mJxfP0hjhCc= Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP I was looking at the inode/dentry reclaim code today and I thought there is an obvious and easy to implement way to avoid fragmentation by checking the number of objects in a slab page. Subject: Heuristic for fragmentation prevention for inode and dentry caches When freeing dentries and inodes we often get to the situation that a slab page cannot be freed because there is only a single object left in that slab page. We add a new function to the slab allocators that returns the number of objects in the same slab page. Then the dentry and inode logic can check if such a situation exits and take measures to try to reclaim that entry sooner. In this patch the check if an inode or dentry has been referenced (and thus should be kept) is skipped if the freeing of the object would result in the slab page becoming available. That will cause overhead in terms of having to re-allocate and generate the inoden or dentry but in all likelyhood the inode or dentry will then be allocated in a slab page that already contains other inodes or dentries. Thus fragmentation is reduced. Signed-off-by: Christopher Lameter Index: linux/include/linux/slab.h =================================================================== --- linux.orig/include/linux/slab.h +++ linux/include/linux/slab.h @@ -165,6 +165,7 @@ void * __must_check krealloc(const void void kfree(const void *); void kzfree(const void *); size_t ksize(const void *); +unsigned kobjects_left_in_slab_page(const void *); #ifdef CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR const char *__check_heap_object(const void *ptr, unsigned long n, Index: linux/mm/slab.c =================================================================== --- linux.orig/mm/slab.c +++ linux/mm/slab.c @@ -4446,3 +4446,24 @@ size_t ksize(const void *objp) return size; } EXPORT_SYMBOL(ksize); + +/* How many objects left in slab page */ +unsigned kobjects_left_in_slab_page(const void *object) +{ + struct page *page; + + if (unlikely(ZERO_OR_NULL_PTR(object))) + return 0; + + page = virt_to_head_page(object); + + if (unlikely(!PageSlab(page))) { + WARN_ON(1); + return 1; + } + + return page->active; +} +EXPORT_SYMBOL(kobjects_left_in_slab_page); + + Index: linux/mm/slub.c =================================================================== --- linux.orig/mm/slub.c +++ linux/mm/slub.c @@ -3879,6 +3879,25 @@ size_t ksize(const void *object) } EXPORT_SYMBOL(ksize); +/* How many objects left in slab page */ +unsigned kobjects_left_in_slab_page(const void *object) +{ + struct page *page; + + if (unlikely(ZERO_OR_NULL_PTR(object))) + return 0; + + page = virt_to_head_page(object); + + if (unlikely(!PageSlab(page))) { + WARN_ON(!PageCompound(page)); + return 1; + } + + return page->inuse; +} +EXPORT_SYMBOL(kobjects_left_in_slab_page); + void kfree(const void *x) { struct page *page; Index: linux/fs/dcache.c =================================================================== --- linux.orig/fs/dcache.c +++ linux/fs/dcache.c @@ -1074,7 +1074,8 @@ static enum lru_status dentry_lru_isolat return LRU_REMOVED; } - if (dentry->d_flags & DCACHE_REFERENCED) { + if (dentry->d_flags & DCACHE_REFERENCED && + kobjects_left_in_slab_page(dentry) > 1) { dentry->d_flags &= ~DCACHE_REFERENCED; spin_unlock(&dentry->d_lock); Index: linux/fs/inode.c =================================================================== --- linux.orig/fs/inode.c +++ linux/fs/inode.c @@ -725,8 +725,12 @@ static enum lru_status inode_lru_isolate return LRU_REMOVED; } - /* recently referenced inodes get one more pass */ - if (inode->i_state & I_REFERENCED) { + /* + * Recently referenced inodes get one more pass + * if they are not the only objects in a slab page + */ + if (inode->i_state & I_REFERENCED && + kobjects_left_in_slab_page(inode) > 1) { inode->i_state &= ~I_REFERENCED; spin_unlock(&inode->i_lock); return LRU_ROTATE;