From patchwork Wed Sep 18 17:52:33 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Duyck X-Patchwork-Id: 11151065 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 4E826912 for ; Wed, 18 Sep 2019 17:52:47 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 2BEC121924 for ; Wed, 18 Sep 2019 17:52:47 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="TNoC0PgG"; dkim=fail reason="signature verification failed" (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="kY3Nlxw4" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 2BEC121924 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:To:From:Subject:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=HKlMaxAn+XkLFdMScNDmX6Dz/DpI1VnBORXX9XOr6Do=; b=TNoC0PgG+n+/Tu qWHVpGEwYGtQ3rf6d+Wrtu2szFlZMAFxTrG1Do2kczWqF0WbqSJ0NJlFg0kncG/kaQCp2YGvF9DpX poRfeIly6Fw4Q7QHlGx9VwJHGnJ4n963dKmT4EZlFsmkDlFWcTjZS5MWv/y+cOz2yGGTSZhHjBwtI ELn0ivez3Xc9LOLdi+iF4CrcXqezaauClpmTNLd4jhCMRVC/MM8LXF72tB1IcIhEpF97T1pzuc9yT xQbZw4wHfFf9nXgFjHXJBiu1WmBx2PxWPlAoDzdWC0eNLT6D98gCFOgWRcGeCcqmyWBSTD0Yg40gJ 89/vPEG0xAEzLUHbmj/g==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.2 #3 (Red Hat Linux)) id 1iAe8C-0006P2-K0; Wed, 18 Sep 2019 17:52:44 +0000 Received: from mail-ot1-x344.google.com ([2607:f8b0:4864:20::344]) by bombadil.infradead.org with esmtps (Exim 4.92.2 #3 (Red Hat Linux)) id 1iAe85-0006Ih-GP for linux-arm-kernel@lists.infradead.org; Wed, 18 Sep 2019 17:52:39 +0000 Received: by mail-ot1-x344.google.com with SMTP id e11so641098otl.5 for ; Wed, 18 Sep 2019 10:52:37 -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=JWWH0nLE5gW80rwb17oSZfM6VHlugSoNSjEeC143ARI=; b=kY3Nlxw4jpobVoe1JNyEjEGVhrVb4uyehLGgS2nDS2Limxn/shG8A6UvTSmRmamYf2 vpwJWEl0pAb1fTuvIm0LsMimt1aZGBGW7khdC8YTa6mZMWQBgNcgOjhkth8enlqk8txQ Ae58XB9KDodcprJ1+qW2Vd2g3Hj7eg/CzfS+9/r+j6C/7zwelWxgfjiiVIBKflrizYNg dLiTBEYyiQYtg7ouCjOE7MeRbNcfZPYmM4OpCYleG6Pv7X2Laj/RmtQzO8GQPnw7QWfJ sfV41kc38Vx9O9JU4Osh/nqinznN8zZcm/K3WaI5q2HT2bNdBne56siHa6p/8uFHnYXR XmZw== 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=JWWH0nLE5gW80rwb17oSZfM6VHlugSoNSjEeC143ARI=; b=FxYguz/U+0ecmtFDqbTOaBZ/wVwNQCMqz90LRQRP+80+LuQ32K3CqR/Q+GPcGiLyR0 PTF+4wc/NBIAPza3autL/8YH05o1rf6Ejl0/1UNf2R+5qhwEwQwd461jbbzdF8g5OYQ0 aAODIHsvMxewgiDQSfvUQan0VT6gq6ToWnrLN1xV6c/NuJkhfwzmHB3fqsTmPk9wIBqs +4THm/yTZkohIXmAgMLPnLZpX16OWfaDOg/OO96PGFqtjusOthWSN3FzpyHBbXjfmIjE NrwDhLkZgonpxDXBG1P80dH8juii+L+n/80hUKAQdp+mTQxAzFrLymM8QWdT9kvm5o54 yQ2A== X-Gm-Message-State: APjAAAU+jHlQsM54b6iCkTzegsWxIEwThU4VZqoqz2abMf/TBHJITmjz KxLNjQco9Zw/OVn6JkhuAH8= X-Google-Smtp-Source: APXvYqyH5jZB85XcGwqiW8u/CLFVrXYTftFKTWVpkVfA0lyvGzPyLpjSrqJtEvx3oszxU7OaB0xUKw== X-Received: by 2002:a05:6830:214d:: with SMTP id r13mr3623505otd.121.1568829156454; Wed, 18 Sep 2019 10:52:36 -0700 (PDT) Received: from localhost.localdomain ([2001:470:b:9c3:9e5c:8eff:fe4f:f2d0]) by smtp.gmail.com with ESMTPSA id e5sm1998110otr.81.2019.09.18.10.52.34 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 18 Sep 2019 10:52:35 -0700 (PDT) Subject: [PATCH v10 1/6] mm: Adjust shuffle code to allow for future coalescing From: Alexander Duyck To: virtio-dev@lists.oasis-open.org, kvm@vger.kernel.org, mst@redhat.com, david@redhat.com, dave.hansen@intel.com, linux-kernel@vger.kernel.org, willy@infradead.org, mhocko@kernel.org, linux-mm@kvack.org, vbabka@suse.cz, akpm@linux-foundation.org, mgorman@techsingularity.net, linux-arm-kernel@lists.infradead.org, osalvador@suse.de Date: Wed, 18 Sep 2019 10:52:33 -0700 Message-ID: <20190918175233.23474.93686.stgit@localhost.localdomain> In-Reply-To: <20190918175109.23474.67039.stgit@localhost.localdomain> References: <20190918175109.23474.67039.stgit@localhost.localdomain> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20190918_105238_150685_2E2A0A2B X-CRM114-Status: GOOD ( 19.77 ) X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.2 on bombadil.infradead.org summary: Content analysis details: (-0.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [2607:f8b0:4864:20:0:0:0:344 listed in] [list.dnswl.org] 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider (alexander.duyck[at]gmail.com) -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , 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, nitesh@redhat.com, pbonzini@redhat.com, dan.j.williams@intel.com, alexander.h.duyck@linux.intel.com Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org From: Alexander Duyck 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. Acked-by: David Hildenbrand Reviewed-by: Dan Williams Signed-off-by: Alexander Duyck --- include/linux/mmzone.h | 12 -------- mm/page_alloc.c | 71 ++++++++++++++++++++++++++++-------------------- mm/shuffle.c | 12 ++++---- mm/shuffle.h | 6 ++++ 4 files changed, 54 insertions(+), 47 deletions(-) diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index bda20282746b..125f300981c6 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 3334a769eb91..268a25830114 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -878,6 +878,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 (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 @@ -906,11 +936,13 @@ 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; + bool to_tail; max_order = min_t(unsigned int, MAX_ORDER, pageblock_order + 1); @@ -979,35 +1011,16 @@ 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; - } - } - + area = &zone->free_area[order]; if (is_shuffle_order(order)) - add_to_free_area_random(page, &zone->free_area[order], - migratetype); + to_tail = shuffle_pick_tail(); else - add_to_free_area(page, &zone->free_area[order], migratetype); + to_tail = buddy_merge_likely(pfn, buddy_pfn, page, order); + if (to_tail) + add_to_free_area_tail(page, area, migratetype); + else + add_to_free_area(page, area, migratetype); } /* diff --git a/mm/shuffle.c b/mm/shuffle.c index 3ce12481b1dc..923af4fe887e 100644 --- a/mm/shuffle.c +++ b/mm/shuffle.c @@ -183,11 +183,11 @@ void __meminit __shuffle_free_memory(pg_data_t *pgdat) shuffle_zone(z); } -void add_to_free_area_random(struct page *page, struct free_area *area, - int migratetype) +bool shuffle_pick_tail(void) { static u64 rand; static u8 rand_bits; + bool ret; /* * The lack of locking is deliberate. If 2 threads race to @@ -198,10 +198,10 @@ void add_to_free_area_random(struct page *page, struct free_area *area, rand = get_random_u64(); } - if (rand & 1) - add_to_free_area(page, area, migratetype); - else - add_to_free_area_tail(page, area, migratetype); + ret = rand & 1; + rand_bits--; rand >>= 1; + + return ret; } diff --git a/mm/shuffle.h b/mm/shuffle.h index 777a257a0d2f..4d79f03b6658 100644 --- a/mm/shuffle.h +++ b/mm/shuffle.h @@ -22,6 +22,7 @@ enum mm_shuffle_ctl { DECLARE_STATIC_KEY_FALSE(page_alloc_shuffle_key); extern void page_alloc_shuffle(enum mm_shuffle_ctl ctl); extern void __shuffle_free_memory(pg_data_t *pgdat); +extern bool shuffle_pick_tail(void); static inline void shuffle_free_memory(pg_data_t *pgdat) { if (!static_branch_unlikely(&page_alloc_shuffle_key)) @@ -44,6 +45,11 @@ static inline bool is_shuffle_order(int order) return order >= SHUFFLE_ORDER; } #else +static inline bool shuffle_pick_tail(void) +{ + return false; +} + static inline void shuffle_free_memory(pg_data_t *pgdat) { } From patchwork Wed Sep 18 17:52:41 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Duyck X-Patchwork-Id: 11151079 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 7A20714DB for ; Wed, 18 Sep 2019 17:53:07 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 54DA921907 for ; Wed, 18 Sep 2019 17:53:07 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="KKbzgbGL"; dkim=fail reason="signature verification failed" (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="s3U3h9kF" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 54DA921907 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:To:From:Subject:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=Ax/EEz0kRqGfb9vq5FUjCVWUHM+p8HUAo7mTgMTnDbs=; b=KKbzgbGLSgovT1 OZPCnoRG56aKjIANAT+PxnYVWcKbxGq4e8wdvRy+15oIIsbD7i+00/zfwPMrpA3nq5C6K/tg7j0cV iSrnMEnfUFb79S2LGovyGr7EZqEvDqXITofKgIYnwruvS3pX6vz+kcxvS052vCqWr1b1ml6/qQ9To hT2OXWFno4lSF6Yx6t4cGEz0gXSfm4VjiWG+THGz2rBldQHocaQNhS7XrVkz867Q17PJ9Dkesl6Eo Vj+iKAXbw0kozXMi+Lf72w8jprVUPPUk2spUfFIsYgJuuo56LHdK/F1ecLOi4PEt4LcWws6Kj9zgd 1/QtFr6DzCLkKwf22m4g==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.2 #3 (Red Hat Linux)) id 1iAe8Y-0006lB-EY; Wed, 18 Sep 2019 17:53:06 +0000 Received: from mail-ot1-x341.google.com ([2607:f8b0:4864:20::341]) by bombadil.infradead.org with esmtps (Exim 4.92.2 #3 (Red Hat Linux)) id 1iAe8F-0006RG-Db for linux-arm-kernel@lists.infradead.org; Wed, 18 Sep 2019 17:52:49 +0000 Received: by mail-ot1-x341.google.com with SMTP id 41so597131oti.12 for ; Wed, 18 Sep 2019 10:52:45 -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=PCzoJtXlSlvmmhuZJXUJGfMf/+R9N4NUqoylP2gvkM8=; b=s3U3h9kF7S2ZNzloy0+5/+cFc0Wrga8frJ4delCGCVbge2n1b4te5qTbTb2Zp7FHyr MHQoaVwAV4OpiNWHC43iJVP2IPmI3fuTJgly248nBV40caVSQKCp/svrcdcnTrL8+VBe TiHA4eXvt6Fq9/YBRJHldZEfNWOV+7LjvWdxQjWuNMrVQA1bzMTOJab5UmMC9+9hzcPw x04R/znjNEQcmzlEOfPRo3fibwzQGa8fFhIJci5rhd5Z8YDlCZ9c0AUYO83lgNrNX0m+ RTSD395lLDqqdrLXjN6Hpi4dmZYI89r1c5yFxLvligEiFhhaYmdG+HZ1eQivbyZtP5Me 4Igw== 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=PCzoJtXlSlvmmhuZJXUJGfMf/+R9N4NUqoylP2gvkM8=; b=M1hbiyxBFp7ne4FgIjCsEDdLnkgstO7WEeBopwKskBGpEjkQM1Abfn6EMhyalOX4k9 oifmJaRoe7fWp1Mjwa96dX9F52aOVTD8CvNUqOsuKCt8NxLDqGd4IF+FziqZLWYM2YlX 81k6FtVVkCB/FJRDykHkfhOrjkJv6Wj6bbcyjaY5lDyXu1pKAse9YZxz73p9MaFRjDs/ cPlCn0gUN1/NyzsdzUP+yAuZ0B3rPtojLCC0vf6X/2KstMfOKJpRsUU+x1hccuqS8Hr9 eAcxcPmAiAqb8ENBRUPTGwUyOJpGLBnyPDNv9HPMlqrTyGHqqx1JkApqOX3putHyLzRE GlGg== X-Gm-Message-State: APjAAAUfAEkJKSF3mhpw4/f0w/uLD8LCJeFq5b50zRLXBwShEsn+c9VG i/AJYcFQmUljysiuI3Pk69I= X-Google-Smtp-Source: APXvYqynMKlu1o1Yzkv7NcZAcihLIaOlGRphkTlW9id/lvcX3BwzI3TKbd/CmySspBt/EMHS3KSiKQ== X-Received: by 2002:a9d:7a55:: with SMTP id z21mr3193460otm.26.1568829164289; Wed, 18 Sep 2019 10:52:44 -0700 (PDT) Received: from localhost.localdomain ([2001:470:b:9c3:9e5c:8eff:fe4f:f2d0]) by smtp.gmail.com with ESMTPSA id i5sm1879072otk.10.2019.09.18.10.52.42 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 18 Sep 2019 10:52:43 -0700 (PDT) Subject: [PATCH v10 2/6] mm: Use zone and order instead of free area in free_list manipulators From: Alexander Duyck To: virtio-dev@lists.oasis-open.org, kvm@vger.kernel.org, mst@redhat.com, david@redhat.com, dave.hansen@intel.com, linux-kernel@vger.kernel.org, willy@infradead.org, mhocko@kernel.org, linux-mm@kvack.org, vbabka@suse.cz, akpm@linux-foundation.org, mgorman@techsingularity.net, linux-arm-kernel@lists.infradead.org, osalvador@suse.de Date: Wed, 18 Sep 2019 10:52:41 -0700 Message-ID: <20190918175241.23474.4680.stgit@localhost.localdomain> In-Reply-To: <20190918175109.23474.67039.stgit@localhost.localdomain> References: <20190918175109.23474.67039.stgit@localhost.localdomain> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20190918_105247_678873_04638F70 X-CRM114-Status: GOOD ( 20.21 ) X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.2 on bombadil.infradead.org summary: Content analysis details: (-0.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [2607:f8b0:4864:20:0:0:0:341 listed in] [list.dnswl.org] 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider (alexander.duyck[at]gmail.com) -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , 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, nitesh@redhat.com, pbonzini@redhat.com, dan.j.williams@intel.com, alexander.h.duyck@linux.intel.com Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org 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 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. Since the functions are only used in the file mm/page_alloc.c we can just move them there to reduce noise in the header. Reviewed-by: Dan Williams Reviewed-by: David Hildenbrand Reviewed-by: Pankaj Gupta Signed-off-by: Alexander Duyck --- include/linux/mmzone.h | 32 ----------------------- mm/page_alloc.c | 68 +++++++++++++++++++++++++++++++++++------------- 2 files changed, 49 insertions(+), 51 deletions(-) diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 125f300981c6..270a7b493174 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -100,29 +100,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) { @@ -130,15 +107,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]); diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 268a25830114..f8271ec8e06e 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -877,6 +877,44 @@ static inline struct capture_control *task_capc(struct zone *zone) } #endif /* CONFIG_COMPACTION */ +/* Used for pages not on another list */ +static inline void add_to_free_list(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_list_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_list(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_list(struct page *page, struct zone *zone, + unsigned int order) +{ + list_del(&page->lru); + __ClearPageBuddy(page); + set_page_private(page, 0); + zone->free_area[order].nr_free--; +} + /* * 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 @@ -939,7 +977,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; bool to_tail; @@ -977,7 +1014,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_list(buddy, zone, order); combined_pfn = buddy_pfn & pfn; page = page + (combined_pfn - pfn); pfn = combined_pfn; @@ -1011,16 +1048,15 @@ static inline void __free_one_page(struct page *page, done_merging: set_page_order(page, order); - area = &zone->free_area[order]; if (is_shuffle_order(order)) to_tail = shuffle_pick_tail(); else to_tail = buddy_merge_likely(pfn, buddy_pfn, page, order); if (to_tail) - add_to_free_area_tail(page, area, migratetype); + add_to_free_list_tail(page, zone, order, migratetype); else - add_to_free_area(page, area, migratetype); + add_to_free_list(page, zone, order, migratetype); } /* @@ -2024,13 +2060,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]); @@ -2044,7 +2078,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_list(&page[size], zone, high, migratetype); set_page_order(&page[size], high); } } @@ -2202,8 +2236,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_list(page, zone, current_order); + expand(zone, page, order, current_order, migratetype); set_pcppage_migratetype(page, migratetype); return page; } @@ -2211,7 +2245,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 @@ -2277,7 +2310,7 @@ static int move_freepages(struct zone *zone, VM_BUG_ON_PAGE(page_zone(page) != zone, page); order = page_order(page); - move_to_free_area(page, &zone->free_area[order], migratetype); + move_to_free_list(page, zone, order, migratetype); page += 1 << order; pages_moved += 1 << order; } @@ -2393,7 +2426,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; @@ -2464,8 +2496,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_list(page, zone, current_order, start_type); } /* @@ -3136,7 +3167,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; @@ -3162,7 +3192,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_list(page, zone, order); /* * Set the pageblock if the isolated page is at least half of a @@ -8583,7 +8613,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_list(page, zone, order); for (i = 0; i < (1 << order); i++) SetPageReserved((page+i)); pfn += (1 << order); From patchwork Wed Sep 18 17:52:49 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Duyck X-Patchwork-Id: 11151089 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 0E7D6912 for ; Wed, 18 Sep 2019 17:53:23 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id D6ACD207FC for ; Wed, 18 Sep 2019 17:53:22 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="XwGvJ1R6"; dkim=fail reason="signature verification failed" (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="fqtWSuWE" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org D6ACD207FC Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:To:From:Subject:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=XC3qfcYLsloaRHmLPPJ7jeTjdGh+w3pKX9GLlYtSHww=; b=XwGvJ1R6MKTq8U IFWBHymavUw2HcggTd7QqnhO4GYakA51Gra+YCuG4cCrcK1bMAzq/7FEYWLKAjqaln7Q04xsavs10 RkVqpViI5j4j8xwcLxYoUkOZ2lyQBatoyiTIJD14XjMyKGvoL5hn2QhSvUM13SqFJtqTHJbdPADNC /+1sN4+DUgXzdGi7+XI/FgYwj/1ldT0Gt1Dzv7GqMxFn/gNq9O9kek1IkzjYj4XcmJSF+p3+mHzsM ZT7BqOmEZe7FPw+FqhCYKzd20YpDSsxQtafqKsuZzBO2rIGhqKq8O+xRywVYqLzFpe1e6KZoyadMg x04LoDepqzwpzstW9UDQ==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.2 #3 (Red Hat Linux)) id 1iAe8o-00073S-Aj; Wed, 18 Sep 2019 17:53:22 +0000 Received: from mail-oi1-x243.google.com ([2607:f8b0:4864:20::243]) by bombadil.infradead.org with esmtps (Exim 4.92.2 #3 (Red Hat Linux)) id 1iAe8L-0006aJ-M2 for linux-arm-kernel@lists.infradead.org; Wed, 18 Sep 2019 17:52:58 +0000 Received: by mail-oi1-x243.google.com with SMTP id k25so300257oiw.13 for ; Wed, 18 Sep 2019 10:52:53 -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=y7KbZYkyzwYapIQguuiVD4dqv+WuQAV+dtijq2F1YKY=; b=fqtWSuWEdQN5brslubxqEkR73HEWpiPVxS7MPeY/UlGMhCXi5ijI1jwuVplr5UdtgI LLNDBrrPfhTK7RiMpW9ZAKWBT3kEpIxnS6hKZh+DtAJ5EoUTbceJ1Pkehs5aSa6P2xjJ Omy/nbQGFE1C+Fs4BdA9Iys0xgOFSm/S2fFbf3y52Er+MfCmX5OQlDKC1zlfdE4KByUk oNrO/KEopykBtRJcky9uoOty51MJE/AR0Xqu7VoEb1G+dkMv+UTwUzr0bLPKK8dJty9l 00N5RWrjt1g1fBZNRBOqKqfDRpiEH0hJRu0RSs45kqtrrzQY/0AKVBqzSlzbyiRk+EIr 80sQ== 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=y7KbZYkyzwYapIQguuiVD4dqv+WuQAV+dtijq2F1YKY=; b=pPlMbItO7YAgCubemcn9aUbVWLqk3JX9NVhexAWfMrBuT7Tzj1GqD9Qt6V10wQZKjm +6Itc3qbfqu+fnDXZc4FfKCwMZWrtaHUY7CGw1yuhEL99jX15bH/iXgjoc6J4GuJqaUP 1Mi0aEr8+Frkc4qy8CQe6F51fX/xsq6z9y3qu3nlz79q3ld40hXV59dug9ZVNWNq7fRC zCpReheLtAZP208+zKXxOm1pTUDew8jfQvI2gcHwUphQs4mNMzoegi45m9IdAPusVfcb /mIzNv6cy/FzWy55YxeO8ck/Od5ynKJXz+DFDQL8rTZa5W6MaAcoARZhoQF+EhPOuflF Wt6g== X-Gm-Message-State: APjAAAU3VLUrSlyvGEc2N5dRvplbwyIXAQODdSpxi9Ig4ck4rrbwARor KGOG6vox22fdfvna1Zmg+ng= X-Google-Smtp-Source: APXvYqxowmCQLeG966zggvG9FfTGqv1oo0ZEvVpSSoJEnL5eH/vnc+wKNwMiM5e1u5cySJhHN+bmsQ== X-Received: by 2002:aca:cdc1:: with SMTP id d184mr3270986oig.23.1568829172347; Wed, 18 Sep 2019 10:52:52 -0700 (PDT) Received: from localhost.localdomain ([2001:470:b:9c3:9e5c:8eff:fe4f:f2d0]) by smtp.gmail.com with ESMTPSA id a88sm2212854otb.0.2019.09.18.10.52.50 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 18 Sep 2019 10:52:51 -0700 (PDT) Subject: [PATCH v10 3/6] mm: Introduce Reported pages From: Alexander Duyck To: virtio-dev@lists.oasis-open.org, kvm@vger.kernel.org, mst@redhat.com, david@redhat.com, dave.hansen@intel.com, linux-kernel@vger.kernel.org, willy@infradead.org, mhocko@kernel.org, linux-mm@kvack.org, vbabka@suse.cz, akpm@linux-foundation.org, mgorman@techsingularity.net, linux-arm-kernel@lists.infradead.org, osalvador@suse.de Date: Wed, 18 Sep 2019 10:52:49 -0700 Message-ID: <20190918175249.23474.51171.stgit@localhost.localdomain> In-Reply-To: <20190918175109.23474.67039.stgit@localhost.localdomain> References: <20190918175109.23474.67039.stgit@localhost.localdomain> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20190918_105253_801359_94E67A19 X-CRM114-Status: GOOD ( 35.09 ) X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.2 on bombadil.infradead.org summary: Content analysis details: (-0.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [2607:f8b0:4864:20:0:0:0:243 listed in] [list.dnswl.org] 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider (alexander.duyck[at]gmail.com) -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , 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, nitesh@redhat.com, pbonzini@redhat.com, dan.j.williams@intel.com, alexander.h.duyck@linux.intel.com Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org From: Alexander Duyck In order to pave the way for free page reporting 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, this patch adds the concept of a Reported Buddy, which is essentially meant to just be the Uptodate flag used in conjunction with the Buddy page type. It adds a set of pointers we shall call "reported_boundary" which represent the upper boundary between the unreported and reported 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 verify that it went through the reporting process. Ultimately a free list has been fully processed when the boundary has been moved from the tail all they way up to occupying the first entry in the list. One limitation to this approach is that it is essentially a linear search and in the case of the free lists we can have pages added to either the head or the tail of the list. In order to place limits on this we only allow pages to be added before the reported_boundary instead of adding to the tail itself. An 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 trying to allocate the reported pages that were likely evicted from the guest memory. Since we will only be reporting one zone at a time we keep the boundary limited to being defined for just the zone we are currently reporting pages from. Doing this we can keep the number of additional pointers needed quite small. To flag that the boundaries are in place we use a single bit in the zone to indicate that reporting and the boundaries are active. We store the index of the boundary pointer used to track the reported page in the page->index value. Doing this we can avoid unnecessary computation to determine the index value again. There should be no issues with this as the value is unused when the page is in the buddy allocator, and is reset as soon as the page is removed from the free list. Signed-off-by: Alexander Duyck --- include/linux/mmzone.h | 16 ++++ include/linux/page-flags.h | 11 +++ mm/Kconfig | 11 +++ mm/compaction.c | 5 + mm/memory_hotplug.c | 2 mm/page_alloc.c | 67 +++++++++++++++-- mm/page_reporting.h | 178 ++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 283 insertions(+), 7 deletions(-) create mode 100644 mm/page_reporting.h diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 270a7b493174..53922c30b8d8 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -463,6 +463,14 @@ struct zone { seqlock_t span_seqlock; #endif +#ifdef CONFIG_PAGE_REPORTING + /* + * Pointer to reported page tracking statistics array. The size of + * the array is MAX_ORDER - PAGE_REPORTING_MIN_ORDER. NULL when + * unused page reporting is not present. + */ + unsigned long *reported_pages; +#endif int initialized; /* Write-intensive fields used from the page allocator */ @@ -538,6 +546,14 @@ enum zone_flags { ZONE_BOOSTED_WATERMARK, /* zone recently boosted watermarks. * Cleared when kswapd is woken. */ + ZONE_PAGE_REPORTING_ACTIVE, /* zone enabled page reporting and is + * activly flushing the data out of + * higher order pages. + */ + ZONE_PAGE_REPORTING_REQUESTED, /* zone enabled page reporting and has + * requested flushing 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 f91cb8898ff0..759a3b3956f2 100644 --- a/include/linux/page-flags.h +++ b/include/linux/page-flags.h @@ -163,6 +163,9 @@ enum pageflags { /* non-lru isolated movable page */ PG_isolated = PG_reclaim, + + /* Buddy pages. Used to track which pages have been reported */ + PG_reported = PG_uptodate, }; #ifndef __GENERATING_BOUNDS_H @@ -432,6 +435,14 @@ static inline bool set_hwpoison_free_buddy_page(struct page *page) #endif /* + * PageReported() is used to track reported free pages within the Buddy + * allocator. We can use the non-atomic version of the test and set + * operations as both should be shielded with the zone lock to prevent + * any possible races on the setting or clearing of the bit. + */ +__PAGEFLAG(Reported, reported, PF_NO_COMPOUND) + +/* * On an anonymous page mapped into a user virtual memory area, * page->mapping points to its anon_vma, not to a struct address_space; * with the PAGE_MAPPING_ANON bit set to distinguish it. See rmap.h. diff --git a/mm/Kconfig b/mm/Kconfig index a5dae9a7eb51..0419b2a9be3e 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -237,6 +237,17 @@ config COMPACTION linux-mm@kvack.org. # +# support for unused page reporting +config PAGE_REPORTING + bool "Allow for reporting of unused pages" + def_bool n + help + Unused page reporting allows for the incremental acquisition of + unused pages from the buddy allocator for the purpose of reporting + those pages to another entity, such as a hypervisor, so that the + memory can be freed up for other uses. + +# # support for page migration # config MIGRATION diff --git a/mm/compaction.c b/mm/compaction.c index ce08b39d85d4..60e064330b3a 100644 --- a/mm/compaction.c +++ b/mm/compaction.c @@ -24,6 +24,7 @@ #include #include #include "internal.h" +#include "page_reporting.h" #ifdef CONFIG_COMPACTION static inline void count_compact_event(enum vm_event_item item) @@ -1325,6 +1326,8 @@ static int next_search_order(struct compact_control *cc, int order) continue; spin_lock_irqsave(&cc->zone->lock, flags); + page_reporting_free_area_release(cc->zone, order, + MIGRATE_MOVABLE); freelist = &area->free_list[MIGRATE_MOVABLE]; list_for_each_entry_reverse(freepage, freelist, lru) { unsigned long pfn; @@ -1681,6 +1684,8 @@ static unsigned long fast_find_migrateblock(struct compact_control *cc) continue; spin_lock_irqsave(&cc->zone->lock, flags); + page_reporting_free_area_release(cc->zone, order, + MIGRATE_MOVABLE); freelist = &area->free_list[MIGRATE_MOVABLE]; list_for_each_entry(freepage, freelist, lru) { unsigned long free_pfn; diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index 49f7bf91c25a..09c6f52e2bc5 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -41,6 +41,7 @@ #include "internal.h" #include "shuffle.h" +#include "page_reporting.h" /* * online_page_callback contains pointer to current page onlining function. @@ -1613,6 +1614,7 @@ static int __ref __offline_pages(unsigned long start_pfn, if (!populated_zone(zone)) { zone_pcp_reset(zone); build_all_zonelists(NULL); + page_reporting_reset_zone(zone); } else zone_pcp_update(zone); diff --git a/mm/page_alloc.c b/mm/page_alloc.c index f8271ec8e06e..ed0128c65936 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -74,6 +74,7 @@ #include #include "internal.h" #include "shuffle.h" +#include "page_reporting.h" /* prevent >1 _updater_ of zone percpu pageset ->high and ->batch fields */ static DEFINE_MUTEX(pcp_batch_high_lock); @@ -891,10 +892,15 @@ static inline void add_to_free_list(struct page *page, struct zone *zone, static inline void add_to_free_list_tail(struct page *page, struct zone *zone, unsigned int order, int migratetype) { - struct free_area *area = &zone->free_area[order]; + struct list_head *tail = get_unreported_tail(zone, order, migratetype); - list_add_tail(&page->lru, &area->free_list[migratetype]); - area->nr_free++; + /* + * To prevent the unreported pages from slipping behind our iterator + * we will force them to be inserted in front of it. By doing this + * we should only need to make one pass through the freelist. + */ + list_add_tail(&page->lru, tail); + zone->free_area[order].nr_free++; } /* Used for pages which are on another list */ @@ -903,12 +909,20 @@ static inline void move_to_free_list(struct page *page, struct zone *zone, { struct free_area *area = &zone->free_area[order]; + /* Make certain the page isn't occupying the boundary */ + if (unlikely(PageReported(page))) + __del_page_from_reported_list(page, zone); + list_move(&page->lru, &area->free_list[migratetype]); } static inline void del_page_from_free_list(struct page *page, struct zone *zone, unsigned int order) { + /* remove page from reported list, and clear reported state */ + if (unlikely(PageReported(page))) + del_page_from_reported_list(page, zone, order); + list_del(&page->lru); __ClearPageBuddy(page); set_page_private(page, 0); @@ -972,7 +986,7 @@ static inline void del_page_from_free_list(struct page *page, 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 reported) { struct capture_control *capc = task_capc(zone); unsigned long uninitialized_var(buddy_pfn); @@ -1048,7 +1062,9 @@ static inline void __free_one_page(struct page *page, done_merging: set_page_order(page, order); - if (is_shuffle_order(order)) + if (reported) + to_tail = true; + else if (is_shuffle_order(order)) to_tail = shuffle_pick_tail(); else to_tail = buddy_merge_likely(pfn, buddy_pfn, page, order); @@ -1367,7 +1383,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); @@ -1383,7 +1399,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); } @@ -2245,6 +2261,43 @@ struct page *__rmqueue_smallest(struct zone *zone, unsigned int order, return NULL; } +#ifdef CONFIG_PAGE_REPORTING +struct list_head **reported_boundary __read_mostly; + +/** + * free_reported_page - Return a now-reported page back where we got it + * @page: Page that was reported + * @order: Order of the reported page + * + * This function will pull the migratetype and order information out + * of the page and attempt to return it where it found it. If the page + * is added to the free list without changes we will mark it as being + * reported. + */ +void free_reported_page(struct page *page, unsigned int order) +{ + struct zone *zone = page_zone(page); + unsigned long pfn; + unsigned int mt; + + /* zone lock should be held when this function is called */ + lockdep_assert_held(&zone->lock); + + pfn = page_to_pfn(page); + mt = get_pfnblock_migratetype(page, pfn); + __free_one_page(page, pfn, zone, order, mt, true); + + /* + * If page was not comingled with another page we can consider + * the result to be "reported" since part of the page hasn't been + * modified, otherwise we would need to report on the new larger + * page. + */ + if (PageBuddy(page) && page_order(page) == order) + add_page_to_reported_list(page, zone, order, mt); +} +#endif /* CONFIG_PAGE_REPORTING */ + /* * This array describes the order lists are fallen back to when * the free lists for the desirable migrate type are depleted diff --git a/mm/page_reporting.h b/mm/page_reporting.h new file mode 100644 index 000000000000..c5e1bb58ad96 --- /dev/null +++ b/mm/page_reporting.h @@ -0,0 +1,178 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _MM_PAGE_REPORTING_H +#define _MM_PAGE_REPORTING_H + +#include +#include +#include +#include +#include +#include + +#define PAGE_REPORTING_MIN_ORDER pageblock_order +#define PAGE_REPORTING_HWM 32 + +#ifdef CONFIG_PAGE_REPORTING +/* Reported page accessors, defined in page_alloc.c */ +void free_reported_page(struct page *page, unsigned int order); + +/* Free reported_pages and reset reported page tracking count to 0 */ +static inline void page_reporting_reset_zone(struct zone *zone) +{ + kfree(zone->reported_pages); + zone->reported_pages = NULL; +} + +/* Boundary functions */ +static inline pgoff_t +get_reporting_index(unsigned int order, unsigned int migratetype) +{ + /* + * We will only ever be dealing with pages greater-than or equal to + * PAGE_REPORTING_MIN_ORDER. Since that is the case we can avoid + * allocating unused space by limiting our index range to only the + * orders that are supported for page reporting. + */ + return (order - PAGE_REPORTING_MIN_ORDER) * MIGRATE_TYPES + migratetype; +} + +extern struct list_head **reported_boundary __read_mostly; + +static inline void +page_reporting_reset_boundary(struct zone *zone, unsigned int order, int mt) +{ + int index; + + if (order < PAGE_REPORTING_MIN_ORDER) + return; + if (!test_bit(ZONE_PAGE_REPORTING_ACTIVE, &zone->flags)) + return; + + index = get_reporting_index(order, mt); + reported_boundary[index] = &zone->free_area[order].free_list[mt]; +} + +static inline void page_reporting_disable_boundaries(struct zone *zone) +{ + /* zone lock should be held when this function is called */ + lockdep_assert_held(&zone->lock); + + __clear_bit(ZONE_PAGE_REPORTING_ACTIVE, &zone->flags); +} + +static inline void +page_reporting_free_area_release(struct zone *zone, unsigned int order, int mt) +{ + page_reporting_reset_boundary(zone, order, mt); +} + +/* + * Method for obtaining the tail of the free list. Using this allows for + * tail insertions of unreported pages into the region that is currently + * being scanned so as to avoid interleaving reported and unreported pages. + */ +static inline struct list_head * +get_unreported_tail(struct zone *zone, unsigned int order, int migratetype) +{ + if (order >= PAGE_REPORTING_MIN_ORDER && + test_bit(ZONE_PAGE_REPORTING_ACTIVE, &zone->flags)) + return reported_boundary[get_reporting_index(order, + migratetype)]; + + return &zone->free_area[order].free_list[migratetype]; +} + +/* + * Functions for adding/removing reported pages to the freelist. + * All of them expect the zone lock to be held to maintain + * consistency of the reported list as a subset of the free list. + */ +static inline void +add_page_to_reported_list(struct page *page, struct zone *zone, + unsigned int order, unsigned int mt) +{ + /* + * Default to using index 0, this will be updated later if the zone + * is still being processed. + */ + page->index = 0; + + /* flag page as reported */ + __SetPageReported(page); + + /* update areated page accounting */ + zone->reported_pages[order - PAGE_REPORTING_MIN_ORDER]++; +} + +static inline void page_reporting_pull_boundary(struct page *page) +{ + struct list_head **tail = &reported_boundary[page->index]; + + if (*tail == &page->lru) + *tail = page->lru.next; +} + +static inline void +__del_page_from_reported_list(struct page *page, struct zone *zone) +{ + /* + * Since the page is being pulled from the list we need to update + * the boundary, after that we can just update the index so that + * the correct boundary will be checked in the future. + */ + if (test_bit(ZONE_PAGE_REPORTING_ACTIVE, &zone->flags)) + page_reporting_pull_boundary(page); +} + +static inline void +del_page_from_reported_list(struct page *page, struct zone *zone, + unsigned int order) +{ + __del_page_from_reported_list(page, zone); + + /* page_private will contain the page order, so just use it directly */ + zone->reported_pages[order - PAGE_REPORTING_MIN_ORDER]--; + + /* clear the flag so we can report on it when it returns */ + __ClearPageReported(page); +} + +#else /* CONFIG_PAGE_REPORTING */ +static inline void page_reporting_reset_zone(struct zone *zone) +{ +} + +static inline void +page_reporting_free_area_release(struct zone *zone, unsigned int order, int mt) +{ +} + +static inline struct list_head * +get_unreported_tail(struct zone *zone, unsigned int order, int migratetype) +{ + return &zone->free_area[order].free_list[migratetype]; +} + +static inline void +add_page_to_reported_list(struct page *page, struct zone *zone, + int order, int migratetype) +{ +} + +static inline void +__del_page_from_reported_list(struct page *page, struct zone *zone) +{ +} + +static inline void +del_page_from_reported_list(struct page *page, struct zone *zone, + unsigned int order) +{ +} + +static inline void +move_page_to_reported_list(struct page *page, struct zone *zone, int dest_mt) +{ +} +#endif /* CONFIG_PAGE_REPORTING */ +#endif /*_MM_PAGE_REPORTING_H */ From patchwork Wed Sep 18 17:52:57 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Duyck X-Patchwork-Id: 11151093 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 23531912 for ; Wed, 18 Sep 2019 17:53:48 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id EB1A921925 for ; Wed, 18 Sep 2019 17:53:47 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="A6nQf3WJ"; dkim=fail reason="signature verification failed" (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="hXK6gWJS" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org EB1A921925 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:To:From:Subject:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=6p+baGprx5LLRhKdX0J03cLdC1cW/J339j1cvqMd4Tc=; b=A6nQf3WJSyd37f T/dUGUyBv1a+2sHCOjPxUKQSCBgB4j7jUKqWONM7i/6f08ohHvZvPIhpUqNCcO1MFDkVCNSrMQzio 1niJ739YNKhkrdnDo1cgJDWQEcVIaWPX2OjH5d57Pao/bCw3xWonRVpaJHbdwDYWYnXagRKBCzwzf WXstwI3ZQb3tvAZiY6hhoxZ7Lv0sMr7GLWv5gUrNRRvrbOAxg3kDoLtQXHWT5bi8GrkZwdH/KQkSC w9hVY++4FKPqJwcMYgpSzOvwyWxkrkfBIpZq2gboc8VWePKAVW1VJz+uoHyP4zY8QmoAPMioUFtwh lbgysz3ClMy36a4u9j5A==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.2 #3 (Red Hat Linux)) id 1iAe97-0007M2-PO; Wed, 18 Sep 2019 17:53:41 +0000 Received: from mail-oi1-x242.google.com ([2607:f8b0:4864:20::242]) by bombadil.infradead.org with esmtps (Exim 4.92.2 #3 (Red Hat Linux)) id 1iAe8T-0006iZ-Hx for linux-arm-kernel@lists.infradead.org; Wed, 18 Sep 2019 17:53:03 +0000 Received: by mail-oi1-x242.google.com with SMTP id e18so411883oii.0 for ; Wed, 18 Sep 2019 10:53:01 -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=AhRgakU0MKQRR6cibd3J7rx7XiKVe3yFDUh+nL02+OU=; b=hXK6gWJSwJAbm43T7vAw0Lk5NiQNKKHOKVPzjtVAII4vLjAzb/FsL6WBNI70+e/Bxg MbApfP31XVX46SKEWHLvQmUANP1BgvMIfjjjk+jgs6ZfbQjrvc9Dyl+5iYVBGpm6WO4d yiFgPCy3JWFrkgoHX81/tacMzaTYGXwAzx0sBmB9C2riFZNi5C+ZwdI1R7LKHr3FTddL BeEpGAiKin6u0z5B3LMWUdhZID+aJVfzSQqNGlJQ6gNAssJu5vjs6DKpn2GwTH/8VdzR L95CDpMHMbud+UEn4Zl4Xbv+x7fPVob+VeBEj2EUYUafwgqXj9kYTSm2E1e/eUZ5Qdol AVpw== 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=AhRgakU0MKQRR6cibd3J7rx7XiKVe3yFDUh+nL02+OU=; b=E6ip/XmWSIzkUjkwrX+utZBECMCYQ4JplCPn3Q6/AWfW7rDSBvV2hzc05zhSvsmpo3 +y4Y4aWTsYQv+SDnNwsdIgb/tvSg5iDS6yus1k0+vbg6JB8lqtzAtD3w8fbDZCdDm1lu ffgdcjUciVbnvC2uH4Pd9Fysh60QX1fWevuz3cTgXjamAZyPw//jaCu90BPgZmxERwYG Wv/E+Zs2yh1Vb1v+wTbgewEnjq5mSMDPhgbCZT7tKAJlaDE+LfRRXH1zsIdrTDy8pYfk fKJeChqIcD2RZ1OkLJfy1FbgdD0nCD2tFKZ44sQtqqOTbxC5NmUriFK7k+ZznyHWpnk9 EvBA== X-Gm-Message-State: APjAAAV4dPn8nH1AzwdXqClwsMNXYbf1pJw3II89amVeIzyyHL+o/r+q Al5PO0L4bXhzVltpEralLIw= X-Google-Smtp-Source: APXvYqzE2EGl7PiThZPVTqLhVx5ehyPxdcY4JGRIHF9S8G2ToMQjPgx935E65AXQrj45hWOTteTNaA== X-Received: by 2002:aca:5856:: with SMTP id m83mr2955719oib.90.1568829180351; Wed, 18 Sep 2019 10:53:00 -0700 (PDT) Received: from localhost.localdomain ([2001:470:b:9c3:9e5c:8eff:fe4f:f2d0]) by smtp.gmail.com with ESMTPSA id v12sm1848407oiv.58.2019.09.18.10.52.58 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 18 Sep 2019 10:52:59 -0700 (PDT) Subject: [PATCH v10 4/6] mm: Add device side and notifier for unused page reporting From: Alexander Duyck To: virtio-dev@lists.oasis-open.org, kvm@vger.kernel.org, mst@redhat.com, david@redhat.com, dave.hansen@intel.com, linux-kernel@vger.kernel.org, willy@infradead.org, mhocko@kernel.org, linux-mm@kvack.org, vbabka@suse.cz, akpm@linux-foundation.org, mgorman@techsingularity.net, linux-arm-kernel@lists.infradead.org, osalvador@suse.de Date: Wed, 18 Sep 2019 10:52:57 -0700 Message-ID: <20190918175257.23474.73638.stgit@localhost.localdomain> In-Reply-To: <20190918175109.23474.67039.stgit@localhost.localdomain> References: <20190918175109.23474.67039.stgit@localhost.localdomain> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20190918_105301_679690_9B28F871 X-CRM114-Status: GOOD ( 34.56 ) X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.2 on bombadil.infradead.org summary: Content analysis details: (-0.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [2607:f8b0:4864:20:0:0:0:242 listed in] [list.dnswl.org] 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider (alexander.duyck[at]gmail.com) -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , 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, nitesh@redhat.com, pbonzini@redhat.com, dan.j.williams@intel.com, alexander.h.duyck@linux.intel.com Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org From: Alexander Duyck With this patch we are adding the pieces needed to enable the reporting of pages to a specific device. That device needs to register a page reporting device that can be used to handle notifications that that pages are unused. Registering the device will in turn enable the notifications and allow page reporting to be active. When the the device is unregistered it will disable page reporting notifications. For now we only allow one page reporting device to be registered at a time. The determination of when to start reporting is based on the tracking of the number of free pages in a given area versus the number of reported pages in that area. We keep track of the number of reported pages per free_area in a separate zone specific area. We do this to avoid modifying the free_area structure as this can lead to false sharing for the highest order with the zone lock which leads to a noticeable performance degradation. Once reporting has started get_unreported_pages will use the reported_boundary pointers to track where it should resume processing the free lists. It will go through and either set the index if it finds a reported page, or it will attempt to isolate the page so that it can be reported. Signed-off-by: Alexander Duyck --- include/linux/page_reporting.h | 31 ++++ mm/Makefile | 1 mm/page_alloc.c | 10 + mm/page_reporting.c | 350 ++++++++++++++++++++++++++++++++++++++++ mm/page_reporting.h | 46 +++++ 5 files changed, 436 insertions(+), 2 deletions(-) create mode 100644 include/linux/page_reporting.h create mode 100644 mm/page_reporting.c diff --git a/include/linux/page_reporting.h b/include/linux/page_reporting.h new file mode 100644 index 000000000000..afa214f7beaf --- /dev/null +++ b/include/linux/page_reporting.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LINUX_PAGE_REPORTING_H +#define _LINUX_PAGE_REPORTING_H + +#include + +struct page_reporting_dev_info { + /* function that alters pages to make them "reported" */ + void (*report)(struct page_reporting_dev_info *phdev, + unsigned int nents); + + /* scatterlist containing pages to be processed */ + struct scatterlist *sg; + + /* + * Upper limit on the number of pages that the react function + * expects to be placed into the batch list to be processed. + */ + unsigned long capacity; + + /* work struct for processing reports */ + struct delayed_work work; + + /* The number of zones requesting reporting */ + atomic_t refcnt; +}; + +/* Tear-down and bring-up for page reporting devices */ +void page_reporting_unregister(struct page_reporting_dev_info *phdev); +int page_reporting_register(struct page_reporting_dev_info *phdev); +#endif /*_LINUX_PAGE_REPORTING_H */ diff --git a/mm/Makefile b/mm/Makefile index d996846697ef..fc4fa17b6c83 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -107,3 +107,4 @@ obj-$(CONFIG_PERCPU_STATS) += percpu-stats.o obj-$(CONFIG_ZONE_DEVICE) += memremap.o obj-$(CONFIG_HMM_MIRROR) += hmm.o obj-$(CONFIG_MEMFD_CREATE) += memfd.o +obj-$(CONFIG_PAGE_REPORTING) += page_reporting.o diff --git a/mm/page_alloc.c b/mm/page_alloc.c index ed0128c65936..b4189d9cc729 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1073,6 +1073,14 @@ static inline void __free_one_page(struct page *page, add_to_free_list_tail(page, zone, order, migratetype); else add_to_free_list(page, zone, order, migratetype); + + /* + * No need to notify on a reported page as the total count of + * unreported pages will not have increased since we have essentially + * merged the reported page with one or more unreported pages. + */ + if (!reported) + page_reporting_notify_free(zone, order); } /* @@ -2262,8 +2270,6 @@ struct page *__rmqueue_smallest(struct zone *zone, unsigned int order, } #ifdef CONFIG_PAGE_REPORTING -struct list_head **reported_boundary __read_mostly; - /** * free_reported_page - Return a now-reported page back where we got it * @page: Page that was reported diff --git a/mm/page_reporting.c b/mm/page_reporting.c new file mode 100644 index 000000000000..3e36f250d2d6 --- /dev/null +++ b/mm/page_reporting.c @@ -0,0 +1,350 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include +#include + +#include "page_reporting.h" +#include "internal.h" + +static struct page_reporting_dev_info __rcu *ph_dev_info __read_mostly; +struct list_head **reported_boundary __read_mostly; + +#define for_each_reporting_migratetype_order(_order, _type) \ + for (_order = MAX_ORDER; _order-- != PAGE_REPORTING_MIN_ORDER;) \ + for (_type = MIGRATE_TYPES; _type--;) \ + if (!is_migrate_isolate(_type)) + +static void page_reporting_populate_metadata(struct zone *zone) +{ + size_t size; + int node; + + /* + * We need to make sure we have somewhere to store the tracking + * data for how many reported pages are in the zone. To do that + * we need to make certain zone->reported_pages is populated. + */ + if (zone->reported_pages) + return; + + node = zone_to_nid(zone); + size = (MAX_ORDER - PAGE_REPORTING_MIN_ORDER) * sizeof(unsigned long); + zone->reported_pages = kzalloc_node(size, GFP_KERNEL, node); +} + +static void page_reporting_reset_all_boundaries(struct zone *zone) +{ + unsigned int order, mt; + + /* Update boundary data to reflect the zone we are currently working */ + for_each_reporting_migratetype_order(order, mt) + page_reporting_reset_boundary(zone, order, mt); +} + +static struct page * +get_unreported_page(struct zone *zone, unsigned int order, int mt) +{ + struct list_head *list = &zone->free_area[order].free_list[mt]; + struct list_head *tail = get_unreported_tail(zone, order, mt); + unsigned long index = get_reporting_index(order, mt); + struct page *page; + + /* Find a page of the appropriate size in the preferred list */ + page = list_last_entry(tail, struct page, lru); + list_for_each_entry_from_reverse(page, list, lru) { + /* If we entered this loop then the "raw" list isn't empty */ + + /* + * We are going to skip over the reported pages. Make + * certain that the index of those pages are correct + * as we will later be moving the boundary into place + * above them. + */ + if (PageReported(page)) { + page->index = index; + tail = &page->lru; + continue; + } + + /* Drop reference to page if isolate fails */ + if (__isolate_free_page(page, order)) + goto out; + + break; + } + + page = NULL; +out: + /* Update the boundary */ + reported_boundary[index] = tail; + + return page; +} + +static void +__page_reporting_cancel(struct zone *zone, + struct page_reporting_dev_info *phdev) +{ + /* processing of the zone is complete, we can disable boundaries */ + page_reporting_disable_boundaries(zone); + + /* + * If there are no longer enough free pages to fully populate + * the scatterlist, then we can just shut it down for this zone. + */ + __clear_bit(ZONE_PAGE_REPORTING_REQUESTED, &zone->flags); + atomic_dec(&phdev->refcnt); +} + +static unsigned int +page_reporting_fill(struct zone *zone, struct page_reporting_dev_info *phdev) +{ + struct scatterlist *sg = phdev->sg; + unsigned int order, mt, count = 0; + + sg_init_table(phdev->sg, phdev->capacity); + + /* Make sure the boundaries are enabled */ + if (!__test_and_set_bit(ZONE_PAGE_REPORTING_ACTIVE, &zone->flags)) + page_reporting_reset_all_boundaries(zone); + + for_each_reporting_migratetype_order(order, mt) { + struct page *page; + + /* + * Pull pages from free list until we have drained + * it or we have reached capacity. + */ + while ((page = get_unreported_page(zone, order, mt))) { + sg_set_page(&sg[count], page, PAGE_SIZE << order, 0); + + if (++count == phdev->capacity) + return phdev->capacity; + } + } + + /* mark end of scatterlist due to underflow */ + if (count) + sg_mark_end(&sg[count - 1]); + + /* We ran out of pages so we can stop now */ + __page_reporting_cancel(zone, phdev); + + return count; +} + +static void page_reporting_drain(struct page_reporting_dev_info *phdev) +{ + struct scatterlist *sg = phdev->sg; + + /* + * Drain the now reported pages back into their respective + * free lists/areas. We assume at least one page is populated. + */ + do { + free_reported_page(sg_page(sg), get_order(sg->length)); + } while (!sg_is_last(sg++)); +} + +/* + * The page reporting cycle consists of 4 stages, fill, report, 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. + */ +static void +page_reporting_cycle(struct zone *zone, struct page_reporting_dev_info *phdev) +{ + /* + * Guarantee boundaries and stats are populated before we + * start placing reported pages in the zone. + */ + page_reporting_populate_metadata(zone); + + spin_lock_irq(&zone->lock); + + /* Cancel the request if we failed to populate zone metadata */ + if (!zone->reported_pages) { + __page_reporting_cancel(zone, phdev); + goto zone_not_ready; + } + + do { + /* Pull pages out of allocator into a scaterlist */ + unsigned int nents = page_reporting_fill(zone, phdev); + + /* no pages were acquired, give up */ + if (!nents) + break; + + spin_unlock_irq(&zone->lock); + + /* begin processing pages in local list */ + phdev->report(phdev, nents); + + spin_lock_irq(&zone->lock); + + /* + * We should have a scatterlist of pages that have been + * processed. Return them to their original free lists. + */ + page_reporting_drain(phdev); + + /* keep pulling pages till there are none to pull */ + } while (test_bit(ZONE_PAGE_REPORTING_REQUESTED, &zone->flags)); +zone_not_ready: + spin_unlock_irq(&zone->lock); +} + +static void page_reporting_process(struct work_struct *work) +{ + struct delayed_work *d_work = to_delayed_work(work); + struct page_reporting_dev_info *phdev = + container_of(d_work, struct page_reporting_dev_info, work); + struct zone *zone = first_online_pgdat()->node_zones; + + do { + if (test_bit(ZONE_PAGE_REPORTING_REQUESTED, &zone->flags)) + page_reporting_cycle(zone, phdev); + + /* Move to next zone, if at end of list start over */ + zone = next_zone(zone) ? : first_online_pgdat()->node_zones; + + /* + * As long as refcnt has not reached zero there are still + * zones to be processed. + */ + } while (atomic_read(&phdev->refcnt)); +} + +/* request page reporting on this zone */ +void __page_reporting_request(struct zone *zone) +{ + struct page_reporting_dev_info *phdev; + + rcu_read_lock(); + + /* + * We use RCU to protect the ph_dev_info pointer. In almost all + * cases this should be present, however in the unlikely case of + * a shutdown this will be NULL and we should exit. + */ + phdev = rcu_dereference(ph_dev_info); + if (unlikely(!phdev)) + goto out; + + /* + * 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_PAGE_REPORTING_REQUESTED, &zone->flags); + + /* + * 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. + */ + if (!atomic_fetch_inc(&phdev->refcnt)) + schedule_delayed_work(&phdev->work, HZ / 10); +out: + rcu_read_unlock(); +} + +static DEFINE_MUTEX(page_reporting_mutex); +DEFINE_STATIC_KEY_FALSE(page_reporting_notify_enabled); + +void page_reporting_unregister(struct page_reporting_dev_info *phdev) +{ + mutex_lock(&page_reporting_mutex); + + if (rcu_access_pointer(ph_dev_info) == phdev) { + /* Disable page reporting notification */ + static_branch_disable(&page_reporting_notify_enabled); + RCU_INIT_POINTER(ph_dev_info, NULL); + synchronize_rcu(); + + /* Flush any existing work, and lock it out */ + cancel_delayed_work_sync(&phdev->work); + + /* Free scatterlist */ + kfree(phdev->sg); + phdev->sg = NULL; + + /* Free boundaries */ + kfree(reported_boundary); + reported_boundary = NULL; + } + + mutex_unlock(&page_reporting_mutex); +} +EXPORT_SYMBOL_GPL(page_reporting_unregister); + +int page_reporting_register(struct page_reporting_dev_info *phdev) +{ + struct zone *zone; + int err = 0; + + /* No point in enabling this if it cannot handle any pages */ + if (WARN_ON(!phdev->capacity)) + return -EINVAL; + + mutex_lock(&page_reporting_mutex); + + /* nothing to do if already in use */ + if (rcu_access_pointer(ph_dev_info)) { + err = -EBUSY; + goto err_out; + } + + /* + * Allocate space to store the boundaries for the zone we are + * actively reporting on. We will need to store one boundary + * pointer per migratetype, and then we need to have one of these + * arrays per order for orders greater than or equal to + * PAGE_REPORTING_MIN_ORDER. + */ + reported_boundary = kcalloc(get_reporting_index(MAX_ORDER, 0), + sizeof(struct list_head *), GFP_KERNEL); + if (!reported_boundary) { + err = -ENOMEM; + goto err_out; + } + + /* allocate scatterlist to store pages being reported on */ + phdev->sg = kcalloc(phdev->capacity, sizeof(*phdev->sg), GFP_KERNEL); + if (!phdev->sg) { + err = -ENOMEM; + + kfree(reported_boundary); + reported_boundary = NULL; + + goto err_out; + } + + + /* initialize refcnt and work structures */ + atomic_set(&phdev->refcnt, 0); + INIT_DELAYED_WORK(&phdev->work, &page_reporting_process); + + /* assign device, and begin initial flush of populated zones */ + rcu_assign_pointer(ph_dev_info, phdev); + for_each_populated_zone(zone) { + spin_lock_irq(&zone->lock); + __page_reporting_request(zone); + spin_unlock_irq(&zone->lock); + } + + /* enable page reporting notification */ + static_branch_enable(&page_reporting_notify_enabled); +err_out: + mutex_unlock(&page_reporting_mutex); + + return err; +} +EXPORT_SYMBOL_GPL(page_reporting_register); diff --git a/mm/page_reporting.h b/mm/page_reporting.h index c5e1bb58ad96..acc6dafc74a1 100644 --- a/mm/page_reporting.h +++ b/mm/page_reporting.h @@ -23,6 +23,48 @@ static inline void page_reporting_reset_zone(struct zone *zone) zone->reported_pages = NULL; } +DECLARE_STATIC_KEY_FALSE(page_reporting_notify_enabled); +void __page_reporting_request(struct zone *zone); + +/** + * page_reporting_notify_free - Free page notification to 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 __page_reporting_request + * 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 page_reporting_notify_free(struct zone *zone, int order) +{ + unsigned long nr_reported; + + /* Called from hot path in __free_one_page() */ + if (!static_branch_unlikely(&page_reporting_notify_enabled)) + return; + + /* Limit notifications only to higher order pages */ + if (order < PAGE_REPORTING_MIN_ORDER) + return; + + /* Do not bother with tests if we have already requested reporting */ + if (test_bit(ZONE_PAGE_REPORTING_REQUESTED, &zone->flags)) + return; + + /* If reported_pages is not populated, assume 0 */ + nr_reported = zone->reported_pages ? + zone->reported_pages[order - PAGE_REPORTING_MIN_ORDER] : 0; + + /* Only request it if we have enough to begin the page reporting */ + if (zone->free_area[order].nr_free < nr_reported + PAGE_REPORTING_HWM) + return; + + /* This is slow, but should be called very rarely */ + __page_reporting_request(zone); +} + /* Boundary functions */ static inline pgoff_t get_reporting_index(unsigned int order, unsigned int migratetype) @@ -142,6 +184,10 @@ static inline void page_reporting_reset_zone(struct zone *zone) { } +static inline void page_reporting_notify_free(struct zone *zone, int order) +{ +} + static inline void page_reporting_free_area_release(struct zone *zone, unsigned int order, int mt) { From patchwork Wed Sep 18 17:53:05 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Duyck X-Patchwork-Id: 11151101 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 5A9FD912 for ; Wed, 18 Sep 2019 17:54:01 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 37951207FC for ; Wed, 18 Sep 2019 17:54:01 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="cqAAM1ml"; dkim=fail reason="signature verification failed" (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="oBnQ2jVN" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 37951207FC Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:To:From:Subject:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=9ms9MYiPtvBigKwFLrFCaBkI1b4dyYKUh1u6LeHMJbU=; b=cqAAM1ml8AMF2A sqI0KwhAQ4KTpc1brK4rSY/Xmrmo3K8FvPiruH/IgzYQCUvAS4gYfPrCnpBCZejgtrWmM+bJtYaOR 6x8i70R4PwurY75GLrmUHyBcBm1ADcBpVma9XRhdH1PVAtW8Ncnz5Hhre1pxGPtfl1CXULU3202sI acwOP7fywsbTM2zQoNYuLpKHvt5CXUYy9dupCqCQAqnCsQt/tmEK421HwYLjVBZQq+XTMlOT+5dRp tK2fapmVgKE8xEwpq4IJGAfiMMw/+vZAwFUIAt+lQ5zCjWTTCPpdZbyofLQCguRIg8E6UJKPu+Hj4 dpG/TgCp1bJuugztF9lg==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.2 #3 (Red Hat Linux)) id 1iAe9P-0007cm-9e; Wed, 18 Sep 2019 17:53:59 +0000 Received: from mail-oi1-x241.google.com ([2607:f8b0:4864:20::241]) by bombadil.infradead.org with esmtps (Exim 4.92.2 #3 (Red Hat Linux)) id 1iAe8a-0006q9-VT for linux-arm-kernel@lists.infradead.org; Wed, 18 Sep 2019 17:53:10 +0000 Received: by mail-oi1-x241.google.com with SMTP id 7so382768oip.5 for ; Wed, 18 Sep 2019 10:53:08 -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=TbxSoczAuzQWlH6idgeC1LPIVw+1Ea/1DcsLl7A3ATs=; b=oBnQ2jVNymUtlpzhKot6hsQqUxgEcS2+Wppxl37IJ5vWnUDzpQOVCbjCzXqi+pMD/B 9/d5e/KjwjUvfuhB/YZawGYKq2YCSIv5eiiFoWMxEDTohEh/HqnCIK8BCUlXJQK+bcWx lTIHd2cAGkLXBhY4o3cYdtKnC/+U8jZcEvat3yVtMyG4HTqtLHu0j/vxvpbYsqn8D0Pd 3F6w6jGYi9FX9W/9bPjzaGszHWkOrQbUc2vLLQaVBG04zvI41UU8cuCUYyxR9HCoMc36 /M8rqm7rT+FGb20S7RPlbNWi0rZFo91eQCBIHFdH6HZZC3cWeNY2l7PXp0NSneQAiXj4 gcBg== 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=TbxSoczAuzQWlH6idgeC1LPIVw+1Ea/1DcsLl7A3ATs=; b=oRCeQrYLUs1lyjoyxitXehfVDGqTrcluRX2CBRg519cuZ1P5so+KARK+UdsNInAEBl c5u6CAIVTDCiDTGJ+PGWJg30+lPFVkthaw4A26BJmHyzUk9747oFoW4IDKV0LEeWJtW5 4+GiQuopCmnJavcux1W+MpU0WxJilqX6ePn0yEijqZF0tBdw2pMpI0YU4HO7j6tTVUD4 cbAG7qPD97gGac5CqRHnpoJyw1yLC8TpZb9Nzh1hd9aQK0/ShVqygx0rIh4az6n1BN+n CHiwWEhxfzsH11WJn4mHa86wYnZiCtOtOhLdeAH696xtmAhqxGaKLjeI+mfL4iPJsSI7 qc8A== X-Gm-Message-State: APjAAAWW1IqoAydRIZkLuUalV/fUsNM7JqCDdRtKl79hVJZs2ZAY17pt o63DqF1iD3bm8fVfbNB4fiY= X-Google-Smtp-Source: APXvYqyphG7ufZuHFK93raK3ouPQlCP9yyxW6Shrp2cdGc2jcqnuHjGAcaUeE5X6UXUakwcIPv1r5w== X-Received: by 2002:aca:c088:: with SMTP id q130mr3257073oif.54.1568829188183; Wed, 18 Sep 2019 10:53:08 -0700 (PDT) Received: from localhost.localdomain ([2001:470:b:9c3:9e5c:8eff:fe4f:f2d0]) by smtp.gmail.com with ESMTPSA id u12sm1838437oiv.29.2019.09.18.10.53.06 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 18 Sep 2019 10:53:07 -0700 (PDT) Subject: [PATCH v10 5/6] virtio-balloon: Pull page poisoning config out of free page hinting From: Alexander Duyck To: virtio-dev@lists.oasis-open.org, kvm@vger.kernel.org, mst@redhat.com, david@redhat.com, dave.hansen@intel.com, linux-kernel@vger.kernel.org, willy@infradead.org, mhocko@kernel.org, linux-mm@kvack.org, vbabka@suse.cz, akpm@linux-foundation.org, mgorman@techsingularity.net, linux-arm-kernel@lists.infradead.org, osalvador@suse.de Date: Wed, 18 Sep 2019 10:53:05 -0700 Message-ID: <20190918175305.23474.34783.stgit@localhost.localdomain> In-Reply-To: <20190918175109.23474.67039.stgit@localhost.localdomain> References: <20190918175109.23474.67039.stgit@localhost.localdomain> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20190918_105309_144244_F752704E X-CRM114-Status: GOOD ( 14.62 ) X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.2 on bombadil.infradead.org summary: Content analysis details: (-0.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [2607:f8b0:4864:20:0:0:0:241 listed in] [list.dnswl.org] 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider (alexander.duyck[at]gmail.com) -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , 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, nitesh@redhat.com, pbonzini@redhat.com, dan.j.williams@intel.com, alexander.h.duyck@linux.intel.com Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org From: Alexander Duyck Currently the page poisoning setting wasn't being enabled unless free page hinting was enabled. However we will need the page poisoning tracking logic as well for unused page reporting. As such pull it out and make it a separate bit of config in the probe function. In addition we can actually wrap the code in a check for NO_SANITY. If we don't care what is actually in the page we can just default to 0 and leave it there. Reviewed-by: David Hildenbrand Signed-off-by: Alexander Duyck --- drivers/virtio/virtio_balloon.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index 226fbb995fb0..501a8d0ebf86 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c @@ -842,7 +842,6 @@ static int virtio_balloon_register_shrinker(struct virtio_balloon *vb) static int virtballoon_probe(struct virtio_device *vdev) { struct virtio_balloon *vb; - __u32 poison_val; int err; if (!vdev->config->get) { @@ -909,11 +908,18 @@ static int virtballoon_probe(struct virtio_device *vdev) VIRTIO_BALLOON_CMD_ID_STOP); spin_lock_init(&vb->free_page_list_lock); INIT_LIST_HEAD(&vb->free_page_list); - if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_PAGE_POISON)) { - memset(&poison_val, PAGE_POISON, sizeof(poison_val)); - virtio_cwrite(vb->vdev, struct virtio_balloon_config, - poison_val, &poison_val); - } + } + if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_PAGE_POISON)) { + __u32 poison_val; + + /* + * Let the hypervisor know that we are expecting a + * specific value to be written back in unused pages. + */ + memset(&poison_val, PAGE_POISON, sizeof(poison_val)); + + virtio_cwrite(vb->vdev, struct virtio_balloon_config, + poison_val, &poison_val); } /* * We continue to use VIRTIO_BALLOON_F_DEFLATE_ON_OOM to decide if a @@ -1014,7 +1020,9 @@ static int virtballoon_restore(struct virtio_device *vdev) static int virtballoon_validate(struct virtio_device *vdev) { - if (!page_poisoning_enabled()) + /* Tell the host whether we care about poisoned pages. */ + if (IS_ENABLED(CONFIG_PAGE_POISONING_NO_SANITY) || + !page_poisoning_enabled()) __virtio_clear_bit(vdev, VIRTIO_BALLOON_F_PAGE_POISON); __virtio_clear_bit(vdev, VIRTIO_F_IOMMU_PLATFORM); From patchwork Wed Sep 18 17:53:13 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Duyck X-Patchwork-Id: 11151107 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E79C7912 for ; Wed, 18 Sep 2019 17:54:17 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id C1321207FC for ; Wed, 18 Sep 2019 17:54:17 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="A42tMcvz"; dkim=fail reason="signature verification failed" (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="e2N1Rvh5" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org C1321207FC Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:To:From:Subject:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=ctR1xULpEAn5/pEVjMwZJfpoYuKnqVAIyCxy3hnNm+E=; b=A42tMcvzE4mxm6 h81cJHTQkys1oY0erWz4enkStT3DnC5EIgSghSKhoVWPAZlJ5J7+svR4VkwDCweBpz8863JAj/TUI ebaDV1AIC6iJvLhY2UH1WLSon34ZHjRVpPXKJwQ97JNo8JtnPHSnPsv3FMmElEh9CAdazEG/GhPn5 vERybia3c6IuioGfs6WS4n17oIqKWy1KAqDaYcTqkcbPQcdECvN0DNA1NBrnMPZJG9us/sxPC4HfA Z3lwswr1t7+diVtTHsbuOOInTaP+GOBxOvCLwU1V9h8vExR8KwYf8dX7sj6HDDB/EGiCGM4sOucxS s5DI5b8kKCCf+E1bjGmg==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.2 #3 (Red Hat Linux)) id 1iAe9h-0007t7-6o; Wed, 18 Sep 2019 17:54:17 +0000 Received: from mail-oi1-x243.google.com ([2607:f8b0:4864:20::243]) by bombadil.infradead.org with esmtps (Exim 4.92.2 #3 (Red Hat Linux)) id 1iAe8i-0006yJ-N5 for linux-arm-kernel@lists.infradead.org; Wed, 18 Sep 2019 17:53:19 +0000 Received: by mail-oi1-x243.google.com with SMTP id w144so379486oia.6 for ; Wed, 18 Sep 2019 10:53:16 -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=mn811CvvWzN3jT4Al3MUAyM7QLy5vWDmmwUaNApsqLI=; b=e2N1Rvh5CnsPgzn73O1X7IG0/k5i/gprW74Cr40N8g8VvkyHwsmD5WZJwQFqTXx+F2 nrdfghedGt/mhBCk01ksi/hGINb8JhKoM/BwZsEDjH7N74lieYdcKc70HfdFdSlqtGmz Bl+qlAoLHAEmR2GjeDIsIfsjyK14P+RAodNh6K5IH31cm97Fc7aoBpS2I76Yi07bWgU8 GAN5l9jgxhwI0QLv1moHEafKVjak+A6AkKdiPgBrMjdbdWAWXuBRG3Ndcoi6/7gm+vZE uAVo9KbW7bN9R10h72Y6KFZnt0TvgdDdFmP9mLHSAVTYJpbFUmzml0trz8f27cvjaCr4 RmrQ== 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=mn811CvvWzN3jT4Al3MUAyM7QLy5vWDmmwUaNApsqLI=; b=ObiKbTY9fIRIZ0jNQbjFbbbTO3pCZ5bWpEs0/IQ2MZ3imokXYe0jo4jHlSvs7eiqXG MgH/h6O016DAiIFssXiPrtvJkO913uEHmdi+qhePRO/+X/VUhITEWAfgc1Ql5M4CSvCw MyxsHl5gP+2xFSPpbE7COy0ZWmUcGc5xXgIgyu751oDtT1dgkWvC0EA7NjY8vufbFP8y JjoqE+C/uZcR8mCJtcb962nHhfidXqsmC1xsBbJgK9ULMGEcV6zyILWMCeM3NUQ8Y3mV bP+QNDrnunQ49rhRtQYya0l/unCIAldbSHNc623i4J3xadwEW04FMqvmITMw2KHAbnXQ a78Q== X-Gm-Message-State: APjAAAWUPqNuM4utxyGVb8uWcijE4btynvFshoC1Deip2lNSaOiBbdjx vNDNSSpFrIlCr0YUVsEJjBg= X-Google-Smtp-Source: APXvYqx3pqlRwoKEwFCPayUZe5KAwkQRmf4ve3cVECk4baQjoVPyz0JyAqi+dhto/PVdkL4HCzFoLQ== X-Received: by 2002:aca:7509:: with SMTP id q9mr2948237oic.111.1568829195987; Wed, 18 Sep 2019 10:53:15 -0700 (PDT) Received: from localhost.localdomain ([2001:470:b:9c3:9e5c:8eff:fe4f:f2d0]) by smtp.gmail.com with ESMTPSA id p7sm1952343oif.8.2019.09.18.10.53.13 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 18 Sep 2019 10:53:15 -0700 (PDT) Subject: [PATCH v10 6/6] virtio-balloon: Add support for providing unused page reports to host From: Alexander Duyck To: virtio-dev@lists.oasis-open.org, kvm@vger.kernel.org, mst@redhat.com, david@redhat.com, dave.hansen@intel.com, linux-kernel@vger.kernel.org, willy@infradead.org, mhocko@kernel.org, linux-mm@kvack.org, vbabka@suse.cz, akpm@linux-foundation.org, mgorman@techsingularity.net, linux-arm-kernel@lists.infradead.org, osalvador@suse.de Date: Wed, 18 Sep 2019 10:53:13 -0700 Message-ID: <20190918175313.23474.89510.stgit@localhost.localdomain> In-Reply-To: <20190918175109.23474.67039.stgit@localhost.localdomain> References: <20190918175109.23474.67039.stgit@localhost.localdomain> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20190918_105316_817621_B4AC4175 X-CRM114-Status: GOOD ( 20.27 ) X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.2 on bombadil.infradead.org summary: Content analysis details: (-0.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [2607:f8b0:4864:20:0:0:0:243 listed in] [list.dnswl.org] 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider (alexander.duyck[at]gmail.com) -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , 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, nitesh@redhat.com, pbonzini@redhat.com, dan.j.williams@intel.com, alexander.h.duyck@linux.intel.com Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org From: Alexander Duyck Add support for the page reporting feature provided by virtio-balloon. Reporting 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 | 65 +++++++++++++++++++++++++++++++++++ include/uapi/linux/virtio_balloon.h | 1 + 3 files changed, 67 insertions(+) diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig index 078615cf2afc..4b2dd8259ff5 100644 --- a/drivers/virtio/Kconfig +++ b/drivers/virtio/Kconfig @@ -58,6 +58,7 @@ config VIRTIO_BALLOON tristate "Virtio balloon driver" depends on VIRTIO select MEMORY_BALLOON + select PAGE_REPORTING ---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 501a8d0ebf86..40a6dcaf368f 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c @@ -19,6 +19,7 @@ #include #include #include +#include /* * Balloon device works in 4K page units. So each page is pointed to by @@ -37,6 +38,9 @@ #define VIRTIO_BALLOON_FREE_PAGE_SIZE \ (1 << (VIRTIO_BALLOON_FREE_PAGE_ORDER + PAGE_SHIFT)) +/* limit on the number of pages that can be on the reporting vq */ +#define VIRTIO_BALLOON_VRING_HINTS_MAX 16 + #ifdef CONFIG_BALLOON_COMPACTION static struct vfsmount *balloon_mnt; #endif @@ -46,6 +50,7 @@ enum virtio_balloon_vq { VIRTIO_BALLOON_VQ_DEFLATE, VIRTIO_BALLOON_VQ_STATS, VIRTIO_BALLOON_VQ_FREE_PAGE, + VIRTIO_BALLOON_VQ_REPORTING, VIRTIO_BALLOON_VQ_MAX }; @@ -113,6 +118,10 @@ struct virtio_balloon { /* To register a shrinker to shrink memory upon memory pressure */ struct shrinker shrinker; + + /* Unused page reporting device */ + struct virtqueue *reporting_vq; + struct page_reporting_dev_info ph_dev_info; }; static struct virtio_device_id id_table[] = { @@ -152,6 +161,32 @@ static void tell_host(struct virtio_balloon *vb, struct virtqueue *vq) } +void virtballoon_unused_page_report(struct page_reporting_dev_info *ph_dev_info, + unsigned int nents) +{ + struct virtio_balloon *vb = + container_of(ph_dev_info, struct virtio_balloon, ph_dev_info); + struct virtqueue *vq = vb->reporting_vq; + unsigned int unused, err; + + /* We should always be able to add these buffers to an empty queue. */ + err = virtqueue_add_inbuf(vq, ph_dev_info->sg, nents, vb, + GFP_NOWAIT | __GFP_NOWARN); + + /* + * In the extremely unlikely case that something has changed and we + * are able to trigger an error we will simply display a warning + * and exit without actually processing the pages. + */ + if (WARN_ON(err)) + return; + + virtqueue_kick(vq); + + /* When host has read buffer, this completes via balloon_ack */ + wait_event(vb->acked, virtqueue_get_buf(vq, &unused)); +} + static void set_page_pfns(struct virtio_balloon *vb, __virtio32 pfns[], struct page *page) { @@ -476,6 +511,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_REPORTING] = NULL; if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_STATS_VQ)) { names[VIRTIO_BALLOON_VQ_STATS] = "stats"; @@ -487,11 +523,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_REPORTING)) { + names[VIRTIO_BALLOON_VQ_REPORTING] = "reporting_vq"; + callbacks[VIRTIO_BALLOON_VQ_REPORTING] = 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_REPORTING)) + vb->reporting_vq = vqs[VIRTIO_BALLOON_VQ_REPORTING]; + 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)) { @@ -930,12 +974,30 @@ static int virtballoon_probe(struct virtio_device *vdev) if (err) goto out_del_balloon_wq; } + + vb->ph_dev_info.report = virtballoon_unused_page_report; + if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_REPORTING)) { + unsigned int capacity; + + capacity = min_t(unsigned int, + virtqueue_get_vring_size(vb->reporting_vq), + VIRTIO_BALLOON_VRING_HINTS_MAX); + vb->ph_dev_info.capacity = capacity; + + err = page_reporting_register(&vb->ph_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); @@ -964,6 +1026,8 @@ static void virtballoon_remove(struct virtio_device *vdev) { struct virtio_balloon *vb = vdev->priv; + if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_REPORTING)) + page_reporting_unregister(&vb->ph_dev_info); if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM)) virtio_balloon_unregister_shrinker(vb); spin_lock_irq(&vb->stop_update_lock); @@ -1035,6 +1099,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_REPORTING, }; 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..19974392d324 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_REPORTING 5 /* Page reporting virtqueue */ /* Size of a PFN in the balloon interface. */ #define VIRTIO_BALLOON_PFN_SHIFT 12