Received: by 10.223.176.46 with SMTP id f43csp159032wra; Thu, 25 Jan 2018 19:27:26 -0800 (PST) X-Google-Smtp-Source: AH8x225DJbotFWqpIK4NlYuKkq/w8rX6iSwB0yMTQ+qVNyfCBovf/9ZVpP3xYdmRYpnL3FRJMwfs X-Received: by 2002:a17:902:bb88:: with SMTP id m8-v6mr12921476pls.432.1516937246501; Thu, 25 Jan 2018 19:27:26 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1516937246; cv=none; d=google.com; s=arc-20160816; b=EJd2rKQ38/y/EnCJG9dG7Ivq7qiQtMAXVk1zpI/wWQERwL09JF1tEDN942te7as6dZ kYtYq/OjKqfqdylYeLalGgjNMZsohCXusGnX63wsUKq441qMCiDYwP0EHRMeJVH8aaDw BcQxDtLW9QCa7wl0/WOyLQUNSZIqZ0AE7ioAZmyxLdtNrdKfMpWILfXY0WKsdkvsfLVD RjaAghM5VvTlC3dgHPcLJZ7fxC/jeSesjnplLm+6vmSDSF8aU6kbg2MBseVR+SsuzCvL NNhqyCtbEB/Z7oXmf2paUZYWbakpNXfACdQKe45XSbDakmDPvSZ01yfGPE8pRz5yL5Xx crcw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:in-reply-to :references:subject:cc:to:mime-version:user-agent:from:date :message-id:arc-authentication-results; bh=uCB2wudVDSeUFfjGjSlc5aqoc33Z3kAcz+zZl9h4VRI=; b=D0193eV2hlH7M0N0WGQBh92nL7GhrR7My53giEq4SIa6Dj61zzjjAqnBBP8+qU7SEn 6pTa0t3ePG4WR/raUkC9NaQvTtEW7XXRhoQ7K2dLRP+6jCii6cjN4dWhheWmdZRMbLo+ lkuLnFAeYpz4FMH5WhX8I14ARQ3jr1eO97Hno7R4u9pU0fBvrCuv/NG68OzSPQ0jMtkX ZpKUz8ufaliIxKEycp+RBK/TUFFfk57w2Y4XhJ3kzaV/+MzqkCyJEIOZ6yTJlgVxStOx xJzFbG66cjpZX1knVuIBcp2Up4mG7kyWFsZpAW7pqdjUPiFJ4LRTzos/X29j9O7Z8P4s cyFw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id n12-v6si3043460plk.425.2018.01.25.19.27.12; Thu, 25 Jan 2018 19:27:26 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751458AbeAZD0r (ORCPT + 99 others); Thu, 25 Jan 2018 22:26:47 -0500 Received: from mga09.intel.com ([134.134.136.24]:9289 "EHLO mga09.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751174AbeAZD0p (ORCPT ); Thu, 25 Jan 2018 22:26:45 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga102.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 25 Jan 2018 19:26:44 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.46,414,1511856000"; d="scan'208";a="25572720" Received: from unknown (HELO [10.239.13.97]) ([10.239.13.97]) by fmsmga001.fm.intel.com with ESMTP; 25 Jan 2018 19:26:42 -0800 Message-ID: <5A6AA08B.2080508@intel.com> Date: Fri, 26 Jan 2018 11:29:15 +0800 From: Wei Wang User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.7.0 MIME-Version: 1.0 To: "Michael S. Tsirkin" CC: virtio-dev@lists.oasis-open.org, linux-kernel@vger.kernel.org, virtualization@lists.linux-foundation.org, kvm@vger.kernel.org, linux-mm@kvack.org, mhocko@kernel.org, akpm@linux-foundation.org, pbonzini@redhat.com, liliang.opensource@gmail.com, yang.zhang.wz@gmail.com, quan.xu0@gmail.com, nilal@redhat.com, riel@redhat.com Subject: Re: [PATCH v24 1/2] mm: support reporting free page blocks References: <1516790562-37889-1-git-send-email-wei.w.wang@intel.com> <1516790562-37889-2-git-send-email-wei.w.wang@intel.com> <20180125152933-mutt-send-email-mst@kernel.org> In-Reply-To: <20180125152933-mutt-send-email-mst@kernel.org> Content-Type: text/plain; charset=windows-1252; format=flowed Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On 01/25/2018 09:41 PM, Michael S. Tsirkin wrote: > On Wed, Jan 24, 2018 at 06:42:41PM +0800, Wei Wang wrote: >> This patch adds support to walk through the free page blocks in the >> system and report them via a callback function. Some page blocks may >> leave the free list after zone->lock is released, so it is the caller's >> responsibility to either detect or prevent the use of such pages. >> >> One use example of this patch is to accelerate live migration by skipping >> the transfer of free pages reported from the guest. A popular method used >> by the hypervisor to track which part of memory is written during live >> migration is to write-protect all the guest memory. So, those pages that >> are reported as free pages but are written after the report function >> returns will be captured by the hypervisor, and they will be added to the >> next round of memory transfer. >> >> Signed-off-by: Wei Wang >> Signed-off-by: Liang Li >> Cc: Michal Hocko >> Cc: Michael S. Tsirkin >> Acked-by: Michal Hocko >> --- >> include/linux/mm.h | 6 ++++ >> mm/page_alloc.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ >> 2 files changed, 97 insertions(+) >> >> diff --git a/include/linux/mm.h b/include/linux/mm.h >> index ea818ff..b3077dd 100644 >> --- a/include/linux/mm.h >> +++ b/include/linux/mm.h >> @@ -1938,6 +1938,12 @@ extern void free_area_init_node(int nid, unsigned long * zones_size, >> unsigned long zone_start_pfn, unsigned long *zholes_size); >> extern void free_initmem(void); >> >> +extern void walk_free_mem_block(void *opaque, >> + int min_order, >> + bool (*report_pfn_range)(void *opaque, >> + unsigned long pfn, >> + unsigned long num)); >> + >> /* >> * Free reserved pages within range [PAGE_ALIGN(start), end & PAGE_MASK) >> * into the buddy system. The freed pages will be poisoned with pattern >> diff --git a/mm/page_alloc.c b/mm/page_alloc.c >> index 76c9688..705de22 100644 >> --- a/mm/page_alloc.c >> +++ b/mm/page_alloc.c >> @@ -4899,6 +4899,97 @@ void show_free_areas(unsigned int filter, nodemask_t *nodemask) >> show_swap_cache_info(); >> } >> >> +/* >> + * Walk through a free page list and report the found pfn range via the >> + * callback. >> + * >> + * Return false if the callback requests to stop reporting. Otherwise, >> + * return true. >> + */ >> +static bool walk_free_page_list(void *opaque, >> + struct zone *zone, >> + int order, >> + enum migratetype mt, >> + bool (*report_pfn_range)(void *, >> + unsigned long, >> + unsigned long)) >> +{ >> + struct page *page; >> + struct list_head *list; >> + unsigned long pfn, flags; >> + bool ret; >> + >> + spin_lock_irqsave(&zone->lock, flags); >> + list = &zone->free_area[order].free_list[mt]; >> + list_for_each_entry(page, list, lru) { >> + pfn = page_to_pfn(page); >> + ret = report_pfn_range(opaque, pfn, 1 << order); >> + if (!ret) >> + break; >> + } >> + spin_unlock_irqrestore(&zone->lock, flags); >> + >> + return ret; >> +} > There are two issues with this API. One is that it is not > restarteable: if you return false, you start from the > beginning. So no way to drop lock, do something slow > and then proceed. > > Another is that you are using it to report free page hints. Presumably > the point is to drop these pages - keeping them near head of the list > and reusing the reported ones will just make everything slower > invalidating the hint. > > How about rotating these pages towards the end of the list? > Probably not on each call, callect reported pages and then > move them to tail when we exit. I'm not sure how this would help. For example, we have a list of 2M free page blocks: A-->B-->C-->D-->E-->F-->G--H After reporting A and B, and put them to the end and exit, when the caller comes back, 1) if the list remains unchanged, then it will be C-->D-->E-->F-->G-->H-->A-->B 2) If worse, all the blocks have been split into smaller blocks and used after the caller comes back. where could we continue? The reason to think about "restart" is the worry about the virtqueue is full, right? But we've agreed that losing some hints to report isn't important, and in practice, the virtqueue won't be full as the host side is faster. I'm concerned that actions on the free list may cause more controversy though it might be safe to do from some aspect, and would be hard to end debating. If possible, we could go with the most prudent approach for now, and have more discussions in future improvement patches. What would you think? > > >> + >> +/** >> + * walk_free_mem_block - Walk through the free page blocks in the system >> + * @opaque: the context passed from the caller >> + * @min_order: the minimum order of free lists to check >> + * @report_pfn_range: the callback to report the pfn range of the free pages >> + * >> + * If the callback returns false, stop iterating the list of free page blocks. >> + * Otherwise, continue to report. >> + * >> + * Please note that there are no locking guarantees for the callback and >> + * that the reported pfn range might be freed or disappear after the >> + * callback returns so the caller has to be very careful how it is used. >> + * >> + * The callback itself must not sleep or perform any operations which would >> + * require any memory allocations directly (not even GFP_NOWAIT/GFP_ATOMIC) >> + * or via any lock dependency. It is generally advisable to implement >> + * the callback as simple as possible and defer any heavy lifting to a >> + * different context. >> + * >> + * There is no guarantee that each free range will be reported only once >> + * during one walk_free_mem_block invocation. >> + * >> + * pfn_to_page on the given range is strongly discouraged and if there is >> + * an absolute need for that make sure to contact MM people to discuss >> + * potential problems. >> + * >> + * The function itself might sleep so it cannot be called from atomic >> + * contexts. >> + * >> + * In general low orders tend to be very volatile and so it makes more >> + * sense to query larger ones first for various optimizations which like >> + * ballooning etc... This will reduce the overhead as well. >> + */ >> +void walk_free_mem_block(void *opaque, >> + int min_order, >> + bool (*report_pfn_range)(void *opaque, >> + unsigned long pfn, >> + unsigned long num)) >> +{ >> + struct zone *zone; >> + int order; >> + enum migratetype mt; >> + bool ret; >> + >> + for_each_populated_zone(zone) { >> + for (order = MAX_ORDER - 1; order >= min_order; order--) { >> + for (mt = 0; mt < MIGRATE_TYPES; mt++) { >> + ret = walk_free_page_list(opaque, zone, >> + order, mt, >> + report_pfn_range); >> + if (!ret) >> + return; >> + } >> + } >> + } >> +} >> +EXPORT_SYMBOL_GPL(walk_free_mem_block); >> + > I think callers need a way to > 1. distinguish between completion and exit on error The first one here has actually been achieved by v25, where walk_free_mem_block returns 0 on completing the reporting, or a non-zero value which is returned from the callback. So the caller will detect errors via letting the callback to return something. Best, Wei