From patchwork Wed Jun 19 22:33:02 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Duyck X-Patchwork-Id: 11005515 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 6F3DA76 for ; Wed, 19 Jun 2019 22:33:11 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5E44028807 for ; Wed, 19 Jun 2019 22:33:11 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 522B828841; Wed, 19 Jun 2019 22:33:11 +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=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=unavailable 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 A9CA728807 for ; Wed, 19 Jun 2019 22:33:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730773AbfFSWdG (ORCPT ); Wed, 19 Jun 2019 18:33:06 -0400 Received: from mail-io1-f66.google.com ([209.85.166.66]:43549 "EHLO mail-io1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726496AbfFSWdG (ORCPT ); Wed, 19 Jun 2019 18:33:06 -0400 Received: by mail-io1-f66.google.com with SMTP id k20so1079951ios.10; Wed, 19 Jun 2019 15:33:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=subject:from:to:cc:date:message-id:in-reply-to:references :user-agent:mime-version:content-transfer-encoding; bh=F/9CnX80uREAl0+uDwGFKwrKVTkwRc085X3OG7yt7+w=; b=u+Tng6Wd+9EcoTeB9cOi6UNvkOs30SqWYHHObrN0enKv7O9KSLMiJD+B/m7FDKJobp U15+Gevz191I0isHqbdBxybXGLbmWa590iXaWpF8tJZe4fvVvAeOI8SN5hl95qKkIwoG 4qVHJ63fZemQZXHnbmPQtO/b+uc8oH1nGjGoTFoM3a9+zq5FLUEpSqi3eagsTQsilwEH dC5xSnZPPX1uZ7XXNyYEgZukguxMfADOHl74s7AMg7zLHZSC/fsgG7trQfTec/h3X5V9 feQWHkTkGhr1LKTcQ0pQjayjm8Vm9lUAojKvfGGtuj/RxUTP0h7ovzS+g/QizvRyss2e GmvA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:from:to:cc:date:message-id:in-reply-to :references:user-agent:mime-version:content-transfer-encoding; bh=F/9CnX80uREAl0+uDwGFKwrKVTkwRc085X3OG7yt7+w=; b=G4/8JHJx2SiePBfd0l3EbYR80tMXoFB52LPDu541+jCJ+HT4DdZkB+y7pkCqOJ2Skf v3DqkBZaVNObX25ELrdhtYLkVjwSjjL5AHrJLMYQGxITuZ1lDrC1gqjsYApHuSqb5nGt 4G3oSKJMkf8xibsUpXt58HzLgh3YEZIBZAELFuaePVhhQ3k7v2Q0GIvVZRj6lExny9vg akhAVRsdSyBGWsgppTUuCO303mr9halvMTlBSWSf+zXdqbWWkffRMCsBalcBo2Jb9iuY HOOsaAxZUCV0yA3+knZ85H0gDB+n9kwgZeJMptbxwW9CykhLIpc/KDQCvyNlucciTpog doUA== X-Gm-Message-State: APjAAAWIVva/1zDU4drOGoplQsqgHvR49LWWXo2sVHWb0HmdIM9Ws5kr CupaA7IGWgTdt8T3mA5cSLY= X-Google-Smtp-Source: APXvYqw4o8A6+PG9trd+RXJLq8lvf+5YtSoaew5wEQ4VMk70V7RQw3K9/H0udPCiWZ9wgQwxtWgceQ== X-Received: by 2002:a02:11c2:: with SMTP id 185mr39139210jaf.8.1560983584277; Wed, 19 Jun 2019 15:33:04 -0700 (PDT) Received: from localhost.localdomain (50-126-100-225.drr01.csby.or.frontiernet.net. [50.126.100.225]) by smtp.gmail.com with ESMTPSA id i23sm13270218ioj.24.2019.06.19.15.33.02 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 19 Jun 2019 15:33:03 -0700 (PDT) Subject: [PATCH v1 1/6] mm: Adjust shuffle code to allow for future coalescing From: Alexander Duyck To: nitesh@redhat.com, kvm@vger.kernel.org, david@redhat.com, mst@redhat.com, dave.hansen@intel.com, linux-kernel@vger.kernel.org, linux-mm@kvack.org, akpm@linux-foundation.org Cc: yang.zhang.wz@gmail.com, pagupta@redhat.com, riel@surriel.com, konrad.wilk@oracle.com, lcapitulino@redhat.com, wei.w.wang@intel.com, aarcange@redhat.com, pbonzini@redhat.com, dan.j.williams@intel.com, alexander.h.duyck@linux.intel.com Date: Wed, 19 Jun 2019 15:33:02 -0700 Message-ID: <20190619223302.1231.51136.stgit@localhost.localdomain> In-Reply-To: <20190619222922.1231.27432.stgit@localhost.localdomain> References: <20190619222922.1231.27432.stgit@localhost.localdomain> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Alexander Duyck This patch is meant to move the head/tail adding logic out of the shuffle code and into the __free_one_page function since ultimately that is where it is really needed anyway. By doing this we should be able to reduce the overhead and can consolidate all of the list addition bits in one spot. Signed-off-by: Alexander Duyck Reviewed-by: Dave Hansen --- include/linux/mmzone.h | 12 -------- mm/page_alloc.c | 70 +++++++++++++++++++++++++++--------------------- mm/shuffle.c | 24 ---------------- mm/shuffle.h | 35 ++++++++++++++++++++++++ 4 files changed, 74 insertions(+), 67 deletions(-) diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 427b79c39b3c..4c07af2cfc2f 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -116,18 +116,6 @@ static inline void add_to_free_area_tail(struct page *page, struct free_area *ar area->nr_free++; } -#ifdef CONFIG_SHUFFLE_PAGE_ALLOCATOR -/* Used to preserve page allocation order entropy */ -void add_to_free_area_random(struct page *page, struct free_area *area, - int migratetype); -#else -static inline void add_to_free_area_random(struct page *page, - struct free_area *area, int migratetype) -{ - add_to_free_area(page, area, migratetype); -} -#endif - /* Used for pages which are on another list */ static inline void move_to_free_area(struct page *page, struct free_area *area, int migratetype) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index f4651a09948c..ec344ce46587 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -830,6 +830,36 @@ static inline struct capture_control *task_capc(struct zone *zone) #endif /* CONFIG_COMPACTION */ /* + * If this is not the largest possible page, check if the buddy + * of the next-highest order is free. If it is, it's possible + * that pages are being freed that will coalesce soon. In case, + * that is happening, add the free page to the tail of the list + * so it's less likely to be used soon and more likely to be merged + * as a higher order page + */ +static inline bool +buddy_merge_likely(unsigned long pfn, unsigned long buddy_pfn, + struct page *page, unsigned int order) +{ + struct page *higher_page, *higher_buddy; + unsigned long combined_pfn; + + if (is_shuffle_order(order) || order >= (MAX_ORDER - 2)) + return false; + + if (!pfn_valid_within(buddy_pfn)) + return false; + + combined_pfn = buddy_pfn & pfn; + higher_page = page + (combined_pfn - pfn); + buddy_pfn = __find_buddy_pfn(combined_pfn, order + 1); + higher_buddy = higher_page + (buddy_pfn - combined_pfn); + + return pfn_valid_within(buddy_pfn) && + page_is_buddy(higher_page, higher_buddy, order + 1); +} + +/* * Freeing function for a buddy system allocator. * * The concept of a buddy system is to maintain direct-mapped table @@ -858,11 +888,12 @@ static inline void __free_one_page(struct page *page, struct zone *zone, unsigned int order, int migratetype) { - unsigned long combined_pfn; + struct capture_control *capc = task_capc(zone); unsigned long uninitialized_var(buddy_pfn); - struct page *buddy; + unsigned long combined_pfn; + struct free_area *area; unsigned int max_order; - struct capture_control *capc = task_capc(zone); + struct page *buddy; max_order = min_t(unsigned int, MAX_ORDER, pageblock_order + 1); @@ -931,35 +962,12 @@ static inline void __free_one_page(struct page *page, done_merging: set_page_order(page, order); - /* - * If this is not the largest possible page, check if the buddy - * of the next-highest order is free. If it is, it's possible - * that pages are being freed that will coalesce soon. In case, - * that is happening, add the free page to the tail of the list - * so it's less likely to be used soon and more likely to be merged - * as a higher order page - */ - if ((order < MAX_ORDER-2) && pfn_valid_within(buddy_pfn) - && !is_shuffle_order(order)) { - struct page *higher_page, *higher_buddy; - combined_pfn = buddy_pfn & pfn; - higher_page = page + (combined_pfn - pfn); - buddy_pfn = __find_buddy_pfn(combined_pfn, order + 1); - higher_buddy = higher_page + (buddy_pfn - combined_pfn); - if (pfn_valid_within(buddy_pfn) && - page_is_buddy(higher_page, higher_buddy, order + 1)) { - add_to_free_area_tail(page, &zone->free_area[order], - migratetype); - return; - } - } - - if (is_shuffle_order(order)) - add_to_free_area_random(page, &zone->free_area[order], - migratetype); + area = &zone->free_area[order]; + if (buddy_merge_likely(pfn, buddy_pfn, page, order) || + is_shuffle_tail_page(order)) + add_to_free_area_tail(page, area, migratetype); else - add_to_free_area(page, &zone->free_area[order], migratetype); - + add_to_free_area(page, area, migratetype); } /* diff --git a/mm/shuffle.c b/mm/shuffle.c index 3ce12481b1dc..55d592e62526 100644 --- a/mm/shuffle.c +++ b/mm/shuffle.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include "internal.h" #include "shuffle.h" @@ -182,26 +181,3 @@ void __meminit __shuffle_free_memory(pg_data_t *pgdat) for (z = pgdat->node_zones; z < pgdat->node_zones + MAX_NR_ZONES; z++) shuffle_zone(z); } - -void add_to_free_area_random(struct page *page, struct free_area *area, - int migratetype) -{ - static u64 rand; - static u8 rand_bits; - - /* - * The lack of locking is deliberate. If 2 threads race to - * update the rand state it just adds to the entropy. - */ - if (rand_bits == 0) { - rand_bits = 64; - rand = get_random_u64(); - } - - if (rand & 1) - add_to_free_area(page, area, migratetype); - else - add_to_free_area_tail(page, area, migratetype); - rand_bits--; - rand >>= 1; -} diff --git a/mm/shuffle.h b/mm/shuffle.h index 777a257a0d2f..3f4edb60a453 100644 --- a/mm/shuffle.h +++ b/mm/shuffle.h @@ -3,6 +3,7 @@ #ifndef _MM_SHUFFLE_H #define _MM_SHUFFLE_H #include +#include /* * SHUFFLE_ENABLE is called from the command line enabling path, or by @@ -43,6 +44,35 @@ static inline bool is_shuffle_order(int order) return false; return order >= SHUFFLE_ORDER; } + +static inline bool is_shuffle_tail_page(int order) +{ + static u64 rand; + static u8 rand_bits; + u64 rand_old; + + if (!is_shuffle_order(order)) + return false; + + /* + * The lack of locking is deliberate. If 2 threads race to + * update the rand state it just adds to the entropy. + */ + if (rand_bits-- == 0) { + rand_bits = 64; + rand = get_random_u64(); + } + + /* + * Test highest order bit while shifting our random value. This + * should result in us testing for the carry flag following the + * shift. + */ + rand_old = rand; + rand <<= 1; + + return rand < rand_old; +} #else static inline void shuffle_free_memory(pg_data_t *pgdat) { @@ -60,5 +90,10 @@ static inline bool is_shuffle_order(int order) { return false; } + +static inline bool is_shuffle_tail_page(int order) +{ + return false; +} #endif #endif /* _MM_SHUFFLE_H */ From patchwork Wed Jun 19 22:33:09 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Duyck X-Patchwork-Id: 11005519 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 D38BE76 for ; Wed, 19 Jun 2019 22:33:17 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id BFEF028807 for ; Wed, 19 Jun 2019 22:33:17 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B3FA928841; Wed, 19 Jun 2019 22:33:17 +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=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=unavailable 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 5D1CA28807 for ; Wed, 19 Jun 2019 22:33:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730819AbfFSWdM (ORCPT ); Wed, 19 Jun 2019 18:33:12 -0400 Received: from mail-io1-f68.google.com ([209.85.166.68]:33499 "EHLO mail-io1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730730AbfFSWdM (ORCPT ); Wed, 19 Jun 2019 18:33:12 -0400 Received: by mail-io1-f68.google.com with SMTP id u13so1460663iop.0; Wed, 19 Jun 2019 15:33:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=subject:from:to:cc:date:message-id:in-reply-to:references :user-agent:mime-version:content-transfer-encoding; bh=NZX9ozjZ+h++nQ9qTzVYYR055FmQZfSwp2MFV40l/Yg=; b=AykkqRY/B8jQYskC0hBeay6QNRuqle2AeMVGLRM8LvJGbh2o+2wLfzsOBZFBEUIu9Y qCSO6NhEds2PvgNyNoMgHAKvxivTIw9RwSJ2CdlS5Zm4U/SjABUyMfAwNpnYf6X+WqnU M7/QbmMXRZZlCzuk9OblJhNYm0tZmX+NxWi693yH6wo7MWpwFAdRKQlJ3U1fwg0m6f0P 2iROcjzO+q3Rrm3wki11NzixozRES4o5dJ10ciG8N9BtseIWAF4Tn0T3o8HgFZWUpeLy Un960tboJzppnKgY/ELquoAi59xkBmskrUyQsnEHENGdgSl3UiTCXoyywpupYHnM0Rdg I9Ow== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:from:to:cc:date:message-id:in-reply-to :references:user-agent:mime-version:content-transfer-encoding; bh=NZX9ozjZ+h++nQ9qTzVYYR055FmQZfSwp2MFV40l/Yg=; b=SZEDujrAHkEXTT5irJxtVGK7PMwhW1r11WqLOcvefWd39vho77Zqf71/lbdt6aHfzi uE0BNflP652fOLnMkdvGdyshoRZXR++U9dAmTW+RiJ/xznUhceD4h7JUeUgVmyKOCzpc nhiyc2CYoB39wt2S/I5iAPgau9acDEyLA0wI0tptBT0HgBUvzGatIyUjPgWjhbU7Bs8i 6pYlFTZ2xfL0aSHlDteWUq747qvJXWr5TPNbISugMo9MurUfecgkqZkhxIfI/faIZ+jp WFzZFa+Z99eG/cDcvvKUkqZ9JHjOZKhmPOslP7IXMQ8VhKZbWFRFJjysCSnyRHA5fHCk +dCQ== X-Gm-Message-State: APjAAAVKepplJl37QrcQKMEg5aG+eewCyrB0R6noPxWnEIwt27/IztRS lkXk/Ahx6T6aBBgNMeKUMSY= X-Google-Smtp-Source: APXvYqwRnLuDFzAfR5lMoUpbGfuz69Ko0BWafruD9h5MagTA3O8l8M6s6sqfE+SW8RL4CMOIW1ybvA== X-Received: by 2002:a02:5489:: with SMTP id t131mr97296596jaa.70.1560983591570; Wed, 19 Jun 2019 15:33:11 -0700 (PDT) Received: from localhost.localdomain (50-126-100-225.drr01.csby.or.frontiernet.net. [50.126.100.225]) by smtp.gmail.com with ESMTPSA id q13sm17804752ioh.36.2019.06.19.15.33.09 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 19 Jun 2019 15:33:11 -0700 (PDT) Subject: [PATCH v1 2/6] mm: Move set/get_pcppage_migratetype to mmzone.h From: Alexander Duyck To: nitesh@redhat.com, kvm@vger.kernel.org, david@redhat.com, mst@redhat.com, dave.hansen@intel.com, linux-kernel@vger.kernel.org, linux-mm@kvack.org, akpm@linux-foundation.org Cc: yang.zhang.wz@gmail.com, pagupta@redhat.com, riel@surriel.com, konrad.wilk@oracle.com, lcapitulino@redhat.com, wei.w.wang@intel.com, aarcange@redhat.com, pbonzini@redhat.com, dan.j.williams@intel.com, alexander.h.duyck@linux.intel.com Date: Wed, 19 Jun 2019 15:33:09 -0700 Message-ID: <20190619223309.1231.16506.stgit@localhost.localdomain> In-Reply-To: <20190619222922.1231.27432.stgit@localhost.localdomain> References: <20190619222922.1231.27432.stgit@localhost.localdomain> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Alexander Duyck In order to support page aeration it will be necessary to store and retrieve the migratetype of a page. To enable that I am moving the set and get operations for pcppage_migratetype into the mmzone header so that they can be used when adding or removing pages from the free lists. Signed-off-by: Alexander Duyck --- include/linux/mmzone.h | 18 ++++++++++++++++++ mm/page_alloc.c | 18 ------------------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 4c07af2cfc2f..6f8fd5c1a286 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -95,6 +95,24 @@ static inline bool is_migrate_movable(int mt) get_pfnblock_flags_mask(page, page_to_pfn(page), \ PB_migrate_end, MIGRATETYPE_MASK) +/* + * A cached value of the page's pageblock's migratetype, used when the page is + * put on a pcplist. Used to avoid the pageblock migratetype lookup when + * freeing from pcplists in most cases, at the cost of possibly becoming stale. + * Also the migratetype set in the page does not necessarily match the pcplist + * index, e.g. page might have MIGRATE_CMA set but be on a pcplist with any + * other index - this ensures that it will be put on the correct CMA freelist. + */ +static inline int get_pcppage_migratetype(struct page *page) +{ + return page->index; +} + +static inline void set_pcppage_migratetype(struct page *page, int migratetype) +{ + page->index = migratetype; +} + struct free_area { struct list_head free_list[MIGRATE_TYPES]; unsigned long nr_free; diff --git a/mm/page_alloc.c b/mm/page_alloc.c index ec344ce46587..3e21e01f6165 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -136,24 +136,6 @@ struct pcpu_drain { int percpu_pagelist_fraction; gfp_t gfp_allowed_mask __read_mostly = GFP_BOOT_MASK; -/* - * A cached value of the page's pageblock's migratetype, used when the page is - * put on a pcplist. Used to avoid the pageblock migratetype lookup when - * freeing from pcplists in most cases, at the cost of possibly becoming stale. - * Also the migratetype set in the page does not necessarily match the pcplist - * index, e.g. page might have MIGRATE_CMA set but be on a pcplist with any - * other index - this ensures that it will be put on the correct CMA freelist. - */ -static inline int get_pcppage_migratetype(struct page *page) -{ - return page->index; -} - -static inline void set_pcppage_migratetype(struct page *page, int migratetype) -{ - page->index = migratetype; -} - #ifdef CONFIG_PM_SLEEP /* * The following functions are used by the suspend/hibernate code to temporarily From patchwork Wed Jun 19 22:33:16 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Duyck X-Patchwork-Id: 11005531 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 8F9CA13AF for ; Wed, 19 Jun 2019 22:33:41 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7F7A728807 for ; Wed, 19 Jun 2019 22:33:41 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 733E428841; Wed, 19 Jun 2019 22:33:41 +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=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=unavailable 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 CAC6428807 for ; Wed, 19 Jun 2019 22:33:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730860AbfFSWdU (ORCPT ); Wed, 19 Jun 2019 18:33:20 -0400 Received: from mail-io1-f68.google.com ([209.85.166.68]:45341 "EHLO mail-io1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730850AbfFSWdT (ORCPT ); Wed, 19 Jun 2019 18:33:19 -0400 Received: by mail-io1-f68.google.com with SMTP id e3so1255669ioc.12; Wed, 19 Jun 2019 15:33:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=subject:from:to:cc:date:message-id:in-reply-to:references :user-agent:mime-version:content-transfer-encoding; bh=C0Bf7M/8cNMTOD5Oi+UUTlzGK+ofWvIbu+KdmI1IyVU=; b=Eoulzf7P/OMOo6UZcSrsWbKXBQDMcqi3Lt3uX4516MwL+PQ9++SEChgXNQyFiosCTa XTg4LkxnkpTckIHJnEJlp1MYaY4Lt9wnn8HkSZOd+pw3HaJjj732wmiSM4cNNILGt3j9 ob7q+r/GhMWZrGJXnvmKGggYinS7vRlPyrluqnSjmvM0S3oIFGkV/Y8T1hizTV1BXYdb VtKWtXd+Vk/aqzxcjxtAP7m9CzCvIbAfYlzjvQWSXcgr9seH89NFUgRwO3gzSV3K4AsT pXF8Foro/42GRqNcJN2OP1EPhgLYDRqVardVtEb7/SbHc5T2/log0PBLWrXz8DwOWHRm B+fQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:from:to:cc:date:message-id:in-reply-to :references:user-agent:mime-version:content-transfer-encoding; bh=C0Bf7M/8cNMTOD5Oi+UUTlzGK+ofWvIbu+KdmI1IyVU=; b=L7DlA0aiCOXsTfs1AKvqzboW6z7PPI2qgDT/FUgosACqiN2a+VbBJ2pOiixJ0zG8X9 gPHfD5kbjzxfu94DHNhYA1we1Sy5vv99XGSdN/+ifQSqaHHGE00ho8MhEk7XcJbMfBF/ pNxE/ri5rzkABNb6SV7OI6KDZaPiosK6Hgn1Gn/y3YC9jEJO7JZuQaZmn1W1hRS+tT3H Beq9bbHj+LbSErPDZpbpwwlS2lonwljqXNQeZQfruVXL715atDNgm2l5ZQtYp+s8fxXP j2RbZEbOX0pWOrYr5SOge3GU2f5J6zmgZjq7BKgMB27C9tWiUor9KxaxSvnKEDubjaFI Jl+g== X-Gm-Message-State: APjAAAUhT1JSyMew542sXgIVU58UK50lEQV+cv+bSUDt0vMCEwXPi9q2 Ifsy5J5s8EID4mQ156ACS0g= X-Google-Smtp-Source: APXvYqx79H8ElBelvGscKvVv57A/nzg/ZdF+AMPkeYAHiq1eEfYfdHd9cuqUI0iuasR1vsEvSUjDfQ== X-Received: by 2002:a5e:820a:: with SMTP id l10mr13256571iom.283.1560983598744; Wed, 19 Jun 2019 15:33:18 -0700 (PDT) Received: from localhost.localdomain (50-126-100-225.drr01.csby.or.frontiernet.net. [50.126.100.225]) by smtp.gmail.com with ESMTPSA id p10sm12684507iob.54.2019.06.19.15.33.17 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 19 Jun 2019 15:33:18 -0700 (PDT) Subject: [PATCH v1 3/6] mm: Use zone and order instead of free area in free_list manipulators From: Alexander Duyck To: nitesh@redhat.com, kvm@vger.kernel.org, david@redhat.com, mst@redhat.com, dave.hansen@intel.com, linux-kernel@vger.kernel.org, linux-mm@kvack.org, akpm@linux-foundation.org Cc: yang.zhang.wz@gmail.com, pagupta@redhat.com, riel@surriel.com, konrad.wilk@oracle.com, lcapitulino@redhat.com, wei.w.wang@intel.com, aarcange@redhat.com, pbonzini@redhat.com, dan.j.williams@intel.com, alexander.h.duyck@linux.intel.com Date: Wed, 19 Jun 2019 15:33:16 -0700 Message-ID: <20190619223316.1231.50329.stgit@localhost.localdomain> In-Reply-To: <20190619222922.1231.27432.stgit@localhost.localdomain> References: <20190619222922.1231.27432.stgit@localhost.localdomain> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Alexander Duyck In order to enable the use of the zone from the list manipulator functions I will need access to the zone pointer. As it turns out most of the accessors were always just being directly passed &zone->free_area[order] anyway so it would make sense to just fold that into the function itself and pass the zone and order as arguments instead of the free area. In addition in order to be able to reference the zone we need to move the declaration of the functions down so that we have the zone defined before we define the list manipulation functions. Signed-off-by: Alexander Duyck --- include/linux/mmzone.h | 72 +++++++++++++++++++++++++++--------------------- mm/page_alloc.c | 30 +++++++------------- 2 files changed, 51 insertions(+), 51 deletions(-) diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 6f8fd5c1a286..c3597920a155 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -118,29 +118,6 @@ struct free_area { unsigned long nr_free; }; -/* Used for pages not on another list */ -static inline void add_to_free_area(struct page *page, struct free_area *area, - int migratetype) -{ - list_add(&page->lru, &area->free_list[migratetype]); - area->nr_free++; -} - -/* Used for pages not on another list */ -static inline void add_to_free_area_tail(struct page *page, struct free_area *area, - int migratetype) -{ - list_add_tail(&page->lru, &area->free_list[migratetype]); - area->nr_free++; -} - -/* Used for pages which are on another list */ -static inline void move_to_free_area(struct page *page, struct free_area *area, - int migratetype) -{ - list_move(&page->lru, &area->free_list[migratetype]); -} - static inline struct page *get_page_from_free_area(struct free_area *area, int migratetype) { @@ -148,15 +125,6 @@ static inline struct page *get_page_from_free_area(struct free_area *area, struct page, lru); } -static inline void del_page_from_free_area(struct page *page, - struct free_area *area) -{ - list_del(&page->lru); - __ClearPageBuddy(page); - set_page_private(page, 0); - area->nr_free--; -} - static inline bool free_area_empty(struct free_area *area, int migratetype) { return list_empty(&area->free_list[migratetype]); @@ -805,6 +773,46 @@ static inline bool pgdat_is_empty(pg_data_t *pgdat) return !pgdat->node_start_pfn && !pgdat->node_spanned_pages; } +/* Used for pages not on another list */ +static inline void add_to_free_area(struct page *page, struct zone *zone, + unsigned int order, int migratetype) +{ + struct free_area *area = &zone->free_area[order]; + + list_add(&page->lru, &area->free_list[migratetype]); + area->nr_free++; +} + +/* Used for pages not on another list */ +static inline void add_to_free_area_tail(struct page *page, struct zone *zone, + unsigned int order, int migratetype) +{ + struct free_area *area = &zone->free_area[order]; + + list_add_tail(&page->lru, &area->free_list[migratetype]); + area->nr_free++; +} + +/* Used for pages which are on another list */ +static inline void move_to_free_area(struct page *page, struct zone *zone, + unsigned int order, int migratetype) +{ + struct free_area *area = &zone->free_area[order]; + + list_move(&page->lru, &area->free_list[migratetype]); +} + +static inline void del_page_from_free_area(struct page *page, struct zone *zone, + unsigned int order) +{ + struct free_area *area = &zone->free_area[order]; + + list_del(&page->lru); + __ClearPageBuddy(page); + set_page_private(page, 0); + area->nr_free--; +} + #include void build_all_zonelists(pg_data_t *pgdat); diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 3e21e01f6165..aad2b2529ab7 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -873,7 +873,6 @@ static inline void __free_one_page(struct page *page, struct capture_control *capc = task_capc(zone); unsigned long uninitialized_var(buddy_pfn); unsigned long combined_pfn; - struct free_area *area; unsigned int max_order; struct page *buddy; @@ -910,7 +909,7 @@ static inline void __free_one_page(struct page *page, if (page_is_guard(buddy)) clear_page_guard(zone, buddy, order, migratetype); else - del_page_from_free_area(buddy, &zone->free_area[order]); + del_page_from_free_area(buddy, zone, order); combined_pfn = buddy_pfn & pfn; page = page + (combined_pfn - pfn); pfn = combined_pfn; @@ -944,12 +943,11 @@ static inline void __free_one_page(struct page *page, done_merging: set_page_order(page, order); - area = &zone->free_area[order]; if (buddy_merge_likely(pfn, buddy_pfn, page, order) || is_shuffle_tail_page(order)) - add_to_free_area_tail(page, area, migratetype); + add_to_free_area_tail(page, zone, order, migratetype); else - add_to_free_area(page, area, migratetype); + add_to_free_area(page, zone, order, migratetype); } /* @@ -1941,13 +1939,11 @@ void __init init_cma_reserved_pageblock(struct page *page) * -- nyc */ static inline void expand(struct zone *zone, struct page *page, - int low, int high, struct free_area *area, - int migratetype) + int low, int high, int migratetype) { unsigned long size = 1 << high; while (high > low) { - area--; high--; size >>= 1; VM_BUG_ON_PAGE(bad_range(zone, &page[size]), &page[size]); @@ -1961,7 +1957,7 @@ static inline void expand(struct zone *zone, struct page *page, if (set_page_guard(zone, &page[size], high, migratetype)) continue; - add_to_free_area(&page[size], area, migratetype); + add_to_free_area(&page[size], zone, high, migratetype); set_page_order(&page[size], high); } } @@ -2122,8 +2118,8 @@ struct page *__rmqueue_smallest(struct zone *zone, unsigned int order, page = get_page_from_free_area(area, migratetype); if (!page) continue; - del_page_from_free_area(page, area); - expand(zone, page, order, current_order, area, migratetype); + del_page_from_free_area(page, zone, current_order); + expand(zone, page, order, current_order, migratetype); set_pcppage_migratetype(page, migratetype); return page; } @@ -2131,7 +2127,6 @@ struct page *__rmqueue_smallest(struct zone *zone, unsigned int order, return NULL; } - /* * This array describes the order lists are fallen back to when * the free lists for the desirable migrate type are depleted @@ -2208,7 +2203,7 @@ static int move_freepages(struct zone *zone, } order = page_order(page); - move_to_free_area(page, &zone->free_area[order], migratetype); + move_to_free_area(page, zone, order, migratetype); page += 1 << order; pages_moved += 1 << order; } @@ -2324,7 +2319,6 @@ static void steal_suitable_fallback(struct zone *zone, struct page *page, unsigned int alloc_flags, int start_type, bool whole_block) { unsigned int current_order = page_order(page); - struct free_area *area; int free_pages, movable_pages, alike_pages; int old_block_type; @@ -2395,8 +2389,7 @@ static void steal_suitable_fallback(struct zone *zone, struct page *page, return; single_page: - area = &zone->free_area[current_order]; - move_to_free_area(page, area, start_type); + move_to_free_area(page, zone, current_order, start_type); } /* @@ -3067,7 +3060,6 @@ void split_page(struct page *page, unsigned int order) int __isolate_free_page(struct page *page, unsigned int order) { - struct free_area *area = &page_zone(page)->free_area[order]; unsigned long watermark; struct zone *zone; int mt; @@ -3093,7 +3085,7 @@ int __isolate_free_page(struct page *page, unsigned int order) /* Remove page from free list */ - del_page_from_free_area(page, area); + del_page_from_free_area(page, zone, order); /* * Set the pageblock if the isolated page is at least half of a @@ -8513,7 +8505,7 @@ void zone_pcp_reset(struct zone *zone) pr_info("remove from free list %lx %d %lx\n", pfn, 1 << order, end_pfn); #endif - del_page_from_free_area(page, &zone->free_area[order]); + del_page_from_free_area(page, zone, order); for (i = 0; i < (1 << order); i++) SetPageReserved((page+i)); pfn += (1 << order); From patchwork Wed Jun 19 22:33:23 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Duyck X-Patchwork-Id: 11005525 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 0643D1580 for ; Wed, 19 Jun 2019 22:33:30 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E8ABA28807 for ; Wed, 19 Jun 2019 22:33:29 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id DC58D28841; Wed, 19 Jun 2019 22:33:29 +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=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=unavailable 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 1A5C52883C for ; Wed, 19 Jun 2019 22:33:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730926AbfFSWd2 (ORCPT ); Wed, 19 Jun 2019 18:33:28 -0400 Received: from mail-io1-f67.google.com ([209.85.166.67]:38348 "EHLO mail-io1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730914AbfFSWd1 (ORCPT ); Wed, 19 Jun 2019 18:33:27 -0400 Received: by mail-io1-f67.google.com with SMTP id j6so436809ioa.5; Wed, 19 Jun 2019 15:33:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=subject:from:to:cc:date:message-id:in-reply-to:references :user-agent:mime-version:content-transfer-encoding; bh=uFIpek7shBaVr9DU13GRQZ4ibKs0x6v0iQmP4OpKI7k=; b=k/OoraMNYNLWswsjRZR3jEbeHgciCrA3Pvkj8V+NcMuwZd4nDStE1mCeb2clq7uoPE Bf0GYaBQ58HCl4cWZHr/PK4K4jEqlPVoK9CIq9gBKyQP+SAMwHApaOQ+/pM/boz+OI3N Ddc47rKbDu9wx2/eEEMCGKLqNnTrNgKTd6Eb2XLmtry661w/558JU3OoCoNGpsOBoRAn mhk+F4qr5+ZnCArtmzi2LJGPyjE7a2T+Bn/9P+Ib5zy4BsTFTShpemJziW9RGWAgDKkx 0qaUB6uoFgFyhUPIj/dCvXQQW9NCpd74Z4QihncLfIL8C1BwyheFscAO19MnmxiE0jYW AH+g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:from:to:cc:date:message-id:in-reply-to :references:user-agent:mime-version:content-transfer-encoding; bh=uFIpek7shBaVr9DU13GRQZ4ibKs0x6v0iQmP4OpKI7k=; b=Alae/MRlkPe2T2dQ19GnGDhfV5rAVql1UkKno/m/uGlo02w8juQEk/mogfXYItpDmk lF9U1TxQJ/Ghysudw/+lP5THPaPJ/l4YIOpsKEJf00pChAFyGQ1ZW8OhAK+QTfVpgE89 aBIr6tYqmTOnH7ILh9x/PdPVnmGakelmM9VVFXg9y9A80X9VUC2Bcf5pO6TmTsrF9nuO 6si8KiZMWMxaaBgVhcA6LPaDPvHaVqraAC5kHSo+nacvupKZco2QxkZdDp4oz5yYsJCh reY+DayjxD/sQciYPRCcO0hDSCOMMNEQ0B9xrbDHzXM0FB+r+lijkmzsPoFaSQHLlNVg b90w== X-Gm-Message-State: APjAAAUdnJKkEVnjkU0Qw2dcfZV3bIHszDmGWvHq23xLkV42D9CkrvYB leXkRFyYMzJ+DVOruKdOUiU= X-Google-Smtp-Source: APXvYqyGIUEECip5yOIkf36i1rUmylXKTO5CxpW8E+NA2U4z3c9cYnuIYIokSVtGEOBlV0rtIuMF/Q== X-Received: by 2002:a02:ccd2:: with SMTP id k18mr1709593jaq.3.1560983605934; Wed, 19 Jun 2019 15:33:25 -0700 (PDT) Received: from localhost.localdomain (50-126-100-225.drr01.csby.or.frontiernet.net. [50.126.100.225]) by smtp.gmail.com with ESMTPSA id a15sm13136500ioc.27.2019.06.19.15.33.24 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 19 Jun 2019 15:33:25 -0700 (PDT) Subject: [PATCH v1 4/6] mm: Introduce "aerated" pages From: Alexander Duyck To: nitesh@redhat.com, kvm@vger.kernel.org, david@redhat.com, mst@redhat.com, dave.hansen@intel.com, linux-kernel@vger.kernel.org, linux-mm@kvack.org, akpm@linux-foundation.org Cc: yang.zhang.wz@gmail.com, pagupta@redhat.com, riel@surriel.com, konrad.wilk@oracle.com, lcapitulino@redhat.com, wei.w.wang@intel.com, aarcange@redhat.com, pbonzini@redhat.com, dan.j.williams@intel.com, alexander.h.duyck@linux.intel.com Date: Wed, 19 Jun 2019 15:33:23 -0700 Message-ID: <20190619223323.1231.86906.stgit@localhost.localdomain> In-Reply-To: <20190619222922.1231.27432.stgit@localhost.localdomain> References: <20190619222922.1231.27432.stgit@localhost.localdomain> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Alexander Duyck In order to pave the way for free page hinting in virtualized environments we will need a way to get pages out of the free lists and identify those pages after they have been returned. To accomplish this patch adds the concept of an "aerated" flag, which is essentially meant to just be the Offline page type used in conjustion with the Buddy page type bit. For now we can just add the basic logic to set the flag and track the number of aerated pages per free area. Signed-off-by: Alexander Duyck --- include/linux/memory_aeration.h | 61 +++++++++++++++++++++++++ include/linux/mmzone.h | 13 ++++- mm/Kconfig | 5 ++ mm/page_alloc.c | 97 +++++++++++++++++++++++++++++++++++++-- 4 files changed, 168 insertions(+), 8 deletions(-) create mode 100644 include/linux/memory_aeration.h diff --git a/include/linux/memory_aeration.h b/include/linux/memory_aeration.h new file mode 100644 index 000000000000..44cfbc259778 --- /dev/null +++ b/include/linux/memory_aeration.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LINUX_MEMORY_AERATION_H +#define _LINUX_MEMORY_AERATION_H + +#include +#include + +struct page *get_aeration_page(struct zone *zone, unsigned int order, + int migratetype); +void put_aeration_page(struct zone *zone, struct page *page); + +static inline struct list_head *aerator_get_tail(struct zone *zone, + unsigned int order, + int migratetype) +{ + return &zone->free_area[order].free_list[migratetype]; +} + +static inline void set_page_aerated(struct page *page, + struct zone *zone, + unsigned int order, + int migratetype) +{ +#ifdef CONFIG_AERATION + /* update areated page accounting */ + zone->free_area[order].nr_free_aerated++; + + /* record migratetype and flag page as aerated */ + set_pcppage_migratetype(page, migratetype); + __SetPageAerated(page); +#endif +} + +static inline void clear_page_aerated(struct page *page, + struct zone *zone, + struct free_area *area) +{ +#ifdef CONFIG_AERATION + if (likely(!PageAerated(page))) + return; + + __ClearPageAerated(page); + area->nr_free_aerated--; +#endif +} + +/** + * aerator_notify_free - Free page notification that will start page processing + * @zone: Pointer to current zone of last page processed + * @order: Order of last page added to zone + * + * This function is meant to act as a screener for __aerator_notify which + * will determine if a give zone has crossed over the high-water mark that + * will justify us beginning page treatment. If we have crossed that + * threshold then it will start the process of pulling some pages and + * placing them in the batch list for treatment. + */ +static inline void aerator_notify_free(struct zone *zone, int order) +{ +} +#endif /*_LINUX_MEMORY_AERATION_H */ diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index c3597920a155..7d89722ae9eb 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -116,6 +116,7 @@ static inline void set_pcppage_migratetype(struct page *page, int migratetype) struct free_area { struct list_head free_list[MIGRATE_TYPES]; unsigned long nr_free; + unsigned long nr_free_aerated; }; static inline struct page *get_page_from_free_area(struct free_area *area, @@ -773,6 +774,8 @@ static inline bool pgdat_is_empty(pg_data_t *pgdat) return !pgdat->node_start_pfn && !pgdat->node_spanned_pages; } +#include + /* Used for pages not on another list */ static inline void add_to_free_area(struct page *page, struct zone *zone, unsigned int order, int migratetype) @@ -787,10 +790,10 @@ static inline void add_to_free_area(struct page *page, struct zone *zone, static inline void add_to_free_area_tail(struct page *page, struct zone *zone, unsigned int order, int migratetype) { - struct free_area *area = &zone->free_area[order]; + struct list_head *tail = aerator_get_tail(zone, order, migratetype); - list_add_tail(&page->lru, &area->free_list[migratetype]); - area->nr_free++; + list_add_tail(&page->lru, tail); + zone->free_area[order].nr_free++; } /* Used for pages which are on another list */ @@ -799,6 +802,8 @@ static inline void move_to_free_area(struct page *page, struct zone *zone, { struct free_area *area = &zone->free_area[order]; + clear_page_aerated(page, zone, area); + list_move(&page->lru, &area->free_list[migratetype]); } @@ -807,6 +812,8 @@ static inline void del_page_from_free_area(struct page *page, struct zone *zone, { struct free_area *area = &zone->free_area[order]; + clear_page_aerated(page, zone, area); + list_del(&page->lru); __ClearPageBuddy(page); set_page_private(page, 0); diff --git a/mm/Kconfig b/mm/Kconfig index 7c41d2300e07..209dc4bea481 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -236,6 +236,11 @@ config COMPACTION linux-mm@kvack.org. # +# support for memory aeration +config AERATION + bool + +# # support for page migration # config MIGRATION diff --git a/mm/page_alloc.c b/mm/page_alloc.c index aad2b2529ab7..eb7ba8385374 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -68,6 +68,7 @@ #include #include #include +#include #include #include @@ -868,10 +869,11 @@ static inline struct capture_control *task_capc(struct zone *zone) static inline void __free_one_page(struct page *page, unsigned long pfn, struct zone *zone, unsigned int order, - int migratetype) + int migratetype, bool aerated) { struct capture_control *capc = task_capc(zone); unsigned long uninitialized_var(buddy_pfn); + bool fully_aerated = aerated; unsigned long combined_pfn; unsigned int max_order; struct page *buddy; @@ -902,6 +904,11 @@ static inline void __free_one_page(struct page *page, goto done_merging; if (!page_is_buddy(page, buddy, order)) goto done_merging; + + /* assume buddy is not aerated */ + if (aerated) + fully_aerated = false; + /* * Our buddy is free or it is CONFIG_DEBUG_PAGEALLOC guard page, * merge with it and move up one order. @@ -943,11 +950,17 @@ static inline void __free_one_page(struct page *page, done_merging: set_page_order(page, order); - if (buddy_merge_likely(pfn, buddy_pfn, page, order) || + if (aerated || + buddy_merge_likely(pfn, buddy_pfn, page, order) || is_shuffle_tail_page(order)) add_to_free_area_tail(page, zone, order, migratetype); else add_to_free_area(page, zone, order, migratetype); + + if (fully_aerated) + set_page_aerated(page, zone, order, migratetype); + else + aerator_notify_free(zone, order); } /* @@ -1247,7 +1260,7 @@ static void free_pcppages_bulk(struct zone *zone, int count, if (unlikely(isolated_pageblocks)) mt = get_pageblock_migratetype(page); - __free_one_page(page, page_to_pfn(page), zone, 0, mt); + __free_one_page(page, page_to_pfn(page), zone, 0, mt, false); trace_mm_page_pcpu_drain(page, 0, mt); } spin_unlock(&zone->lock); @@ -1263,7 +1276,7 @@ static void free_one_page(struct zone *zone, is_migrate_isolate(migratetype))) { migratetype = get_pfnblock_migratetype(page, pfn); } - __free_one_page(page, pfn, zone, order, migratetype); + __free_one_page(page, pfn, zone, order, migratetype, false); spin_unlock(&zone->lock); } @@ -2127,6 +2140,77 @@ struct page *__rmqueue_smallest(struct zone *zone, unsigned int order, return NULL; } +#ifdef CONFIG_AERATION +/** + * get_aeration_page - Provide a "raw" page for aeration by the aerator + * @zone: Zone to draw pages from + * @order: Order to draw pages from + * @migratetype: Migratetype to draw pages from + * + * This function will obtain a page from above the boundary. As a result + * we can guarantee the page has not been aerated. + * + * The page will have the migrate type and order stored in the page + * metadata. + * + * Return: page pointer if raw page found, otherwise NULL + */ +struct page *get_aeration_page(struct zone *zone, unsigned int order, + int migratetype) +{ + struct free_area *area = &(zone->free_area[order]); + struct list_head *list = &area->free_list[migratetype]; + struct page *page; + + /* Find a page of the appropriate size in the preferred list */ + page = list_last_entry(aerator_get_tail(zone, order, migratetype), + struct page, lru); + list_for_each_entry_from_reverse(page, list, lru) { + if (PageAerated(page)) { + page = list_first_entry(list, struct page, lru); + if (PageAerated(page)) + break; + } + + del_page_from_free_area(page, zone, order); + + /* record migratetype and order within page */ + set_pcppage_migratetype(page, migratetype); + set_page_private(page, order); + __mod_zone_freepage_state(zone, -(1 << order), migratetype); + + return page; + } + + return NULL; +} + +/** + * put_aeration_page - Return a now-aerated "raw" page back where we got it + * @zone: Zone to return pages to + * @page: Previously "raw" page that can now be returned after aeration + * + * This function will pull the migratetype and order information out + * of the page and attempt to return it where it found it. + */ +void put_aeration_page(struct zone *zone, struct page *page) +{ + unsigned int order, mt; + unsigned long pfn; + + mt = get_pcppage_migratetype(page); + pfn = page_to_pfn(page); + + if (unlikely(has_isolate_pageblock(zone) || is_migrate_isolate(mt))) + mt = get_pfnblock_migratetype(page, pfn); + + order = page_private(page); + set_page_private(page, 0); + + __free_one_page(page, pfn, zone, order, mt, true); +} +#endif /* CONFIG_AERATION */ + /* * This array describes the order lists are fallen back to when * the free lists for the desirable migrate type are depleted @@ -5929,9 +6013,12 @@ void __ref memmap_init_zone_device(struct zone *zone, static void __meminit zone_init_free_lists(struct zone *zone) { unsigned int order, t; - for_each_migratetype_order(order, t) { + for_each_migratetype_order(order, t) INIT_LIST_HEAD(&zone->free_area[order].free_list[t]); + + for (order = MAX_ORDER; order--; ) { zone->free_area[order].nr_free = 0; + zone->free_area[order].nr_free_aerated = 0; } } From patchwork Wed Jun 19 22:33:31 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Duyck X-Patchwork-Id: 11005529 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 6AB3B13AF for ; Wed, 19 Jun 2019 22:33:40 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 589CB28807 for ; Wed, 19 Jun 2019 22:33:40 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 4BCA728841; Wed, 19 Jun 2019 22:33:40 +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=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=unavailable 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 4CA6728807 for ; Wed, 19 Jun 2019 22:33:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730938AbfFSWdf (ORCPT ); Wed, 19 Jun 2019 18:33:35 -0400 Received: from mail-io1-f68.google.com ([209.85.166.68]:34378 "EHLO mail-io1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730504AbfFSWde (ORCPT ); Wed, 19 Jun 2019 18:33:34 -0400 Received: by mail-io1-f68.google.com with SMTP id k8so187437iot.1; Wed, 19 Jun 2019 15:33:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=subject:from:to:cc:date:message-id:in-reply-to:references :user-agent:mime-version:content-transfer-encoding; bh=OnfCOLVUM2RdwkrCGbwB+NaigOrBL5HPfiKOHiPEd+Q=; b=VOj/Ebn5EmXVZGb7w3umnmzaylkU/2Mwo9MY4M7o56x1OkSv27WjZ+qp8OSOch2Kwg uOHFWPdmdCJbtRsBpzIaWhLNmCjs0BmAfVDNwQ1+LnfFp0wHRWRs0tfTU4G5ZGolUo5q kbiCoiPafMyGLqeXWRH5nbFk8fbtYK9rzwhm+GZWXoVUD2T7SuaM9uzpierFXpCjBakk mEk1JuHBzZRaYDamWy4DRFni1oycKwq4u7sxLduBDo/Za9qyUACaAv5bV7Kf9ErOZIsa zn9UNKNGz9LWE9g8NRzRjUa3MTd3hxH5zjZy2x0sqUeiznvSAAb1YMuzrHGDaCkUgWoi naCg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:from:to:cc:date:message-id:in-reply-to :references:user-agent:mime-version:content-transfer-encoding; bh=OnfCOLVUM2RdwkrCGbwB+NaigOrBL5HPfiKOHiPEd+Q=; b=cuZ4DnE+G+LDwmhbsYwGF/Pw3mw59kt+VYAjddgxelkzUUV7snGRqVaPXjI/yscrpb vCiaFtgJN13mChHwnxlJDI9UEkZX/ZLjg7kbS+cNeLCRHO+Q+hHEloPm8bXudM7tgbJ+ qoigoOIJFqGolNng3SjZ7P7II9GO07rTvyv0QcD78PZiE67ti/FVu3hp8ETtre4bFWRR VPk1535juSb46T1rx1en68hSDkCjzRr8QpE7VyelAtORBRFEZ6XPK08dt0eITi6iVTbz 4bjBlN4yrfaJTgnKWgoBwaYzDpoEacrHz0a6ZSJSC/WYmgJ11dGL4GA6vVYQRlRYbfBc enzQ== X-Gm-Message-State: APjAAAUk5MLHM4hD3sitJf1FgaNAcepCXGfiArAE2dSMnksDn1IzHCoN xpIR6QOgMGjGwmWgo5fEWnQ= X-Google-Smtp-Source: APXvYqzFzWntvUwa+A8P/XLBxNEA6gs2CvtTGf9vkOmTbbiqnl1BvbkUuEpkbUt2yQIUlkfCUmR2Yw== X-Received: by 2002:a6b:6409:: with SMTP id t9mr14858793iog.270.1560983613186; Wed, 19 Jun 2019 15:33:33 -0700 (PDT) Received: from localhost.localdomain (50-126-100-225.drr01.csby.or.frontiernet.net. [50.126.100.225]) by smtp.gmail.com with ESMTPSA id v25sm15370617ioh.25.2019.06.19.15.33.31 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 19 Jun 2019 15:33:32 -0700 (PDT) Subject: [PATCH v1 5/6] mm: Add logic for separating "aerated" pages from "raw" pages From: Alexander Duyck To: nitesh@redhat.com, kvm@vger.kernel.org, david@redhat.com, mst@redhat.com, dave.hansen@intel.com, linux-kernel@vger.kernel.org, linux-mm@kvack.org, akpm@linux-foundation.org Cc: yang.zhang.wz@gmail.com, pagupta@redhat.com, riel@surriel.com, konrad.wilk@oracle.com, lcapitulino@redhat.com, wei.w.wang@intel.com, aarcange@redhat.com, pbonzini@redhat.com, dan.j.williams@intel.com, alexander.h.duyck@linux.intel.com Date: Wed, 19 Jun 2019 15:33:31 -0700 Message-ID: <20190619223331.1231.39271.stgit@localhost.localdomain> In-Reply-To: <20190619222922.1231.27432.stgit@localhost.localdomain> References: <20190619222922.1231.27432.stgit@localhost.localdomain> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Alexander Duyck Add a set of pointers we shall call "boundary" which represents the upper boundary between the "raw" and "aerated" pages. The general idea is that in order for a page to cross from one side of the boundary to the other it will need to go through the aeration treatment. By doing this we should be able to make certain that we keep the aerated pages as one contiguous block on the end of each free list. This will allow us to efficiently walk the free lists whenever we need to go in and start processing hints to the hypervisor that the pages are no longer in use. And added advantage to this approach is that we should be reducing the overall memory footprint of the guest as it will be more likely to recycle warm pages versus the aerated pages that are likely to be cache cold. Since we will only be aerating one zone at a time we keep the boundary limited to being defined for just the zone we are currently placing aerated pages into. Doing this we can keep the number of additional poitners needed quite small. Signed-off-by: Alexander Duyck --- include/linux/memory_aeration.h | 57 ++++++++ include/linux/mmzone.h | 8 + include/linux/page-flags.h | 8 + mm/Makefile | 1 mm/aeration.c | 270 +++++++++++++++++++++++++++++++++++++++ mm/page_alloc.c | 4 - 6 files changed, 347 insertions(+), 1 deletion(-) create mode 100644 mm/aeration.c diff --git a/include/linux/memory_aeration.h b/include/linux/memory_aeration.h index 44cfbc259778..2f45196218b1 100644 --- a/include/linux/memory_aeration.h +++ b/include/linux/memory_aeration.h @@ -3,19 +3,50 @@ #define _LINUX_MEMORY_AERATION_H #include +#include #include +#include +#define AERATOR_MIN_ORDER pageblock_order +#define AERATOR_HWM 32 + +struct aerator_dev_info { + void (*react)(struct aerator_dev_info *a_dev_info); + struct list_head batch; + unsigned long capacity; + atomic_t refcnt; +}; + +extern struct static_key aerator_notify_enabled; + +void __aerator_notify(struct zone *zone); struct page *get_aeration_page(struct zone *zone, unsigned int order, int migratetype); void put_aeration_page(struct zone *zone, struct page *page); +void __aerator_del_from_boundary(struct page *page, struct zone *zone); +void aerator_add_to_boundary(struct page *page, struct zone *zone); + +struct list_head *__aerator_get_tail(unsigned int order, int migratetype); static inline struct list_head *aerator_get_tail(struct zone *zone, unsigned int order, int migratetype) { +#ifdef CONFIG_AERATION + if (order >= AERATOR_MIN_ORDER && + test_bit(ZONE_AERATION_ACTIVE, &zone->flags)) + return __aerator_get_tail(order, migratetype); +#endif return &zone->free_area[order].free_list[migratetype]; } +static inline void aerator_del_from_boundary(struct page *page, + struct zone *zone) +{ + if (PageAerated(page) && test_bit(ZONE_AERATION_ACTIVE, &zone->flags)) + __aerator_del_from_boundary(page, zone); +} + static inline void set_page_aerated(struct page *page, struct zone *zone, unsigned int order, @@ -28,6 +59,9 @@ static inline void set_page_aerated(struct page *page, /* record migratetype and flag page as aerated */ set_pcppage_migratetype(page, migratetype); __SetPageAerated(page); + + /* update boundary of new migratetype and record it */ + aerator_add_to_boundary(page, zone); #endif } @@ -39,11 +73,19 @@ static inline void clear_page_aerated(struct page *page, if (likely(!PageAerated(page))) return; + /* push boundary back if we removed the upper boundary */ + aerator_del_from_boundary(page, zone); + __ClearPageAerated(page); area->nr_free_aerated--; #endif } +static inline unsigned long aerator_raw_pages(struct free_area *area) +{ + return area->nr_free - area->nr_free_aerated; +} + /** * aerator_notify_free - Free page notification that will start page processing * @zone: Pointer to current zone of last page processed @@ -57,5 +99,20 @@ static inline void clear_page_aerated(struct page *page, */ static inline void aerator_notify_free(struct zone *zone, int order) { +#ifdef CONFIG_AERATION + if (!static_key_false(&aerator_notify_enabled)) + return; + if (order < AERATOR_MIN_ORDER) + return; + if (test_bit(ZONE_AERATION_REQUESTED, &zone->flags)) + return; + if (aerator_raw_pages(&zone->free_area[order]) < AERATOR_HWM) + return; + + __aerator_notify(zone); +#endif } + +void aerator_shutdown(void); +int aerator_startup(struct aerator_dev_info *sdev); #endif /*_LINUX_MEMORY_AERATION_H */ diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 7d89722ae9eb..52190a791e63 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -554,6 +554,14 @@ enum zone_flags { ZONE_BOOSTED_WATERMARK, /* zone recently boosted watermarks. * Cleared when kswapd is woken. */ + ZONE_AERATION_REQUESTED, /* zone enabled aeration and is + * requesting scrubbing the data out of + * higher order pages. + */ + ZONE_AERATION_ACTIVE, /* zone enabled aeration and is + * activly cleaning the data out of + * higher order pages. + */ }; static inline unsigned long zone_managed_pages(struct zone *zone) diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h index b848517da64c..f16e73318d49 100644 --- a/include/linux/page-flags.h +++ b/include/linux/page-flags.h @@ -745,6 +745,14 @@ static inline int page_has_type(struct page *page) PAGE_TYPE_OPS(Offline, offline) /* + * PageAerated() is an alias for Offline, however it is not meant to be an + * exclusive value. It should be combined with PageBuddy() when seen as it + * is meant to indicate that the page has been scrubbed while waiting in + * the buddy system. + */ +PAGE_TYPE_OPS(Aerated, offline) + +/* * If kmemcg is enabled, the buddy allocator will set PageKmemcg() on * pages allocated with __GFP_ACCOUNT. It gets cleared on page free. */ diff --git a/mm/Makefile b/mm/Makefile index ac5e5ba78874..26c2fcd2b89d 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -104,3 +104,4 @@ obj-$(CONFIG_HARDENED_USERCOPY) += usercopy.o obj-$(CONFIG_PERCPU_STATS) += percpu-stats.o obj-$(CONFIG_HMM) += hmm.o obj-$(CONFIG_MEMFD_CREATE) += memfd.o +obj-$(CONFIG_AERATION) += aeration.o diff --git a/mm/aeration.c b/mm/aeration.c new file mode 100644 index 000000000000..720dc51cb215 --- /dev/null +++ b/mm/aeration.c @@ -0,0 +1,270 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include +#include + +static struct aerator_dev_info *a_dev_info; +struct static_key aerator_notify_enabled; + +struct list_head *boundary[MAX_ORDER - AERATOR_MIN_ORDER][MIGRATE_TYPES]; + +static void aerator_reset_boundary(struct zone *zone, unsigned int order, + unsigned int migratetype) +{ + boundary[order - AERATOR_MIN_ORDER][migratetype] = + &zone->free_area[order].free_list[migratetype]; +} + +#define for_each_aerate_migratetype_order(_order, _type) \ + for (_order = MAX_ORDER; _order-- != AERATOR_MIN_ORDER;) \ + for (_type = MIGRATE_TYPES; _type--;) + +static void aerator_populate_boundaries(struct zone *zone) +{ + unsigned int order, mt; + + if (test_bit(ZONE_AERATION_ACTIVE, &zone->flags)) + return; + + for_each_aerate_migratetype_order(order, mt) + aerator_reset_boundary(zone, order, mt); + + set_bit(ZONE_AERATION_ACTIVE, &zone->flags); +} + +struct list_head *__aerator_get_tail(unsigned int order, int migratetype) +{ + return boundary[order - AERATOR_MIN_ORDER][migratetype]; +} + +void __aerator_del_from_boundary(struct page *page, struct zone *zone) +{ + unsigned int order = page_private(page) - AERATOR_MIN_ORDER; + int mt = get_pcppage_migratetype(page); + struct list_head **tail = &boundary[order][mt]; + + if (*tail == &page->lru) + *tail = page->lru.next; +} + +void aerator_add_to_boundary(struct page *page, struct zone *zone) +{ + unsigned int order = page_private(page) - AERATOR_MIN_ORDER; + int mt = get_pcppage_migratetype(page); + struct list_head **tail = &boundary[order][mt]; + + *tail = &page->lru; +} + +void aerator_shutdown(void) +{ + static_key_slow_dec(&aerator_notify_enabled); + + while (atomic_read(&a_dev_info->refcnt)) + msleep(20); + + WARN_ON(!list_empty(&a_dev_info->batch)); + + a_dev_info = NULL; +} +EXPORT_SYMBOL_GPL(aerator_shutdown); + +static void aerator_schedule_initial_aeration(void) +{ + struct zone *zone; + + for_each_populated_zone(zone) { + spin_lock(&zone->lock); + __aerator_notify(zone); + spin_unlock(&zone->lock); + } +} + +int aerator_startup(struct aerator_dev_info *sdev) +{ + if (a_dev_info) + return -EBUSY; + + INIT_LIST_HEAD(&sdev->batch); + atomic_set(&sdev->refcnt, 0); + + a_dev_info = sdev; + aerator_schedule_initial_aeration(); + + static_key_slow_inc(&aerator_notify_enabled); + + return 0; +} +EXPORT_SYMBOL_GPL(aerator_startup); + +static void aerator_fill(struct zone *zone) +{ + struct list_head *batch = &a_dev_info->batch; + int budget = a_dev_info->capacity; + unsigned int order, mt; + + for_each_aerate_migratetype_order(order, mt) { + struct page *page; + + /* + * Pull pages from free list until we have drained + * it or we have filled the batch reactor. + */ + while ((page = get_aeration_page(zone, order, mt))) { + list_add_tail(&page->lru, batch); + + if (!--budget) + return; + } + } + + /* + * If there are no longer enough free pages to fully populate + * the aerator, then we can just shut it down for this zone. + */ + clear_bit(ZONE_AERATION_REQUESTED, &zone->flags); + atomic_dec(&a_dev_info->refcnt); +} + +static void aerator_drain(struct zone *zone) +{ + struct list_head *list = &a_dev_info->batch; + struct page *page; + + /* + * Drain the now aerated pages back into their respective + * free lists/areas. + */ + while ((page = list_first_entry_or_null(list, struct page, lru))) { + list_del(&page->lru); + put_aeration_page(zone, page); + } +} + +static void aerator_scrub_zone(struct zone *zone) +{ + /* See if there are any pages to pull */ + if (!test_bit(ZONE_AERATION_REQUESTED, &zone->flags)) + return; + + spin_lock(&zone->lock); + + do { + aerator_fill(zone); + + if (list_empty(&a_dev_info->batch)) + break; + + spin_unlock(&zone->lock); + + /* + * Start aerating the pages in the batch, and then + * once that is completed we can drain the reactor + * and refill the reactor, restarting the cycle. + */ + a_dev_info->react(a_dev_info); + + spin_lock(&zone->lock); + + /* + * Guarantee boundaries are populated before we + * start placing aerated pages in the zone. + */ + aerator_populate_boundaries(zone); + + /* + * We should have a list of pages that have been + * processed. Return them to their original free lists. + */ + aerator_drain(zone); + + /* keep pulling pages till there are none to pull */ + } while (test_bit(ZONE_AERATION_REQUESTED, &zone->flags)); + + clear_bit(ZONE_AERATION_ACTIVE, &zone->flags); + + spin_unlock(&zone->lock); +} + +/** + * aerator_cycle - start aerating a batch of pages, drain, and refill + * + * The aerator cycle consists of 4 stages, fill, react, drain, and idle. + * We will cycle through the first 3 stages until we fail to obtain any + * pages, in that case we will switch to idle and the thread will go back + * to sleep awaiting the next request for aeration. + */ +static void aerator_cycle(struct work_struct *work) +{ + struct zone *zone = first_online_pgdat()->node_zones; + int refcnt; + + /* + * We want to hold one additional reference against the number of + * active hints as we may clear the hint that originally brought us + * here. We will clear it after we have either vaporized the content + * of the pages, or if we discover all pages were stolen out from + * under us. + */ + atomic_inc(&a_dev_info->refcnt); + + for (;;) { + aerator_scrub_zone(zone); + + /* + * Move to next zone, if at the end of the list + * test to see if we can just go into idle. + */ + zone = next_zone(zone); + if (zone) + continue; + zone = first_online_pgdat()->node_zones; + + /* + * If we never generated any pages and we are + * holding the only remaining reference to active + * hints then we can just let this go for now and + * go idle. + */ + refcnt = atomic_read(&a_dev_info->refcnt); + if (refcnt != 1) + continue; + if (atomic_try_cmpxchg(&a_dev_info->refcnt, &refcnt, 0)) + break; + } +} + +static DECLARE_DELAYED_WORK(aerator_work, &aerator_cycle); + +void __aerator_notify(struct zone *zone) +{ + /* + * We can use separate test and set operations here as there + * is nothing else that can set or clear this bit while we are + * holding the zone lock. The advantage to doing it this way is + * that we don't have to dirty the cacheline unless we are + * changing the value. + */ + set_bit(ZONE_AERATION_REQUESTED, &zone->flags); + + if (atomic_fetch_inc(&a_dev_info->refcnt)) + return; + + /* + * We should never be calling this function while there are already + * pages in the list being aerated. If we are called under such a + * circumstance report an error. + */ + WARN_ON(!list_empty(&a_dev_info->batch)); + + /* + * Delay the start of work to allow a sizable queue to build. For + * now we are limiting this to running no more than 10 times per + * second. + */ + schedule_delayed_work(&aerator_work, HZ / 10); +} diff --git a/mm/page_alloc.c b/mm/page_alloc.c index eb7ba8385374..45269c46c662 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -2168,8 +2168,10 @@ struct page *get_aeration_page(struct zone *zone, unsigned int order, list_for_each_entry_from_reverse(page, list, lru) { if (PageAerated(page)) { page = list_first_entry(list, struct page, lru); - if (PageAerated(page)) + if (PageAerated(page)) { + aerator_add_to_boundary(page, zone); break; + } } del_page_from_free_area(page, zone, order); From patchwork Wed Jun 19 22:33:38 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Duyck X-Patchwork-Id: 11005533 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 2E51576 for ; Wed, 19 Jun 2019 22:33:44 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 18E9228807 for ; Wed, 19 Jun 2019 22:33:44 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0C141288A0; Wed, 19 Jun 2019 22:33:44 +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=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,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 521C728807 for ; Wed, 19 Jun 2019 22:33:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730983AbfFSWdm (ORCPT ); Wed, 19 Jun 2019 18:33:42 -0400 Received: from mail-io1-f68.google.com ([209.85.166.68]:34402 "EHLO mail-io1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726251AbfFSWdl (ORCPT ); Wed, 19 Jun 2019 18:33:41 -0400 Received: by mail-io1-f68.google.com with SMTP id k8so187919iot.1; Wed, 19 Jun 2019 15:33:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=subject:from:to:cc:date:message-id:in-reply-to:references :user-agent:mime-version:content-transfer-encoding; bh=yajzYDUqG1ebFIffOMsyiuD/cX8ysLbDnEYZsXDC2Oc=; b=CkHOyBLfjkZscXBBRUrAj76gIABVTxN4enuI5JTaj3hHhk5IZG5cBtPg0NGdVPEhqt 9tEJS19ud/merARypx+IJ6GDIL8wlHrLjuHk0bBh5tS7uMslRu6/DjeidMoN6SIS4qvT 8vOe4IuKzS+F12UkSA+mZrgjMm+iBT0Mc1nM7N6grbBfKJ2EVStny52UrT4zQ3wltImt JBs5VO5VcFb9fFWkYP5Gymo/ups1lS+DxpjP6vS2aqE8i4tU4xOUBx4OTC9mD1THSTLK jTvRN03YylrVBI9Zya6V5VAcTsJ1N0FQ0Okzi6W0PUhEp3qZd8tJqDpksIRbvkzail2n 1xtg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:from:to:cc:date:message-id:in-reply-to :references:user-agent:mime-version:content-transfer-encoding; bh=yajzYDUqG1ebFIffOMsyiuD/cX8ysLbDnEYZsXDC2Oc=; b=RdrsDcoY6I9ZqibkDJVbVAL4CnwRjzA4Z6V14teqVRt8fiwvEW1K/CyaBX/1C6aofa 5Sba49nHIMABiPmLLpyFly7RWFP/LtR31IvwjQ2AMLaURltou8CO0j6mRW8qOBlhx+fO 027m/wFoHweUZY7AYkrcEs2Wdc7ZatttBLu7MSM1VsEEOXzc865FikevZRoNgOhFo/lL QVCqAlRR+LnAmZjA+zPu7+h8QpzVioAUMEFhcxLrAabG5BTz+wGZvyY10wiGbchPAeo8 cHIyCyLHU5c7rWwe82V/Itu4xYf+9m/G4E+hrPvaD9lkcDIfXnqBWxOiR7I1YObKv2Ew DtEQ== X-Gm-Message-State: APjAAAXlDctL5gVXaenzd3VvXD8ih8srDxZVu6fD4Df9sxZ/7Lw3rr4X hAqVfpuneNkRaI/Nq1EgqRw= X-Google-Smtp-Source: APXvYqxE9Ekot4Aq4UKpkJxZ/HLof0EmpylZv/EIMvZvgdgOA4zaMDe7/teWqAvV9VkFix7eWOC8SA== X-Received: by 2002:a6b:b985:: with SMTP id j127mr7261112iof.186.1560983620443; Wed, 19 Jun 2019 15:33:40 -0700 (PDT) Received: from localhost.localdomain (50-126-100-225.drr01.csby.or.frontiernet.net. [50.126.100.225]) by smtp.gmail.com with ESMTPSA id t133sm37266495iof.21.2019.06.19.15.33.38 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 19 Jun 2019 15:33:39 -0700 (PDT) Subject: [PATCH v1 6/6] virtio-balloon: Add support for aerating memory via hinting From: Alexander Duyck To: nitesh@redhat.com, kvm@vger.kernel.org, david@redhat.com, mst@redhat.com, dave.hansen@intel.com, linux-kernel@vger.kernel.org, linux-mm@kvack.org, akpm@linux-foundation.org Cc: yang.zhang.wz@gmail.com, pagupta@redhat.com, riel@surriel.com, konrad.wilk@oracle.com, lcapitulino@redhat.com, wei.w.wang@intel.com, aarcange@redhat.com, pbonzini@redhat.com, dan.j.williams@intel.com, alexander.h.duyck@linux.intel.com Date: Wed, 19 Jun 2019 15:33:38 -0700 Message-ID: <20190619223338.1231.52537.stgit@localhost.localdomain> In-Reply-To: <20190619222922.1231.27432.stgit@localhost.localdomain> References: <20190619222922.1231.27432.stgit@localhost.localdomain> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Alexander Duyck Add support for aerating memory using the hinting feature provided by virtio-balloon. Hinting differs from the regular balloon functionality in that is is much less durable than a standard memory balloon. Instead of creating a list of pages that cannot be accessed the pages are only inaccessible while they are being indicated to the virtio interface. Once the interface has acknowledged them they are placed back into their respective free lists and are once again accessible by the guest system. Signed-off-by: Alexander Duyck --- drivers/virtio/Kconfig | 1 drivers/virtio/virtio_balloon.c | 110 ++++++++++++++++++++++++++++++++++- include/uapi/linux/virtio_balloon.h | 1 3 files changed, 108 insertions(+), 4 deletions(-) diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig index 023fc3bc01c6..9cdaccf92c3a 100644 --- a/drivers/virtio/Kconfig +++ b/drivers/virtio/Kconfig @@ -47,6 +47,7 @@ config VIRTIO_BALLOON tristate "Virtio balloon driver" depends on VIRTIO select MEMORY_BALLOON + select AERATION ---help--- This driver supports increasing and decreasing the amount of memory within a KVM guest. diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index 44339fc87cc7..91f1e8c9017d 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c @@ -18,6 +18,7 @@ #include #include #include +#include /* * Balloon device works in 4K page units. So each page is pointed to by @@ -26,6 +27,7 @@ */ #define VIRTIO_BALLOON_PAGES_PER_PAGE (unsigned)(PAGE_SIZE >> VIRTIO_BALLOON_PFN_SHIFT) #define VIRTIO_BALLOON_ARRAY_PFNS_MAX 256 +#define VIRTIO_BALLOON_ARRAY_HINTS_MAX 32 #define VIRTBALLOON_OOM_NOTIFY_PRIORITY 80 #define VIRTIO_BALLOON_FREE_PAGE_ALLOC_FLAG (__GFP_NORETRY | __GFP_NOWARN | \ @@ -45,6 +47,7 @@ enum virtio_balloon_vq { VIRTIO_BALLOON_VQ_DEFLATE, VIRTIO_BALLOON_VQ_STATS, VIRTIO_BALLOON_VQ_FREE_PAGE, + VIRTIO_BALLOON_VQ_HINTING, VIRTIO_BALLOON_VQ_MAX }; @@ -54,7 +57,8 @@ enum virtio_balloon_config_read { struct virtio_balloon { struct virtio_device *vdev; - struct virtqueue *inflate_vq, *deflate_vq, *stats_vq, *free_page_vq; + struct virtqueue *inflate_vq, *deflate_vq, *stats_vq, *free_page_vq, + *hinting_vq; /* Balloon's own wq for cpu-intensive work items */ struct workqueue_struct *balloon_wq; @@ -103,9 +107,21 @@ struct virtio_balloon { /* Synchronize access/update to this struct virtio_balloon elements */ struct mutex balloon_lock; - /* The array of pfns we tell the Host about. */ - unsigned int num_pfns; - __virtio32 pfns[VIRTIO_BALLOON_ARRAY_PFNS_MAX]; + + union { + /* The array of pfns we tell the Host about. */ + struct { + unsigned int num_pfns; + __virtio32 pfns[VIRTIO_BALLOON_ARRAY_PFNS_MAX]; + }; + /* The array of physical addresses we are hinting on */ + struct { + unsigned int num_hints; + __virtio64 hints[VIRTIO_BALLOON_ARRAY_HINTS_MAX]; + }; + }; + + struct aerator_dev_info a_dev_info; /* Memory statistics */ struct virtio_balloon_stat stats[VIRTIO_BALLOON_S_NR]; @@ -151,6 +167,68 @@ static void tell_host(struct virtio_balloon *vb, struct virtqueue *vq) } +static u64 page_to_hints_pa_order(struct page *page) +{ + unsigned char order; + dma_addr_t pa; + + BUILD_BUG_ON((64 - VIRTIO_BALLOON_PFN_SHIFT) >= + (1 << VIRTIO_BALLOON_PFN_SHIFT)); + + /* + * Record physical page address combined with page order. + * Order will never exceed 64 - VIRTIO_BALLON_PFN_SHIFT + * since the size has to fit into a 64b value. So as long + * as VIRTIO_BALLOON_SHIFT is greater than this combining + * the two values should be safe. + */ + pa = page_to_phys(page); + order = page_private(page) + + PAGE_SHIFT - VIRTIO_BALLOON_PFN_SHIFT; + + return (u64)(pa | order); +} + +void virtballoon_aerator_react(struct aerator_dev_info *a_dev_info) +{ + struct virtio_balloon *vb = container_of(a_dev_info, + struct virtio_balloon, + a_dev_info); + struct virtqueue *vq = vb->hinting_vq; + struct scatterlist sg; + unsigned int unused; + struct page *page; + + mutex_lock(&vb->balloon_lock); + + vb->num_hints = 0; + + list_for_each_entry(page, &a_dev_info->batch, lru) { + vb->hints[vb->num_hints++] = + cpu_to_virtio64(vb->vdev, + page_to_hints_pa_order(page)); + } + + /* We shouldn't have been called if there is nothing to process */ + if (WARN_ON(vb->num_hints == 0)) + goto out; + + sg_init_one(&sg, vb->hints, + sizeof(vb->hints[0]) * vb->num_hints); + + /* + * We should always be able to add one buffer to an + * empty queue. + */ + virtqueue_add_outbuf(vq, &sg, 1, vb, GFP_KERNEL); + virtqueue_kick(vq); + + /* When host has read buffer, this completes via balloon_ack */ + wait_event(vb->acked, virtqueue_get_buf(vq, &unused)); +out: + mutex_unlock(&vb->balloon_lock); +} + static void set_page_pfns(struct virtio_balloon *vb, __virtio32 pfns[], struct page *page) { @@ -475,6 +553,7 @@ static int init_vqs(struct virtio_balloon *vb) names[VIRTIO_BALLOON_VQ_DEFLATE] = "deflate"; names[VIRTIO_BALLOON_VQ_STATS] = NULL; names[VIRTIO_BALLOON_VQ_FREE_PAGE] = NULL; + names[VIRTIO_BALLOON_VQ_HINTING] = NULL; if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_STATS_VQ)) { names[VIRTIO_BALLOON_VQ_STATS] = "stats"; @@ -486,11 +565,19 @@ static int init_vqs(struct virtio_balloon *vb) callbacks[VIRTIO_BALLOON_VQ_FREE_PAGE] = NULL; } + if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_HINTING)) { + names[VIRTIO_BALLOON_VQ_HINTING] = "hinting_vq"; + callbacks[VIRTIO_BALLOON_VQ_HINTING] = balloon_ack; + } + err = vb->vdev->config->find_vqs(vb->vdev, VIRTIO_BALLOON_VQ_MAX, vqs, callbacks, names, NULL, NULL); if (err) return err; + if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_HINTING)) + vb->hinting_vq = vqs[VIRTIO_BALLOON_VQ_HINTING]; + vb->inflate_vq = vqs[VIRTIO_BALLOON_VQ_INFLATE]; vb->deflate_vq = vqs[VIRTIO_BALLOON_VQ_DEFLATE]; if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_STATS_VQ)) { @@ -929,12 +1016,24 @@ static int virtballoon_probe(struct virtio_device *vdev) if (err) goto out_del_balloon_wq; } + + vb->a_dev_info.react = virtballoon_aerator_react; + vb->a_dev_info.capacity = VIRTIO_BALLOON_ARRAY_HINTS_MAX; + if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_HINTING)) { + err = aerator_startup(&vb->a_dev_info); + if (err) + goto out_unregister_shrinker; + } + virtio_device_ready(vdev); if (towards_target(vb)) virtballoon_changed(vdev); return 0; +out_unregister_shrinker: + if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM)) + virtio_balloon_unregister_shrinker(vb); out_del_balloon_wq: if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT)) destroy_workqueue(vb->balloon_wq); @@ -963,6 +1062,8 @@ static void virtballoon_remove(struct virtio_device *vdev) { struct virtio_balloon *vb = vdev->priv; + if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_HINTING)) + aerator_shutdown(); if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM)) virtio_balloon_unregister_shrinker(vb); spin_lock_irq(&vb->stop_update_lock); @@ -1032,6 +1133,7 @@ static int virtballoon_validate(struct virtio_device *vdev) VIRTIO_BALLOON_F_DEFLATE_ON_OOM, VIRTIO_BALLOON_F_FREE_PAGE_HINT, VIRTIO_BALLOON_F_PAGE_POISON, + VIRTIO_BALLOON_F_HINTING, }; static struct virtio_driver virtio_balloon_driver = { diff --git a/include/uapi/linux/virtio_balloon.h b/include/uapi/linux/virtio_balloon.h index a1966cd7b677..2b0f62814e22 100644 --- a/include/uapi/linux/virtio_balloon.h +++ b/include/uapi/linux/virtio_balloon.h @@ -36,6 +36,7 @@ #define VIRTIO_BALLOON_F_DEFLATE_ON_OOM 2 /* Deflate balloon on OOM */ #define VIRTIO_BALLOON_F_FREE_PAGE_HINT 3 /* VQ to report free pages */ #define VIRTIO_BALLOON_F_PAGE_POISON 4 /* Guest is using page poisoning */ +#define VIRTIO_BALLOON_F_HINTING 5 /* Page hinting virtqueue */ /* Size of a PFN in the balloon interface. */ #define VIRTIO_BALLOON_PFN_SHIFT 12