From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=3.0 tests=DKIMWL_WL_HIGH,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH, MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id DC6B5C54E4A for ; Thu, 7 May 2020 10:33:08 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id BC735207DD for ; Thu, 7 May 2020 10:33:08 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="hxVbWKj7" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727104AbgEGKdH (ORCPT ); Thu, 7 May 2020 06:33:07 -0400 Received: from us-smtp-1.mimecast.com ([207.211.31.81]:30246 "EHLO us-smtp-delivery-1.mimecast.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726877AbgEGKc6 (ORCPT ); Thu, 7 May 2020 06:32:58 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1588847577; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=WsWC5kNCuNT2tK5daPiXWaoy0z2HcrZA36JQLbaWqFQ=; b=hxVbWKj7dxrsGUaaYh7yE6LCjACV/NZXQCGpCDPuzxhdK17D7swILRvFUMNmN8new7ZmBD +W3EA5Vob66BlFaySRfkqUbF4miIDOhuTaMUjr26vmQa+3JKc6fgxi1/qe6J1epRWMMJ9+ aW4FgxZI51TrPjgXd+N3Dko3H7pXuGs= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-401-Y-DGf1eNMO2RvRtpmRn8vw-1; Thu, 07 May 2020 06:32:53 -0400 X-MC-Unique: Y-DGf1eNMO2RvRtpmRn8vw-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 370CB1005510; Thu, 7 May 2020 10:32:51 +0000 (UTC) Received: from t480s.redhat.com (ovpn-113-245.ams2.redhat.com [10.36.113.245]) by smtp.corp.redhat.com (Postfix) with ESMTP id 7A6265D9C5; Thu, 7 May 2020 10:32:42 +0000 (UTC) From: David Hildenbrand To: linux-kernel@vger.kernel.org Cc: linux-mm@kvack.org, virtio-dev@lists.oasis-open.org, virtualization@lists.linux-foundation.org, kvm@vger.kernel.org, Michal Hocko , Andrew Morton , "Michael S . Tsirkin" , David Hildenbrand , Pankaj Gupta , Jason Wang , Oscar Salvador , Igor Mammedov , Dave Young , Dan Williams , Pavel Tatashin , Stefan Hajnoczi , Vlastimil Babka Subject: [PATCH v3 06/15] virtio-mem: Allow to offline partially unplugged memory blocks Date: Thu, 7 May 2020 12:31:10 +0200 Message-Id: <20200507103119.11219-7-david@redhat.com> In-Reply-To: <20200507103119.11219-1-david@redhat.com> References: <20200507103119.11219-1-david@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Dropping the reference count of PageOffline() pages during MEM_GOING_ONLINE allows offlining code to skip them. However, we also have to clear PG_reserved, because PG_reserved pages get detected as unmovable right away. Take care of restoring the reference count when offlining is canceled. Clarify why we don't have to perform any action when unloading the driver. Also, let's add a warning if anybody is still holding a reference to unplugged pages when offlining. Tested-by: Pankaj Gupta Cc: "Michael S. Tsirkin" Cc: Jason Wang Cc: Oscar Salvador Cc: Michal Hocko Cc: Igor Mammedov Cc: Dave Young Cc: Andrew Morton Cc: Dan Williams Cc: Pavel Tatashin Cc: Stefan Hajnoczi Cc: Vlastimil Babka Signed-off-by: David Hildenbrand --- drivers/virtio/virtio_mem.c | 68 ++++++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/drivers/virtio/virtio_mem.c b/drivers/virtio/virtio_mem.c index 74f0d3cb1d22..b0b41c73ce89 100644 --- a/drivers/virtio/virtio_mem.c +++ b/drivers/virtio/virtio_mem.c @@ -572,6 +572,57 @@ static void virtio_mem_notify_online(struct virtio_mem *vm, unsigned long mb_id, virtio_mem_retry(vm); } +static void virtio_mem_notify_going_offline(struct virtio_mem *vm, + unsigned long mb_id) +{ + const unsigned long nr_pages = PFN_DOWN(vm->subblock_size); + struct page *page; + unsigned long pfn; + int sb_id, i; + + for (sb_id = 0; sb_id < vm->nb_sb_per_mb; sb_id++) { + if (virtio_mem_mb_test_sb_plugged(vm, mb_id, sb_id, 1)) + continue; + /* + * Drop our reference to the pages so the memory can get + * offlined and add the unplugged pages to the managed + * page counters (so offlining code can correctly subtract + * them again). + */ + pfn = PFN_DOWN(virtio_mem_mb_id_to_phys(mb_id) + + sb_id * vm->subblock_size); + adjust_managed_page_count(pfn_to_page(pfn), nr_pages); + for (i = 0; i < nr_pages; i++) { + page = pfn_to_page(pfn + i); + if (WARN_ON(!page_ref_dec_and_test(page))) + dump_page(page, "unplugged page referenced"); + } + } +} + +static void virtio_mem_notify_cancel_offline(struct virtio_mem *vm, + unsigned long mb_id) +{ + const unsigned long nr_pages = PFN_DOWN(vm->subblock_size); + unsigned long pfn; + int sb_id, i; + + for (sb_id = 0; sb_id < vm->nb_sb_per_mb; sb_id++) { + if (virtio_mem_mb_test_sb_plugged(vm, mb_id, sb_id, 1)) + continue; + /* + * Get the reference we dropped when going offline and + * subtract the unplugged pages from the managed page + * counters. + */ + pfn = PFN_DOWN(virtio_mem_mb_id_to_phys(mb_id) + + sb_id * vm->subblock_size); + adjust_managed_page_count(pfn_to_page(pfn), -nr_pages); + for (i = 0; i < nr_pages; i++) + page_ref_inc(pfn_to_page(pfn + i)); + } +} + /* * This callback will either be called synchronously from add_memory() or * asynchronously (e.g., triggered via user space). We have to be careful @@ -618,6 +669,7 @@ static int virtio_mem_memory_notifier_cb(struct notifier_block *nb, break; } vm->hotplug_active = true; + virtio_mem_notify_going_offline(vm, mb_id); break; case MEM_GOING_ONLINE: mutex_lock(&vm->hotplug_mutex); @@ -642,6 +694,12 @@ static int virtio_mem_memory_notifier_cb(struct notifier_block *nb, mutex_unlock(&vm->hotplug_mutex); break; case MEM_CANCEL_OFFLINE: + if (!vm->hotplug_active) + break; + virtio_mem_notify_cancel_offline(vm, mb_id); + vm->hotplug_active = false; + mutex_unlock(&vm->hotplug_mutex); + break; case MEM_CANCEL_ONLINE: if (!vm->hotplug_active) break; @@ -668,8 +726,11 @@ static void virtio_mem_set_fake_offline(unsigned long pfn, struct page *page = pfn_to_page(pfn); __SetPageOffline(page); - if (!onlined) + if (!onlined) { SetPageDirty(page); + /* FIXME: remove after cleanups */ + ClearPageReserved(page); + } } } @@ -1722,6 +1783,11 @@ static void virtio_mem_remove(struct virtio_device *vdev) BUG_ON(rc); virtio_mem_mb_set_state(vm, mb_id, VIRTIO_MEM_MB_STATE_UNUSED); } + /* + * After we unregistered our callbacks, user space can no longer + * offline partially plugged online memory blocks. No need to worry + * about them. + */ /* unregister callbacks */ unregister_virtio_mem_device(vm); -- 2.25.3 From mboxrd@z Thu Jan 1 00:00:00 1970 From: David Hildenbrand Subject: [PATCH v3 06/15] virtio-mem: Allow to offline partially unplugged memory blocks Date: Thu, 7 May 2020 12:31:10 +0200 Message-ID: <20200507103119.11219-7-david@redhat.com> References: <20200507103119.11219-1-david@redhat.com> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Return-path: In-Reply-To: <20200507103119.11219-1-david@redhat.com> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: virtualization-bounces@lists.linux-foundation.org Sender: "Virtualization" To: linux-kernel@vger.kernel.org Cc: virtio-dev@lists.oasis-open.org, Pavel Tatashin , kvm@vger.kernel.org, "Michael S . Tsirkin" , Michal Hocko , linux-mm@kvack.org, Stefan Hajnoczi , Pankaj Gupta , Igor Mammedov , Andrew Morton , virtualization@lists.linux-foundation.org, Dave Young , Dan Williams , Vlastimil Babka , Oscar Salvador List-Id: virtualization@lists.linuxfoundation.org Dropping the reference count of PageOffline() pages during MEM_GOING_ONLINE allows offlining code to skip them. However, we also have to clear PG_reserved, because PG_reserved pages get detected as unmovable right away. Take care of restoring the reference count when offlining is canceled. Clarify why we don't have to perform any action when unloading the driver. Also, let's add a warning if anybody is still holding a reference to unplugged pages when offlining. Tested-by: Pankaj Gupta Cc: "Michael S. Tsirkin" Cc: Jason Wang Cc: Oscar Salvador Cc: Michal Hocko Cc: Igor Mammedov Cc: Dave Young Cc: Andrew Morton Cc: Dan Williams Cc: Pavel Tatashin Cc: Stefan Hajnoczi Cc: Vlastimil Babka Signed-off-by: David Hildenbrand --- drivers/virtio/virtio_mem.c | 68 ++++++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/drivers/virtio/virtio_mem.c b/drivers/virtio/virtio_mem.c index 74f0d3cb1d22..b0b41c73ce89 100644 --- a/drivers/virtio/virtio_mem.c +++ b/drivers/virtio/virtio_mem.c @@ -572,6 +572,57 @@ static void virtio_mem_notify_online(struct virtio_mem *vm, unsigned long mb_id, virtio_mem_retry(vm); } +static void virtio_mem_notify_going_offline(struct virtio_mem *vm, + unsigned long mb_id) +{ + const unsigned long nr_pages = PFN_DOWN(vm->subblock_size); + struct page *page; + unsigned long pfn; + int sb_id, i; + + for (sb_id = 0; sb_id < vm->nb_sb_per_mb; sb_id++) { + if (virtio_mem_mb_test_sb_plugged(vm, mb_id, sb_id, 1)) + continue; + /* + * Drop our reference to the pages so the memory can get + * offlined and add the unplugged pages to the managed + * page counters (so offlining code can correctly subtract + * them again). + */ + pfn = PFN_DOWN(virtio_mem_mb_id_to_phys(mb_id) + + sb_id * vm->subblock_size); + adjust_managed_page_count(pfn_to_page(pfn), nr_pages); + for (i = 0; i < nr_pages; i++) { + page = pfn_to_page(pfn + i); + if (WARN_ON(!page_ref_dec_and_test(page))) + dump_page(page, "unplugged page referenced"); + } + } +} + +static void virtio_mem_notify_cancel_offline(struct virtio_mem *vm, + unsigned long mb_id) +{ + const unsigned long nr_pages = PFN_DOWN(vm->subblock_size); + unsigned long pfn; + int sb_id, i; + + for (sb_id = 0; sb_id < vm->nb_sb_per_mb; sb_id++) { + if (virtio_mem_mb_test_sb_plugged(vm, mb_id, sb_id, 1)) + continue; + /* + * Get the reference we dropped when going offline and + * subtract the unplugged pages from the managed page + * counters. + */ + pfn = PFN_DOWN(virtio_mem_mb_id_to_phys(mb_id) + + sb_id * vm->subblock_size); + adjust_managed_page_count(pfn_to_page(pfn), -nr_pages); + for (i = 0; i < nr_pages; i++) + page_ref_inc(pfn_to_page(pfn + i)); + } +} + /* * This callback will either be called synchronously from add_memory() or * asynchronously (e.g., triggered via user space). We have to be careful @@ -618,6 +669,7 @@ static int virtio_mem_memory_notifier_cb(struct notifier_block *nb, break; } vm->hotplug_active = true; + virtio_mem_notify_going_offline(vm, mb_id); break; case MEM_GOING_ONLINE: mutex_lock(&vm->hotplug_mutex); @@ -642,6 +694,12 @@ static int virtio_mem_memory_notifier_cb(struct notifier_block *nb, mutex_unlock(&vm->hotplug_mutex); break; case MEM_CANCEL_OFFLINE: + if (!vm->hotplug_active) + break; + virtio_mem_notify_cancel_offline(vm, mb_id); + vm->hotplug_active = false; + mutex_unlock(&vm->hotplug_mutex); + break; case MEM_CANCEL_ONLINE: if (!vm->hotplug_active) break; @@ -668,8 +726,11 @@ static void virtio_mem_set_fake_offline(unsigned long pfn, struct page *page = pfn_to_page(pfn); __SetPageOffline(page); - if (!onlined) + if (!onlined) { SetPageDirty(page); + /* FIXME: remove after cleanups */ + ClearPageReserved(page); + } } } @@ -1722,6 +1783,11 @@ static void virtio_mem_remove(struct virtio_device *vdev) BUG_ON(rc); virtio_mem_mb_set_state(vm, mb_id, VIRTIO_MEM_MB_STATE_UNUSED); } + /* + * After we unregistered our callbacks, user space can no longer + * offline partially plugged online memory blocks. No need to worry + * about them. + */ /* unregister callbacks */ unregister_virtio_mem_device(vm); -- 2.25.3 From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: virtio-dev-return-7245-cohuck=redhat.com@lists.oasis-open.org Sender: List-Post: List-Help: List-Unsubscribe: List-Subscribe: Received: from lists.oasis-open.org (oasis-open.org [10.110.1.242]) by lists.oasis-open.org (Postfix) with ESMTP id 5A8F0985E09 for ; Thu, 7 May 2020 10:32:59 +0000 (UTC) From: David Hildenbrand Date: Thu, 7 May 2020 12:31:10 +0200 Message-Id: <20200507103119.11219-7-david@redhat.com> In-Reply-To: <20200507103119.11219-1-david@redhat.com> References: <20200507103119.11219-1-david@redhat.com> MIME-Version: 1.0 Subject: [virtio-dev] [PATCH v3 06/15] virtio-mem: Allow to offline partially unplugged memory blocks Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: quoted-printable To: linux-kernel@vger.kernel.org Cc: linux-mm@kvack.org, virtio-dev@lists.oasis-open.org, virtualization@lists.linux-foundation.org, kvm@vger.kernel.org, Michal Hocko , Andrew Morton , "Michael S . Tsirkin" , David Hildenbrand , Pankaj Gupta , Jason Wang , Oscar Salvador , Igor Mammedov , Dave Young , Dan Williams , Pavel Tatashin , Stefan Hajnoczi , Vlastimil Babka List-ID: Dropping the reference count of PageOffline() pages during MEM_GOING_ONLINE allows offlining code to skip them. However, we also have to clear PG_reserved, because PG_reserved pages get detected as unmovable right away. Take care of restoring the reference count when offlining is canceled. Clarify why we don't have to perform any action when unloading the driver. Also, let's add a warning if anybody is still holding a reference to unplugged pages when offlining. Tested-by: Pankaj Gupta Cc: "Michael S. Tsirkin" Cc: Jason Wang Cc: Oscar Salvador Cc: Michal Hocko Cc: Igor Mammedov Cc: Dave Young Cc: Andrew Morton Cc: Dan Williams Cc: Pavel Tatashin Cc: Stefan Hajnoczi Cc: Vlastimil Babka Signed-off-by: David Hildenbrand --- drivers/virtio/virtio_mem.c | 68 ++++++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/drivers/virtio/virtio_mem.c b/drivers/virtio/virtio_mem.c index 74f0d3cb1d22..b0b41c73ce89 100644 --- a/drivers/virtio/virtio_mem.c +++ b/drivers/virtio/virtio_mem.c @@ -572,6 +572,57 @@ static void virtio_mem_notify_online(struct virtio_mem= *vm, unsigned long mb_id, =09=09virtio_mem_retry(vm); } =20 +static void virtio_mem_notify_going_offline(struct virtio_mem *vm, +=09=09=09=09=09 unsigned long mb_id) +{ +=09const unsigned long nr_pages =3D PFN_DOWN(vm->subblock_size); +=09struct page *page; +=09unsigned long pfn; +=09int sb_id, i; + +=09for (sb_id =3D 0; sb_id < vm->nb_sb_per_mb; sb_id++) { +=09=09if (virtio_mem_mb_test_sb_plugged(vm, mb_id, sb_id, 1)) +=09=09=09continue; +=09=09/* +=09=09 * Drop our reference to the pages so the memory can get +=09=09 * offlined and add the unplugged pages to the managed +=09=09 * page counters (so offlining code can correctly subtract +=09=09 * them again). +=09=09 */ +=09=09pfn =3D PFN_DOWN(virtio_mem_mb_id_to_phys(mb_id) + +=09=09=09 sb_id * vm->subblock_size); +=09=09adjust_managed_page_count(pfn_to_page(pfn), nr_pages); +=09=09for (i =3D 0; i < nr_pages; i++) { +=09=09=09page =3D pfn_to_page(pfn + i); +=09=09=09if (WARN_ON(!page_ref_dec_and_test(page))) +=09=09=09=09dump_page(page, "unplugged page referenced"); +=09=09} +=09} +} + +static void virtio_mem_notify_cancel_offline(struct virtio_mem *vm, +=09=09=09=09=09 unsigned long mb_id) +{ +=09const unsigned long nr_pages =3D PFN_DOWN(vm->subblock_size); +=09unsigned long pfn; +=09int sb_id, i; + +=09for (sb_id =3D 0; sb_id < vm->nb_sb_per_mb; sb_id++) { +=09=09if (virtio_mem_mb_test_sb_plugged(vm, mb_id, sb_id, 1)) +=09=09=09continue; +=09=09/* +=09=09 * Get the reference we dropped when going offline and +=09=09 * subtract the unplugged pages from the managed page +=09=09 * counters. +=09=09 */ +=09=09pfn =3D PFN_DOWN(virtio_mem_mb_id_to_phys(mb_id) + +=09=09=09 sb_id * vm->subblock_size); +=09=09adjust_managed_page_count(pfn_to_page(pfn), -nr_pages); +=09=09for (i =3D 0; i < nr_pages; i++) +=09=09=09page_ref_inc(pfn_to_page(pfn + i)); +=09} +} + /* * This callback will either be called synchronously from add_memory() or * asynchronously (e.g., triggered via user space). We have to be careful @@ -618,6 +669,7 @@ static int virtio_mem_memory_notifier_cb(struct notifie= r_block *nb, =09=09=09break; =09=09} =09=09vm->hotplug_active =3D true; +=09=09virtio_mem_notify_going_offline(vm, mb_id); =09=09break; =09case MEM_GOING_ONLINE: =09=09mutex_lock(&vm->hotplug_mutex); @@ -642,6 +694,12 @@ static int virtio_mem_memory_notifier_cb(struct notifi= er_block *nb, =09=09mutex_unlock(&vm->hotplug_mutex); =09=09break; =09case MEM_CANCEL_OFFLINE: +=09=09if (!vm->hotplug_active) +=09=09=09break; +=09=09virtio_mem_notify_cancel_offline(vm, mb_id); +=09=09vm->hotplug_active =3D false; +=09=09mutex_unlock(&vm->hotplug_mutex); +=09=09break; =09case MEM_CANCEL_ONLINE: =09=09if (!vm->hotplug_active) =09=09=09break; @@ -668,8 +726,11 @@ static void virtio_mem_set_fake_offline(unsigned long = pfn, =09=09struct page *page =3D pfn_to_page(pfn); =20 =09=09__SetPageOffline(page); -=09=09if (!onlined) +=09=09if (!onlined) { =09=09=09SetPageDirty(page); +=09=09=09/* FIXME: remove after cleanups */ +=09=09=09ClearPageReserved(page); +=09=09} =09} } =20 @@ -1722,6 +1783,11 @@ static void virtio_mem_remove(struct virtio_device *= vdev) =09=09BUG_ON(rc); =09=09virtio_mem_mb_set_state(vm, mb_id, VIRTIO_MEM_MB_STATE_UNUSED); =09} +=09/* +=09 * After we unregistered our callbacks, user space can no longer +=09 * offline partially plugged online memory blocks. No need to worry +=09 * about them. +=09 */ =20 =09/* unregister callbacks */ =09unregister_virtio_mem_device(vm); --=20 2.25.3 --------------------------------------------------------------------- To unsubscribe, e-mail: virtio-dev-unsubscribe@lists.oasis-open.org For additional commands, e-mail: virtio-dev-help@lists.oasis-open.org