Linux-mm Archive on lore.kernel.org
 help / color / Atom feed
* [PATCH v1 0/3] virtio-balloon: Fixes + switch back to OOM handler
@ 2020-02-05 16:33 David Hildenbrand
  2020-02-05 16:34 ` [PATCH v1 1/3] virtio-balloon: Fix memory leak when unloading while hinting is in progress David Hildenbrand
                   ` (2 more replies)
  0 siblings, 3 replies; 27+ messages in thread
From: David Hildenbrand @ 2020-02-05 16:33 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-mm, virtualization, David Hildenbrand, Alexander Duyck,
	David Rientjes, Jason Wang, Liang Li, Michael S. Tsirkin,
	Michal Hocko, Nadav Amit, Tyler Sanderson, Wei Wang

Two fixes for issues I stumbled over while working on patch #3.

Switch back to the good ol' OOM handler for VIRTIO_BALLOON_F_DEFLATE_ON_OOM
as the switch to the shrinker introduce some undesired side effects. Keep
the shrinker in place to handle VIRTIO_BALLOON_F_FREE_PAGE_HINT.
Lengthy discussion under [1].

I tested with QEMU and "deflate-on-oom=on". Works as expected. Did not
test the shrinker for VIRTIO_BALLOON_F_FREE_PAGE_HINT, as it is
hard to trigger (only when migrating a VM, and even then, it might not
trigger).

[1] https://www.spinics.net/lists/linux-virtualization/msg40863.html

David Hildenbrand (3):
  virtio-balloon: Fix memory leak when unloading while hinting is in
    progress
  virtio_balloon: Fix memory leaks on errors in virtballoon_probe()
  virtio-balloon: Switch back to OOM handler for
    VIRTIO_BALLOON_F_DEFLATE_ON_OOM

 drivers/virtio/virtio_balloon.c | 124 +++++++++++++++-----------------
 1 file changed, 57 insertions(+), 67 deletions(-)

-- 
2.24.1



^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH v1 1/3] virtio-balloon: Fix memory leak when unloading while hinting is in progress
  2020-02-05 16:33 [PATCH v1 0/3] virtio-balloon: Fixes + switch back to OOM handler David Hildenbrand
@ 2020-02-05 16:34 ` David Hildenbrand
  2020-02-06  8:36   ` Michael S. Tsirkin
  2020-02-05 16:34 ` [PATCH v1 2/3] virtio_balloon: Fix memory leaks on errors in virtballoon_probe() David Hildenbrand
  2020-02-05 16:34 ` [PATCH v1 3/3] virtio-balloon: Switch back to OOM handler for VIRTIO_BALLOON_F_DEFLATE_ON_OOM David Hildenbrand
  2 siblings, 1 reply; 27+ messages in thread
From: David Hildenbrand @ 2020-02-05 16:34 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-mm, virtualization, David Hildenbrand, Michael S. Tsirkin,
	Jason Wang, Wei Wang, Liang Li

When unloading the driver while hinting is in progress, we will not
release the free page blocks back to MM, resulting in a memory leak.

Fixes: 86a559787e6f ("virtio-balloon: VIRTIO_BALLOON_F_FREE_PAGE_HINT")
Cc: "Michael S. Tsirkin" <mst@redhat.com>
Cc: Jason Wang <jasowang@redhat.com>
Cc: Wei Wang <wei.w.wang@intel.com>
Cc: Liang Li <liang.z.li@intel.com>
Signed-off-by: David Hildenbrand <david@redhat.com>
---
 drivers/virtio/virtio_balloon.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index 8e400ece9273..abef2306c899 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -968,6 +968,10 @@ static void remove_common(struct virtio_balloon *vb)
 		leak_balloon(vb, vb->num_pages);
 	update_balloon_size(vb);
 
+	/* There might be free pages that are being reported: release them. */
+	if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT))
+		return_free_pages_to_mm(vb, ULONG_MAX);
+
 	/* Now we reset the device so we can clean up the queues. */
 	vb->vdev->config->reset(vb->vdev);
 
-- 
2.24.1



^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH v1 2/3] virtio_balloon: Fix memory leaks on errors in virtballoon_probe()
  2020-02-05 16:33 [PATCH v1 0/3] virtio-balloon: Fixes + switch back to OOM handler David Hildenbrand
  2020-02-05 16:34 ` [PATCH v1 1/3] virtio-balloon: Fix memory leak when unloading while hinting is in progress David Hildenbrand
@ 2020-02-05 16:34 ` David Hildenbrand
  2020-02-06  8:36   ` Michael S. Tsirkin
  2020-02-05 16:34 ` [PATCH v1 3/3] virtio-balloon: Switch back to OOM handler for VIRTIO_BALLOON_F_DEFLATE_ON_OOM David Hildenbrand
  2 siblings, 1 reply; 27+ messages in thread
From: David Hildenbrand @ 2020-02-05 16:34 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-mm, virtualization, David Hildenbrand, Michael S. Tsirkin,
	Jason Wang, Wei Wang, Liang Li

We forget to put the inode and unmount the kernfs used for compaction.

Fixes: 71994620bb25 ("virtio_balloon: replace oom notifier with shrinker")
Cc: "Michael S. Tsirkin" <mst@redhat.com>
Cc: Jason Wang <jasowang@redhat.com>
Cc: Wei Wang <wei.w.wang@intel.com>
Cc: Liang Li <liang.z.li@intel.com>
Signed-off-by: David Hildenbrand <david@redhat.com>
---
 drivers/virtio/virtio_balloon.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index abef2306c899..7e5d84caeb94 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -901,8 +901,7 @@ static int virtballoon_probe(struct virtio_device *vdev)
 	vb->vb_dev_info.inode = alloc_anon_inode(balloon_mnt->mnt_sb);
 	if (IS_ERR(vb->vb_dev_info.inode)) {
 		err = PTR_ERR(vb->vb_dev_info.inode);
-		kern_unmount(balloon_mnt);
-		goto out_del_vqs;
+		goto out_kern_unmount;
 	}
 	vb->vb_dev_info.inode->i_mapping->a_ops = &balloon_aops;
 #endif
@@ -913,13 +912,13 @@ static int virtballoon_probe(struct virtio_device *vdev)
 		 */
 		if (virtqueue_get_vring_size(vb->free_page_vq) < 2) {
 			err = -ENOSPC;
-			goto out_del_vqs;
+			goto out_iput;
 		}
 		vb->balloon_wq = alloc_workqueue("balloon-wq",
 					WQ_FREEZABLE | WQ_CPU_INTENSIVE, 0);
 		if (!vb->balloon_wq) {
 			err = -ENOMEM;
-			goto out_del_vqs;
+			goto out_iput;
 		}
 		INIT_WORK(&vb->report_free_page_work, report_free_page_func);
 		vb->cmd_id_received_cache = VIRTIO_BALLOON_CMD_ID_STOP;
@@ -953,6 +952,12 @@ static int virtballoon_probe(struct virtio_device *vdev)
 out_del_balloon_wq:
 	if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT))
 		destroy_workqueue(vb->balloon_wq);
+out_iput:
+#ifdef CONFIG_BALLOON_COMPACTION
+	iput(vb->vb_dev_info.inode);
+out_kern_unmount:
+	kern_unmount(balloon_mnt);
+#endif
 out_del_vqs:
 	vdev->config->del_vqs(vdev);
 out_free_vb:
-- 
2.24.1



^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH v1 3/3] virtio-balloon: Switch back to OOM handler for VIRTIO_BALLOON_F_DEFLATE_ON_OOM
  2020-02-05 16:33 [PATCH v1 0/3] virtio-balloon: Fixes + switch back to OOM handler David Hildenbrand
  2020-02-05 16:34 ` [PATCH v1 1/3] virtio-balloon: Fix memory leak when unloading while hinting is in progress David Hildenbrand
  2020-02-05 16:34 ` [PATCH v1 2/3] virtio_balloon: Fix memory leaks on errors in virtballoon_probe() David Hildenbrand
@ 2020-02-05 16:34 ` David Hildenbrand
  2020-02-05 22:37   ` Tyler Sanderson
                     ` (6 more replies)
  2 siblings, 7 replies; 27+ messages in thread
From: David Hildenbrand @ 2020-02-05 16:34 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-mm, virtualization, David Hildenbrand, Tyler Sanderson,
	Michael S . Tsirkin, Wei Wang, Alexander Duyck, David Rientjes,
	Nadav Amit, Michal Hocko

Commit 71994620bb25 ("virtio_balloon: replace oom notifier with shrinker")
changed the behavior when deflation happens automatically. Instead of
deflating when called by the OOM handler, the shrinker is used.

However, the balloon is not simply some slab cache that should be
shrunk when under memory pressure. The shrinker does not have a concept of
priorities, so this behavior cannot be configured.

There was a report that this results in undesired side effects when
inflating the balloon to shrink the page cache. [1]
	"When inflating the balloon against page cache (i.e. no free memory
	 remains) vmscan.c will both shrink page cache, but also invoke the
	 shrinkers -- including the balloon's shrinker. So the balloon
	 driver allocates memory which requires reclaim, vmscan gets this
	 memory by shrinking the balloon, and then the driver adds the
	 memory back to the balloon. Basically a busy no-op."

The name "deflate on OOM" makes it pretty clear when deflation should
happen - after other approaches to reclaim memory failed, not while
reclaiming. This allows to minimize the footprint of a guest - memory
will only be taken out of the balloon when really needed.

Especially, a drop_slab() will result in the whole balloon getting
deflated - undesired. While handling it via the OOM handler might not be
perfect, it keeps existing behavior. If we want a different behavior, then
we need a new feature bit and document it properly (although, there should
be a clear use case and the intended effects should be well described).

Keep using the shrinker for VIRTIO_BALLOON_F_FREE_PAGE_HINT, because
this has no such side effects. Always register the shrinker with
VIRTIO_BALLOON_F_FREE_PAGE_HINT now. We are always allowed to reuse free
pages that are still to be processed by the guest. The hypervisor takes
care of identifying and resolving possible races between processing a
hinting request and the guest reusing a page.

In contrast to pre commit 71994620bb25 ("virtio_balloon: replace oom
notifier with shrinker"), don't add a moodule parameter to configure the
number of pages to deflate on OOM. Can be re-added if really needed.
Also, pay attention that leak_balloon() returns the number of 4k pages -
convert it properly in virtio_balloon_oom_notify().

Note1: using the OOM handler is frowned upon, but it really is what we
       need for this feature.

Note2: without VIRTIO_BALLOON_F_MUST_TELL_HOST (iow, always with QEMU) we
       could actually skip sending deflation requests to our hypervisor,
       making the OOM path *very* simple. Besically freeing pages and
       updating the balloon. If the communication with the host ever
       becomes a problem on this call path.

[1] https://www.spinics.net/lists/linux-virtualization/msg40863.html

Reported-by: Tyler Sanderson <tysand@google.com>
Cc: Michael S. Tsirkin <mst@redhat.com>
Cc: Wei Wang <wei.w.wang@intel.com>
Cc: Alexander Duyck <alexander.h.duyck@linux.intel.com>
Cc: David Rientjes <rientjes@google.com>
Cc: Nadav Amit <namit@vmware.com>
Cc: Michal Hocko <mhocko@kernel.org>
Signed-off-by: David Hildenbrand <david@redhat.com>
---
 drivers/virtio/virtio_balloon.c | 107 +++++++++++++-------------------
 1 file changed, 44 insertions(+), 63 deletions(-)

diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index 7e5d84caeb94..e7b18f556c5e 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -14,6 +14,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/balloon_compaction.h>
+#include <linux/oom.h>
 #include <linux/wait.h>
 #include <linux/mm.h>
 #include <linux/mount.h>
@@ -27,7 +28,9 @@
  */
 #define VIRTIO_BALLOON_PAGES_PER_PAGE (unsigned)(PAGE_SIZE >> VIRTIO_BALLOON_PFN_SHIFT)
 #define VIRTIO_BALLOON_ARRAY_PFNS_MAX 256
-#define VIRTBALLOON_OOM_NOTIFY_PRIORITY 80
+/* Maximum number of (4k) pages to deflate on OOM notifications. */
+#define VIRTIO_BALLOON_OOM_NR_PAGES 256
+#define VIRTIO_BALLOON_OOM_NOTIFY_PRIORITY 80
 
 #define VIRTIO_BALLOON_FREE_PAGE_ALLOC_FLAG (__GFP_NORETRY | __GFP_NOWARN | \
 					     __GFP_NOMEMALLOC)
@@ -112,8 +115,11 @@ struct virtio_balloon {
 	/* Memory statistics */
 	struct virtio_balloon_stat stats[VIRTIO_BALLOON_S_NR];
 
-	/* To register a shrinker to shrink memory upon memory pressure */
+	/* Shrinker to return free pages - VIRTIO_BALLOON_F_FREE_PAGE_HINT */
 	struct shrinker shrinker;
+
+	/* OOM notifier to deflate on OOM - VIRTIO_BALLOON_F_DEFLATE_ON_OOM */
+	struct notifier_block oom_nb;
 };
 
 static struct virtio_device_id id_table[] = {
@@ -786,50 +792,13 @@ static unsigned long shrink_free_pages(struct virtio_balloon *vb,
 	return blocks_freed * VIRTIO_BALLOON_HINT_BLOCK_PAGES;
 }
 
-static unsigned long leak_balloon_pages(struct virtio_balloon *vb,
-                                          unsigned long pages_to_free)
-{
-	return leak_balloon(vb, pages_to_free * VIRTIO_BALLOON_PAGES_PER_PAGE) /
-		VIRTIO_BALLOON_PAGES_PER_PAGE;
-}
-
-static unsigned long shrink_balloon_pages(struct virtio_balloon *vb,
-					  unsigned long pages_to_free)
-{
-	unsigned long pages_freed = 0;
-
-	/*
-	 * One invocation of leak_balloon can deflate at most
-	 * VIRTIO_BALLOON_ARRAY_PFNS_MAX balloon pages, so we call it
-	 * multiple times to deflate pages till reaching pages_to_free.
-	 */
-	while (vb->num_pages && pages_freed < pages_to_free)
-		pages_freed += leak_balloon_pages(vb,
-						  pages_to_free - pages_freed);
-
-	update_balloon_size(vb);
-
-	return pages_freed;
-}
-
 static unsigned long virtio_balloon_shrinker_scan(struct shrinker *shrinker,
 						  struct shrink_control *sc)
 {
-	unsigned long pages_to_free, pages_freed = 0;
 	struct virtio_balloon *vb = container_of(shrinker,
 					struct virtio_balloon, shrinker);
 
-	pages_to_free = sc->nr_to_scan;
-
-	if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT))
-		pages_freed = shrink_free_pages(vb, pages_to_free);
-
-	if (pages_freed >= pages_to_free)
-		return pages_freed;
-
-	pages_freed += shrink_balloon_pages(vb, pages_to_free - pages_freed);
-
-	return pages_freed;
+	return shrink_free_pages(vb, sc->nr_to_scan);
 }
 
 static unsigned long virtio_balloon_shrinker_count(struct shrinker *shrinker,
@@ -837,26 +806,22 @@ static unsigned long virtio_balloon_shrinker_count(struct shrinker *shrinker,
 {
 	struct virtio_balloon *vb = container_of(shrinker,
 					struct virtio_balloon, shrinker);
-	unsigned long count;
-
-	count = vb->num_pages / VIRTIO_BALLOON_PAGES_PER_PAGE;
-	count += vb->num_free_page_blocks * VIRTIO_BALLOON_HINT_BLOCK_PAGES;
 
-	return count;
+	return vb->num_free_page_blocks * VIRTIO_BALLOON_HINT_BLOCK_PAGES;
 }
 
-static void virtio_balloon_unregister_shrinker(struct virtio_balloon *vb)
+static int virtio_balloon_oom_notify(struct notifier_block *nb,
+				     unsigned long dummy, void *parm)
 {
-	unregister_shrinker(&vb->shrinker);
-}
+	struct virtio_balloon *vb = container_of(nb,
+						 struct virtio_balloon, oom_nb);
+	unsigned long *freed = parm;
 
-static int virtio_balloon_register_shrinker(struct virtio_balloon *vb)
-{
-	vb->shrinker.scan_objects = virtio_balloon_shrinker_scan;
-	vb->shrinker.count_objects = virtio_balloon_shrinker_count;
-	vb->shrinker.seeks = DEFAULT_SEEKS;
+	*freed += leak_balloon(vb, VIRTIO_BALLOON_OOM_NR_PAGES) /
+		  VIRTIO_BALLOON_PAGES_PER_PAGE;
+	update_balloon_size(vb);
 
-	return register_shrinker(&vb->shrinker);
+	return NOTIFY_OK;
 }
 
 static int virtballoon_probe(struct virtio_device *vdev)
@@ -933,22 +898,35 @@ static int virtballoon_probe(struct virtio_device *vdev)
 			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
-	 * shrinker needs to be registered to relieve memory pressure.
-	 */
-	if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM)) {
-		err = virtio_balloon_register_shrinker(vb);
+
+		/*
+		 * We're allowed to reuse any free pages, even if they are
+		 * still to be processed by the host.
+		 */
+		vb->shrinker.scan_objects = virtio_balloon_shrinker_scan;
+		vb->shrinker.count_objects = virtio_balloon_shrinker_count;
+		vb->shrinker.seeks = DEFAULT_SEEKS;
+		err = register_shrinker(&vb->shrinker);
 		if (err)
 			goto out_del_balloon_wq;
 	}
+	if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM)) {
+		vb->oom_nb.notifier_call = virtio_balloon_oom_notify;
+		vb->oom_nb.priority = VIRTIO_BALLOON_OOM_NOTIFY_PRIORITY;
+		err = register_oom_notifier(&vb->oom_nb);
+		if (err < 0)
+			goto out_unregister_shrinker;
+	}
+
 	virtio_device_ready(vdev);
 
 	if (towards_target(vb))
 		virtballoon_changed(vdev);
 	return 0;
 
+out_unregister_shrinker:
+	if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT))
+		unregister_shrinker(&vb->shrinker);
 out_del_balloon_wq:
 	if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT))
 		destroy_workqueue(vb->balloon_wq);
@@ -987,8 +965,11 @@ static void virtballoon_remove(struct virtio_device *vdev)
 {
 	struct virtio_balloon *vb = vdev->priv;
 
-	if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM))
-		virtio_balloon_unregister_shrinker(vb);
+	if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM))
+		unregister_oom_notifier(&vb->oom_nb);
+	if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT))
+		unregister_shrinker(&vb->shrinker);
+
 	spin_lock_irq(&vb->stop_update_lock);
 	vb->stop_update = true;
 	spin_unlock_irq(&vb->stop_update_lock);
-- 
2.24.1



^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v1 3/3] virtio-balloon: Switch back to OOM handler for VIRTIO_BALLOON_F_DEFLATE_ON_OOM
  2020-02-05 16:34 ` [PATCH v1 3/3] virtio-balloon: Switch back to OOM handler for VIRTIO_BALLOON_F_DEFLATE_ON_OOM David Hildenbrand
@ 2020-02-05 22:37   ` Tyler Sanderson
  2020-02-05 22:52     ` David Hildenbrand
  2020-02-06  7:40   ` Michael S. Tsirkin
                     ` (5 subsequent siblings)
  6 siblings, 1 reply; 27+ messages in thread
From: Tyler Sanderson @ 2020-02-05 22:37 UTC (permalink / raw)
  To: David Hildenbrand
  Cc: linux-kernel, linux-mm, virtualization, Michael S . Tsirkin,
	Wei Wang, Alexander Duyck, David Rientjes, Nadav Amit,
	Michal Hocko

[-- Attachment #1: Type: text/plain, Size: 11534 bytes --]

On Wed, Feb 5, 2020 at 8:34 AM David Hildenbrand <david@redhat.com> wrote:

> Commit 71994620bb25 ("virtio_balloon: replace oom notifier with shrinker")
> changed the behavior when deflation happens automatically. Instead of
> deflating when called by the OOM handler, the shrinker is used.
>
> However, the balloon is not simply some slab cache that should be
> shrunk when under memory pressure. The shrinker does not have a concept of
> priorities, so this behavior cannot be configured.
>
> There was a report that this results in undesired side effects when
> inflating the balloon to shrink the page cache. [1]
>         "When inflating the balloon against page cache (i.e. no free memory
>          remains) vmscan.c will both shrink page cache, but also invoke the
>          shrinkers -- including the balloon's shrinker. So the balloon
>          driver allocates memory which requires reclaim, vmscan gets this
>          memory by shrinking the balloon, and then the driver adds the
>          memory back to the balloon. Basically a busy no-op."
>
> The name "deflate on OOM" makes it pretty clear when deflation should
> happen - after other approaches to reclaim memory failed, not while
> reclaiming. This allows to minimize the footprint of a guest - memory
> will only be taken out of the balloon when really needed.
>
> Especially, a drop_slab() will result in the whole balloon getting
> deflated - undesired. While handling it via the OOM handler might not be
> perfect, it keeps existing behavior. If we want a different behavior, then
> we need a new feature bit and document it properly (although, there should
> be a clear use case and the intended effects should be well described).
>
> Keep using the shrinker for VIRTIO_BALLOON_F_FREE_PAGE_HINT, because
> this has no such side effects. Always register the shrinker with
> VIRTIO_BALLOON_F_FREE_PAGE_HINT now. We are always allowed to reuse free
> pages that are still to be processed by the guest. The hypervisor takes
> care of identifying and resolving possible races between processing a
> hinting request and the guest reusing a page.
>
> In contrast to pre commit 71994620bb25 ("virtio_balloon: replace oom
> notifier with shrinker"), don't add a moodule parameter to configure the
> number of pages to deflate on OOM. Can be re-added if really needed.
> Also, pay attention that leak_balloon() returns the number of 4k pages -
> convert it properly in virtio_balloon_oom_notify().
>
> Note1: using the OOM handler is frowned upon, but it really is what we
>        need for this feature.
>
> Note2: without VIRTIO_BALLOON_F_MUST_TELL_HOST (iow, always with QEMU) we
>        could actually skip sending deflation requests to our hypervisor,
>        making the OOM path *very* simple. Besically freeing pages and
>        updating the balloon. If the communication with the host ever
>        becomes a problem on this call path.
>
> [1] https://www.spinics.net/lists/linux-virtualization/msg40863.html
>
> Reported-by: Tyler Sanderson <tysand@google.com>
> Cc: Michael S. Tsirkin <mst@redhat.com>
> Cc: Wei Wang <wei.w.wang@intel.com>
> Cc: Alexander Duyck <alexander.h.duyck@linux.intel.com>
> Cc: David Rientjes <rientjes@google.com>
> Cc: Nadav Amit <namit@vmware.com>
> Cc: Michal Hocko <mhocko@kernel.org>
> Signed-off-by: David Hildenbrand <david@redhat.com>
> ---
>  drivers/virtio/virtio_balloon.c | 107 +++++++++++++-------------------
>  1 file changed, 44 insertions(+), 63 deletions(-)
>
> diff --git a/drivers/virtio/virtio_balloon.c
> b/drivers/virtio/virtio_balloon.c
> index 7e5d84caeb94..e7b18f556c5e 100644
> --- a/drivers/virtio/virtio_balloon.c
> +++ b/drivers/virtio/virtio_balloon.c
> @@ -14,6 +14,7 @@
>  #include <linux/slab.h>
>  #include <linux/module.h>
>  #include <linux/balloon_compaction.h>
> +#include <linux/oom.h>
>  #include <linux/wait.h>
>  #include <linux/mm.h>
>  #include <linux/mount.h>
> @@ -27,7 +28,9 @@
>   */
>  #define VIRTIO_BALLOON_PAGES_PER_PAGE (unsigned)(PAGE_SIZE >>
> VIRTIO_BALLOON_PFN_SHIFT)
>  #define VIRTIO_BALLOON_ARRAY_PFNS_MAX 256
> -#define VIRTBALLOON_OOM_NOTIFY_PRIORITY 80
> +/* Maximum number of (4k) pages to deflate on OOM notifications. */
> +#define VIRTIO_BALLOON_OOM_NR_PAGES 256
> +#define VIRTIO_BALLOON_OOM_NOTIFY_PRIORITY 80
>
>  #define VIRTIO_BALLOON_FREE_PAGE_ALLOC_FLAG (__GFP_NORETRY | __GFP_NOWARN
> | \
>                                              __GFP_NOMEMALLOC)
> @@ -112,8 +115,11 @@ struct virtio_balloon {
>         /* Memory statistics */
>         struct virtio_balloon_stat stats[VIRTIO_BALLOON_S_NR];
>
> -       /* To register a shrinker to shrink memory upon memory pressure */
> +       /* Shrinker to return free pages - VIRTIO_BALLOON_F_FREE_PAGE_HINT
> */
>         struct shrinker shrinker;
> +
> +       /* OOM notifier to deflate on OOM -
> VIRTIO_BALLOON_F_DEFLATE_ON_OOM */
> +       struct notifier_block oom_nb;
>  };
>
>  static struct virtio_device_id id_table[] = {
> @@ -786,50 +792,13 @@ static unsigned long shrink_free_pages(struct
> virtio_balloon *vb,
>         return blocks_freed * VIRTIO_BALLOON_HINT_BLOCK_PAGES;
>  }
>
> -static unsigned long leak_balloon_pages(struct virtio_balloon *vb,
> -                                          unsigned long pages_to_free)
> -{
> -       return leak_balloon(vb, pages_to_free *
> VIRTIO_BALLOON_PAGES_PER_PAGE) /
> -               VIRTIO_BALLOON_PAGES_PER_PAGE;
> -}
> -
> -static unsigned long shrink_balloon_pages(struct virtio_balloon *vb,
> -                                         unsigned long pages_to_free)
> -{
> -       unsigned long pages_freed = 0;
> -
> -       /*
> -        * One invocation of leak_balloon can deflate at most
> -        * VIRTIO_BALLOON_ARRAY_PFNS_MAX balloon pages, so we call it
> -        * multiple times to deflate pages till reaching pages_to_free.
> -        */
> -       while (vb->num_pages && pages_freed < pages_to_free)
> -               pages_freed += leak_balloon_pages(vb,
> -                                                 pages_to_free -
> pages_freed);
> -
> -       update_balloon_size(vb);
> -
> -       return pages_freed;
> -}
> -
>  static unsigned long virtio_balloon_shrinker_scan(struct shrinker
> *shrinker,
>                                                   struct shrink_control
> *sc)
>  {
> -       unsigned long pages_to_free, pages_freed = 0;
>         struct virtio_balloon *vb = container_of(shrinker,
>                                         struct virtio_balloon, shrinker);
>
> -       pages_to_free = sc->nr_to_scan;
> -
> -       if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT))
> -               pages_freed = shrink_free_pages(vb, pages_to_free);
> -
> -       if (pages_freed >= pages_to_free)
> -               return pages_freed;
> -
> -       pages_freed += shrink_balloon_pages(vb, pages_to_free -
> pages_freed);
> -
> -       return pages_freed;
> +       return shrink_free_pages(vb, sc->nr_to_scan);
>  }
>
>  static unsigned long virtio_balloon_shrinker_count(struct shrinker
> *shrinker,
> @@ -837,26 +806,22 @@ static unsigned long
> virtio_balloon_shrinker_count(struct shrinker *shrinker,
>  {
>         struct virtio_balloon *vb = container_of(shrinker,
>                                         struct virtio_balloon, shrinker);
> -       unsigned long count;
> -
> -       count = vb->num_pages / VIRTIO_BALLOON_PAGES_PER_PAGE;
> -       count += vb->num_free_page_blocks *
> VIRTIO_BALLOON_HINT_BLOCK_PAGES;
>
> -       return count;
> +       return vb->num_free_page_blocks * VIRTIO_BALLOON_HINT_BLOCK_PAGES;
>  }
>
> -static void virtio_balloon_unregister_shrinker(struct virtio_balloon *vb)
> +static int virtio_balloon_oom_notify(struct notifier_block *nb,
> +                                    unsigned long dummy, void *parm)
>  {
> -       unregister_shrinker(&vb->shrinker);
> -}
> +       struct virtio_balloon *vb = container_of(nb,
> +                                                struct virtio_balloon,
> oom_nb);
> +       unsigned long *freed = parm;
>
> -static int virtio_balloon_register_shrinker(struct virtio_balloon *vb)
> -{
> -       vb->shrinker.scan_objects = virtio_balloon_shrinker_scan;
> -       vb->shrinker.count_objects = virtio_balloon_shrinker_count;
> -       vb->shrinker.seeks = DEFAULT_SEEKS;
> +       *freed += leak_balloon(vb, VIRTIO_BALLOON_OOM_NR_PAGES) /
> +                 VIRTIO_BALLOON_PAGES_PER_PAGE;
> +       update_balloon_size(vb);
>
> -       return register_shrinker(&vb->shrinker);
> +       return NOTIFY_OK;
>  }
>
>  static int virtballoon_probe(struct virtio_device *vdev)
> @@ -933,22 +898,35 @@ static int virtballoon_probe(struct virtio_device
> *vdev)
>                         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
> -        * shrinker needs to be registered to relieve memory pressure.
> -        */
> -       if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM))
> {
> -               err = virtio_balloon_register_shrinker(vb);
> +
> +               /*
> +                * We're allowed to reuse any free pages, even if they are
> +                * still to be processed by the host.
>
It is important to clarify that pages that are on the inflate queue but not
ACKed by the host (the queue entry has not been returned) are _not_ okay to
reuse.
If the host is going to do something destructive to the page (like deback
it) then that needs to happen before the entry is returned.

+                */
> +               vb->shrinker.scan_objects = virtio_balloon_shrinker_scan;
> +               vb->shrinker.count_objects = virtio_balloon_shrinker_count;
> +               vb->shrinker.seeks = DEFAULT_SEEKS;
> +               err = register_shrinker(&vb->shrinker);
>                 if (err)
>                         goto out_del_balloon_wq;
>         }
> +       if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM)) {
> +               vb->oom_nb.notifier_call = virtio_balloon_oom_notify;
> +               vb->oom_nb.priority = VIRTIO_BALLOON_OOM_NOTIFY_PRIORITY;
> +               err = register_oom_notifier(&vb->oom_nb);
> +               if (err < 0)
> +                       goto out_unregister_shrinker;
> +       }
> +
>         virtio_device_ready(vdev);
>
>         if (towards_target(vb))
>                 virtballoon_changed(vdev);
>         return 0;
>
> +out_unregister_shrinker:
> +       if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT))
> +               unregister_shrinker(&vb->shrinker);
>  out_del_balloon_wq:
>         if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT))
>                 destroy_workqueue(vb->balloon_wq);
> @@ -987,8 +965,11 @@ static void virtballoon_remove(struct virtio_device
> *vdev)
>  {
>         struct virtio_balloon *vb = vdev->priv;
>
> -       if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM))
> -               virtio_balloon_unregister_shrinker(vb);
> +       if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM))
> +               unregister_oom_notifier(&vb->oom_nb);
> +       if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT))
> +               unregister_shrinker(&vb->shrinker);
> +
>         spin_lock_irq(&vb->stop_update_lock);
>         vb->stop_update = true;
>         spin_unlock_irq(&vb->stop_update_lock);
> --
> 2.24.1
>
>

[-- Attachment #2: Type: text/html, Size: 14388 bytes --]

<div dir="ltr"><div dir="ltr"><br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, Feb 5, 2020 at 8:34 AM David Hildenbrand &lt;<a href="mailto:david@redhat.com">david@redhat.com</a>&gt; wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Commit 71994620bb25 (&quot;virtio_balloon: replace oom notifier with shrinker&quot;)<br>
changed the behavior when deflation happens automatically. Instead of<br>
deflating when called by the OOM handler, the shrinker is used.<br>
<br>
However, the balloon is not simply some slab cache that should be<br>
shrunk when under memory pressure. The shrinker does not have a concept of<br>
priorities, so this behavior cannot be configured.<br>
<br>
There was a report that this results in undesired side effects when<br>
inflating the balloon to shrink the page cache. [1]<br>
        &quot;When inflating the balloon against page cache (i.e. no free memory<br>
         remains) vmscan.c will both shrink page cache, but also invoke the<br>
         shrinkers -- including the balloon&#39;s shrinker. So the balloon<br>
         driver allocates memory which requires reclaim, vmscan gets this<br>
         memory by shrinking the balloon, and then the driver adds the<br>
         memory back to the balloon. Basically a busy no-op.&quot;<br>
<br>
The name &quot;deflate on OOM&quot; makes it pretty clear when deflation should<br>
happen - after other approaches to reclaim memory failed, not while<br>
reclaiming. This allows to minimize the footprint of a guest - memory<br>
will only be taken out of the balloon when really needed.<br>
<br>
Especially, a drop_slab() will result in the whole balloon getting<br>
deflated - undesired. While handling it via the OOM handler might not be<br>
perfect, it keeps existing behavior. If we want a different behavior, then<br>
we need a new feature bit and document it properly (although, there should<br>
be a clear use case and the intended effects should be well described).<br>
<br>
Keep using the shrinker for VIRTIO_BALLOON_F_FREE_PAGE_HINT, because<br>
this has no such side effects. Always register the shrinker with<br>
VIRTIO_BALLOON_F_FREE_PAGE_HINT now. We are always allowed to reuse free<br>
pages that are still to be processed by the guest. The hypervisor takes<br>
care of identifying and resolving possible races between processing a<br>
hinting request and the guest reusing a page.<br>
<br>
In contrast to pre commit 71994620bb25 (&quot;virtio_balloon: replace oom<br>
notifier with shrinker&quot;), don&#39;t add a moodule parameter to configure the<br>
number of pages to deflate on OOM. Can be re-added if really needed.<br>
Also, pay attention that leak_balloon() returns the number of 4k pages -<br>
convert it properly in virtio_balloon_oom_notify().<br>
<br>
Note1: using the OOM handler is frowned upon, but it really is what we<br>
       need for this feature.<br>
<br>
Note2: without VIRTIO_BALLOON_F_MUST_TELL_HOST (iow, always with QEMU) we<br>
       could actually skip sending deflation requests to our hypervisor,<br>
       making the OOM path *very* simple. Besically freeing pages and<br>
       updating the balloon. If the communication with the host ever<br>
       becomes a problem on this call path.<br>
<br>
[1] <a href="https://www.spinics.net/lists/linux-virtualization/msg40863.html" rel="noreferrer" target="_blank">https://www.spinics.net/lists/linux-virtualization/msg40863.html</a><br>
<br>
Reported-by: Tyler Sanderson &lt;<a href="mailto:tysand@google.com" target="_blank">tysand@google.com</a>&gt;<br>
Cc: Michael S. Tsirkin &lt;<a href="mailto:mst@redhat.com" target="_blank">mst@redhat.com</a>&gt;<br>
Cc: Wei Wang &lt;<a href="mailto:wei.w.wang@intel.com" target="_blank">wei.w.wang@intel.com</a>&gt;<br>
Cc: Alexander Duyck &lt;<a href="mailto:alexander.h.duyck@linux.intel.com" target="_blank">alexander.h.duyck@linux.intel.com</a>&gt;<br>
Cc: David Rientjes &lt;<a href="mailto:rientjes@google.com" target="_blank">rientjes@google.com</a>&gt;<br>
Cc: Nadav Amit &lt;<a href="mailto:namit@vmware.com" target="_blank">namit@vmware.com</a>&gt;<br>
Cc: Michal Hocko &lt;<a href="mailto:mhocko@kernel.org" target="_blank">mhocko@kernel.org</a>&gt;<br>
Signed-off-by: David Hildenbrand &lt;<a href="mailto:david@redhat.com" target="_blank">david@redhat.com</a>&gt;<br>
---<br>
 drivers/virtio/virtio_balloon.c | 107 +++++++++++++-------------------<br>
 1 file changed, 44 insertions(+), 63 deletions(-)<br>
<br>
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c<br>
index 7e5d84caeb94..e7b18f556c5e 100644<br>
--- a/drivers/virtio/virtio_balloon.c<br>
+++ b/drivers/virtio/virtio_balloon.c<br>
@@ -14,6 +14,7 @@<br>
 #include &lt;linux/slab.h&gt;<br>
 #include &lt;linux/module.h&gt;<br>
 #include &lt;linux/balloon_compaction.h&gt;<br>
+#include &lt;linux/oom.h&gt;<br>
 #include &lt;linux/wait.h&gt;<br>
 #include &lt;linux/mm.h&gt;<br>
 #include &lt;linux/mount.h&gt;<br>
@@ -27,7 +28,9 @@<br>
  */<br>
 #define VIRTIO_BALLOON_PAGES_PER_PAGE (unsigned)(PAGE_SIZE &gt;&gt; VIRTIO_BALLOON_PFN_SHIFT)<br>
 #define VIRTIO_BALLOON_ARRAY_PFNS_MAX 256<br>
-#define VIRTBALLOON_OOM_NOTIFY_PRIORITY 80<br>
+/* Maximum number of (4k) pages to deflate on OOM notifications. */<br>
+#define VIRTIO_BALLOON_OOM_NR_PAGES 256<br>
+#define VIRTIO_BALLOON_OOM_NOTIFY_PRIORITY 80<br>
<br>
 #define VIRTIO_BALLOON_FREE_PAGE_ALLOC_FLAG (__GFP_NORETRY | __GFP_NOWARN | \<br>
                                             __GFP_NOMEMALLOC)<br>
@@ -112,8 +115,11 @@ struct virtio_balloon {<br>
        /* Memory statistics */<br>
        struct virtio_balloon_stat stats[VIRTIO_BALLOON_S_NR];<br>
<br>
-       /* To register a shrinker to shrink memory upon memory pressure */<br>
+       /* Shrinker to return free pages - VIRTIO_BALLOON_F_FREE_PAGE_HINT */<br>
        struct shrinker shrinker;<br>
+<br>
+       /* OOM notifier to deflate on OOM - VIRTIO_BALLOON_F_DEFLATE_ON_OOM */<br>
+       struct notifier_block oom_nb;<br>
 };<br>
<br>
 static struct virtio_device_id id_table[] = {<br>
@@ -786,50 +792,13 @@ static unsigned long shrink_free_pages(struct virtio_balloon *vb,<br>
        return blocks_freed * VIRTIO_BALLOON_HINT_BLOCK_PAGES;<br>
 }<br>
<br>
-static unsigned long leak_balloon_pages(struct virtio_balloon *vb,<br>
-                                          unsigned long pages_to_free)<br>
-{<br>
-       return leak_balloon(vb, pages_to_free * VIRTIO_BALLOON_PAGES_PER_PAGE) /<br>
-               VIRTIO_BALLOON_PAGES_PER_PAGE;<br>
-}<br>
-<br>
-static unsigned long shrink_balloon_pages(struct virtio_balloon *vb,<br>
-                                         unsigned long pages_to_free)<br>
-{<br>
-       unsigned long pages_freed = 0;<br>
-<br>
-       /*<br>
-        * One invocation of leak_balloon can deflate at most<br>
-        * VIRTIO_BALLOON_ARRAY_PFNS_MAX balloon pages, so we call it<br>
-        * multiple times to deflate pages till reaching pages_to_free.<br>
-        */<br>
-       while (vb-&gt;num_pages &amp;&amp; pages_freed &lt; pages_to_free)<br>
-               pages_freed += leak_balloon_pages(vb,<br>
-                                                 pages_to_free - pages_freed);<br>
-<br>
-       update_balloon_size(vb);<br>
-<br>
-       return pages_freed;<br>
-}<br>
-<br>
 static unsigned long virtio_balloon_shrinker_scan(struct shrinker *shrinker,<br>
                                                  struct shrink_control *sc)<br>
 {<br>
-       unsigned long pages_to_free, pages_freed = 0;<br>
        struct virtio_balloon *vb = container_of(shrinker,<br>
                                        struct virtio_balloon, shrinker);<br>
<br>
-       pages_to_free = sc-&gt;nr_to_scan;<br>
-<br>
-       if (virtio_has_feature(vb-&gt;vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT))<br>
-               pages_freed = shrink_free_pages(vb, pages_to_free);<br>
-<br>
-       if (pages_freed &gt;= pages_to_free)<br>
-               return pages_freed;<br>
-<br>
-       pages_freed += shrink_balloon_pages(vb, pages_to_free - pages_freed);<br>
-<br>
-       return pages_freed;<br>
+       return shrink_free_pages(vb, sc-&gt;nr_to_scan);<br>
 }<br>
<br>
 static unsigned long virtio_balloon_shrinker_count(struct shrinker *shrinker,<br>
@@ -837,26 +806,22 @@ static unsigned long virtio_balloon_shrinker_count(struct shrinker *shrinker,<br>
 {<br>
        struct virtio_balloon *vb = container_of(shrinker,<br>
                                        struct virtio_balloon, shrinker);<br>
-       unsigned long count;<br>
-<br>
-       count = vb-&gt;num_pages / VIRTIO_BALLOON_PAGES_PER_PAGE;<br>
-       count += vb-&gt;num_free_page_blocks * VIRTIO_BALLOON_HINT_BLOCK_PAGES;<br>
<br>
-       return count;<br>
+       return vb-&gt;num_free_page_blocks * VIRTIO_BALLOON_HINT_BLOCK_PAGES;<br>
 }<br>
<br>
-static void virtio_balloon_unregister_shrinker(struct virtio_balloon *vb)<br>
+static int virtio_balloon_oom_notify(struct notifier_block *nb,<br>
+                                    unsigned long dummy, void *parm)<br>
 {<br>
-       unregister_shrinker(&amp;vb-&gt;shrinker);<br>
-}<br>
+       struct virtio_balloon *vb = container_of(nb,<br>
+                                                struct virtio_balloon, oom_nb);<br>
+       unsigned long *freed = parm;<br>
<br>
-static int virtio_balloon_register_shrinker(struct virtio_balloon *vb)<br>
-{<br>
-       vb-&gt;shrinker.scan_objects = virtio_balloon_shrinker_scan;<br>
-       vb-&gt;shrinker.count_objects = virtio_balloon_shrinker_count;<br>
-       vb-&gt;shrinker.seeks = DEFAULT_SEEKS;<br>
+       *freed += leak_balloon(vb, VIRTIO_BALLOON_OOM_NR_PAGES) /<br>
+                 VIRTIO_BALLOON_PAGES_PER_PAGE;<br>
+       update_balloon_size(vb);<br>
<br>
-       return register_shrinker(&amp;vb-&gt;shrinker);<br>
+       return NOTIFY_OK;<br>
 }<br>
<br>
 static int virtballoon_probe(struct virtio_device *vdev)<br>
@@ -933,22 +898,35 @@ static int virtballoon_probe(struct virtio_device *vdev)<br>
                        virtio_cwrite(vb-&gt;vdev, struct virtio_balloon_config,<br>
                                      poison_val, &amp;poison_val);<br>
                }<br>
-       }<br>
-       /*<br>
-        * We continue to use VIRTIO_BALLOON_F_DEFLATE_ON_OOM to decide if a<br>
-        * shrinker needs to be registered to relieve memory pressure.<br>
-        */<br>
-       if (virtio_has_feature(vb-&gt;vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM)) {<br>
-               err = virtio_balloon_register_shrinker(vb);<br>
+<br>
+               /*<br>
+                * We&#39;re allowed to reuse any free pages, even if they are<br>
+                * still to be processed by the host.<br></blockquote><div>It is important to clarify that pages that are on the inflate queue but not ACKed by the host (the queue entry has not been returned) are _not_ okay to reuse.</div><div>If the host is going to do something destructive to the page (like deback it) then that needs to happen before the entry is returned.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+                */<br>
+               vb-&gt;shrinker.scan_objects = virtio_balloon_shrinker_scan;<br>
+               vb-&gt;shrinker.count_objects = virtio_balloon_shrinker_count;<br>
+               vb-&gt;shrinker.seeks = DEFAULT_SEEKS;<br>
+               err = register_shrinker(&amp;vb-&gt;shrinker);<br>
                if (err)<br>
                        goto out_del_balloon_wq;<br>
        }<br>
+       if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM)) {<br>
+               vb-&gt;oom_nb.notifier_call = virtio_balloon_oom_notify;<br>
+               vb-&gt;oom_nb.priority = VIRTIO_BALLOON_OOM_NOTIFY_PRIORITY;<br>
+               err = register_oom_notifier(&amp;vb-&gt;oom_nb);<br>
+               if (err &lt; 0)<br>
+                       goto out_unregister_shrinker;<br>
+       }<br>
+<br>
        virtio_device_ready(vdev);<br>
<br>
        if (towards_target(vb))<br>
                virtballoon_changed(vdev);<br>
        return 0;<br>
<br>
+out_unregister_shrinker:<br>
+       if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT))<br>
+               unregister_shrinker(&amp;vb-&gt;shrinker);<br>
 out_del_balloon_wq:<br>
        if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT))<br>
                destroy_workqueue(vb-&gt;balloon_wq);<br>
@@ -987,8 +965,11 @@ static void virtballoon_remove(struct virtio_device *vdev)<br>
 {<br>
        struct virtio_balloon *vb = vdev-&gt;priv;<br>
<br>
-       if (virtio_has_feature(vb-&gt;vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM))<br>
-               virtio_balloon_unregister_shrinker(vb);<br>
+       if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM))<br>
+               unregister_oom_notifier(&amp;vb-&gt;oom_nb);<br>
+       if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT))<br>
+               unregister_shrinker(&amp;vb-&gt;shrinker);<br>
+<br>
        spin_lock_irq(&amp;vb-&gt;stop_update_lock);<br>
        vb-&gt;stop_update = true;<br>
        spin_unlock_irq(&amp;vb-&gt;stop_update_lock);<br>
-- <br>
2.24.1<br>
<br>
</blockquote></div></div>

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v1 3/3] virtio-balloon: Switch back to OOM handler for VIRTIO_BALLOON_F_DEFLATE_ON_OOM
  2020-02-05 22:37   ` Tyler Sanderson
@ 2020-02-05 22:52     ` David Hildenbrand
  2020-02-05 23:06       ` Tyler Sanderson
  0 siblings, 1 reply; 27+ messages in thread
From: David Hildenbrand @ 2020-02-05 22:52 UTC (permalink / raw)
  To: Tyler Sanderson
  Cc: David Hildenbrand, linux-kernel, linux-mm, virtualization,
	Michael S . Tsirkin, Wei Wang, Alexander Duyck, David Rientjes,
	Nadav Amit, Michal Hocko

[-- Attachment #1: Type: text/plain, Size: 10424 bytes --]



> Am 05.02.2020 um 23:37 schrieb Tyler Sanderson <tysand@google.com>:
> 
> 
> 
> 
>> On Wed, Feb 5, 2020 at 8:34 AM David Hildenbrand <david@redhat.com> wrote:
>> Commit 71994620bb25 ("virtio_balloon: replace oom notifier with shrinker")
>> changed the behavior when deflation happens automatically. Instead of
>> deflating when called by the OOM handler, the shrinker is used.
>> 
>> However, the balloon is not simply some slab cache that should be
>> shrunk when under memory pressure. The shrinker does not have a concept of
>> priorities, so this behavior cannot be configured.
>> 
>> There was a report that this results in undesired side effects when
>> inflating the balloon to shrink the page cache. [1]
>>         "When inflating the balloon against page cache (i.e. no free memory
>>          remains) vmscan.c will both shrink page cache, but also invoke the
>>          shrinkers -- including the balloon's shrinker. So the balloon
>>          driver allocates memory which requires reclaim, vmscan gets this
>>          memory by shrinking the balloon, and then the driver adds the
>>          memory back to the balloon. Basically a busy no-op."
>> 
>> The name "deflate on OOM" makes it pretty clear when deflation should
>> happen - after other approaches to reclaim memory failed, not while
>> reclaiming. This allows to minimize the footprint of a guest - memory
>> will only be taken out of the balloon when really needed.
>> 
>> Especially, a drop_slab() will result in the whole balloon getting
>> deflated - undesired. While handling it via the OOM handler might not be
>> perfect, it keeps existing behavior. If we want a different behavior, then
>> we need a new feature bit and document it properly (although, there should
>> be a clear use case and the intended effects should be well described).
>> 
>> Keep using the shrinker for VIRTIO_BALLOON_F_FREE_PAGE_HINT, because
>> this has no such side effects. Always register the shrinker with
>> VIRTIO_BALLOON_F_FREE_PAGE_HINT now. We are always allowed to reuse free
>> pages that are still to be processed by the guest. The hypervisor takes
>> care of identifying and resolving possible races between processing a
>> hinting request and the guest reusing a page.
>> 
>> In contrast to pre commit 71994620bb25 ("virtio_balloon: replace oom
>> notifier with shrinker"), don't add a moodule parameter to configure the
>> number of pages to deflate on OOM. Can be re-added if really needed.
>> Also, pay attention that leak_balloon() returns the number of 4k pages -
>> convert it properly in virtio_balloon_oom_notify().
>> 
>> Note1: using the OOM handler is frowned upon, but it really is what we
>>        need for this feature.
>> 
>> Note2: without VIRTIO_BALLOON_F_MUST_TELL_HOST (iow, always with QEMU) we
>>        could actually skip sending deflation requests to our hypervisor,
>>        making the OOM path *very* simple. Besically freeing pages and
>>        updating the balloon. If the communication with the host ever
>>        becomes a problem on this call path.
>> 
>> [1] https://www.spinics.net/lists/linux-virtualization/msg40863.html
>> 
>> Reported-by: Tyler Sanderson <tysand@google.com>
>> Cc: Michael S. Tsirkin <mst@redhat.com>
>> Cc: Wei Wang <wei.w.wang@intel.com>
>> Cc: Alexander Duyck <alexander.h.duyck@linux.intel.com>
>> Cc: David Rientjes <rientjes@google.com>
>> Cc: Nadav Amit <namit@vmware.com>
>> Cc: Michal Hocko <mhocko@kernel.org>
>> Signed-off-by: David Hildenbrand <david@redhat.com>
>> ---
>>  drivers/virtio/virtio_balloon.c | 107 +++++++++++++-------------------
>>  1 file changed, 44 insertions(+), 63 deletions(-)
>> 
>> diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
>> index 7e5d84caeb94..e7b18f556c5e 100644
>> --- a/drivers/virtio/virtio_balloon.c
>> +++ b/drivers/virtio/virtio_balloon.c
>> @@ -14,6 +14,7 @@
>>  #include <linux/slab.h>
>>  #include <linux/module.h>
>>  #include <linux/balloon_compaction.h>
>> +#include <linux/oom.h>
>>  #include <linux/wait.h>
>>  #include <linux/mm.h>
>>  #include <linux/mount.h>
>> @@ -27,7 +28,9 @@
>>   */
>>  #define VIRTIO_BALLOON_PAGES_PER_PAGE (unsigned)(PAGE_SIZE >> VIRTIO_BALLOON_PFN_SHIFT)
>>  #define VIRTIO_BALLOON_ARRAY_PFNS_MAX 256
>> -#define VIRTBALLOON_OOM_NOTIFY_PRIORITY 80
>> +/* Maximum number of (4k) pages to deflate on OOM notifications. */
>> +#define VIRTIO_BALLOON_OOM_NR_PAGES 256
>> +#define VIRTIO_BALLOON_OOM_NOTIFY_PRIORITY 80
>> 
>>  #define VIRTIO_BALLOON_FREE_PAGE_ALLOC_FLAG (__GFP_NORETRY | __GFP_NOWARN | \
>>                                              __GFP_NOMEMALLOC)
>> @@ -112,8 +115,11 @@ struct virtio_balloon {
>>         /* Memory statistics */
>>         struct virtio_balloon_stat stats[VIRTIO_BALLOON_S_NR];
>> 
>> -       /* To register a shrinker to shrink memory upon memory pressure */
>> +       /* Shrinker to return free pages - VIRTIO_BALLOON_F_FREE_PAGE_HINT */
>>         struct shrinker shrinker;
>> +
>> +       /* OOM notifier to deflate on OOM - VIRTIO_BALLOON_F_DEFLATE_ON_OOM */
>> +       struct notifier_block oom_nb;
>>  };
>> 
>>  static struct virtio_device_id id_table[] = {
>> @@ -786,50 +792,13 @@ static unsigned long shrink_free_pages(struct virtio_balloon *vb,
>>         return blocks_freed * VIRTIO_BALLOON_HINT_BLOCK_PAGES;
>>  }
>> 
>> -static unsigned long leak_balloon_pages(struct virtio_balloon *vb,
>> -                                          unsigned long pages_to_free)
>> -{
>> -       return leak_balloon(vb, pages_to_free * VIRTIO_BALLOON_PAGES_PER_PAGE) /
>> -               VIRTIO_BALLOON_PAGES_PER_PAGE;
>> -}
>> -
>> -static unsigned long shrink_balloon_pages(struct virtio_balloon *vb,
>> -                                         unsigned long pages_to_free)
>> -{
>> -       unsigned long pages_freed = 0;
>> -
>> -       /*
>> -        * One invocation of leak_balloon can deflate at most
>> -        * VIRTIO_BALLOON_ARRAY_PFNS_MAX balloon pages, so we call it
>> -        * multiple times to deflate pages till reaching pages_to_free.
>> -        */
>> -       while (vb->num_pages && pages_freed < pages_to_free)
>> -               pages_freed += leak_balloon_pages(vb,
>> -                                                 pages_to_free - pages_freed);
>> -
>> -       update_balloon_size(vb);
>> -
>> -       return pages_freed;
>> -}
>> -
>>  static unsigned long virtio_balloon_shrinker_scan(struct shrinker *shrinker,
>>                                                   struct shrink_control *sc)
>>  {
>> -       unsigned long pages_to_free, pages_freed = 0;
>>         struct virtio_balloon *vb = container_of(shrinker,
>>                                         struct virtio_balloon, shrinker);
>> 
>> -       pages_to_free = sc->nr_to_scan;
>> -
>> -       if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT))
>> -               pages_freed = shrink_free_pages(vb, pages_to_free);
>> -
>> -       if (pages_freed >= pages_to_free)
>> -               return pages_freed;
>> -
>> -       pages_freed += shrink_balloon_pages(vb, pages_to_free - pages_freed);
>> -
>> -       return pages_freed;
>> +       return shrink_free_pages(vb, sc->nr_to_scan);
>>  }
>> 
>>  static unsigned long virtio_balloon_shrinker_count(struct shrinker *shrinker,
>> @@ -837,26 +806,22 @@ static unsigned long virtio_balloon_shrinker_count(struct shrinker *shrinker,
>>  {
>>         struct virtio_balloon *vb = container_of(shrinker,
>>                                         struct virtio_balloon, shrinker);
>> -       unsigned long count;
>> -
>> -       count = vb->num_pages / VIRTIO_BALLOON_PAGES_PER_PAGE;
>> -       count += vb->num_free_page_blocks * VIRTIO_BALLOON_HINT_BLOCK_PAGES;
>> 
>> -       return count;
>> +       return vb->num_free_page_blocks * VIRTIO_BALLOON_HINT_BLOCK_PAGES;
>>  }
>> 
>> -static void virtio_balloon_unregister_shrinker(struct virtio_balloon *vb)
>> +static int virtio_balloon_oom_notify(struct notifier_block *nb,
>> +                                    unsigned long dummy, void *parm)
>>  {
>> -       unregister_shrinker(&vb->shrinker);
>> -}
>> +       struct virtio_balloon *vb = container_of(nb,
>> +                                                struct virtio_balloon, oom_nb);
>> +       unsigned long *freed = parm;
>> 
>> -static int virtio_balloon_register_shrinker(struct virtio_balloon *vb)
>> -{
>> -       vb->shrinker.scan_objects = virtio_balloon_shrinker_scan;
>> -       vb->shrinker.count_objects = virtio_balloon_shrinker_count;
>> -       vb->shrinker.seeks = DEFAULT_SEEKS;
>> +       *freed += leak_balloon(vb, VIRTIO_BALLOON_OOM_NR_PAGES) /
>> +                 VIRTIO_BALLOON_PAGES_PER_PAGE;
>> +       update_balloon_size(vb);
>> 
>> -       return register_shrinker(&vb->shrinker);
>> +       return NOTIFY_OK;
>>  }
>> 
>>  static int virtballoon_probe(struct virtio_device *vdev)
>> @@ -933,22 +898,35 @@ static int virtballoon_probe(struct virtio_device *vdev)
>>                         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
>> -        * shrinker needs to be registered to relieve memory pressure.
>> -        */
>> -       if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM)) {
>> -               err = virtio_balloon_register_shrinker(vb);
>> +
>> +               /*
>> +                * We're allowed to reuse any free pages, even if they are
>> +                * still to be processed by the host.
> It is important to clarify that pages that are on the inflate queue but not ACKed by the host (the queue entry has not been returned) are _not_ okay to reuse.
> If the host is going to do something destructive to the page (like deback it) then that needs to happen before the entry is returned.

While you are correct, this comment is in the „free page hinting“ section/if (not obvious by looking at the diff only), so it does not apply to inflate/deflate queues - but only free pages that are getting hinted. Or am I misreading your suggestion/missing something?

Thanks!



[-- Attachment #2: Type: text/html, Size: 14853 bytes --]

<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body dir="auto"><div dir="ltr"><br></div><div dir="ltr"><br><blockquote type="cite">Am 05.02.2020 um 23:37 schrieb Tyler Sanderson &lt;tysand@google.com&gt;:<br><br></blockquote></div><blockquote type="cite"><div dir="ltr"><div dir="ltr"><div dir="ltr"><br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, Feb 5, 2020 at 8:34 AM David Hildenbrand &lt;<a href="mailto:david@redhat.com">david@redhat.com</a>&gt; wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Commit 71994620bb25 ("virtio_balloon: replace oom notifier with shrinker")<br>
changed the behavior when deflation happens automatically. Instead of<br>
deflating when called by the OOM handler, the shrinker is used.<br>
<br>
However, the balloon is not simply some slab cache that should be<br>
shrunk when under memory pressure. The shrinker does not have a concept of<br>
priorities, so this behavior cannot be configured.<br>
<br>
There was a report that this results in undesired side effects when<br>
inflating the balloon to shrink the page cache. [1]<br>
&nbsp; &nbsp; &nbsp; &nbsp; "When inflating the balloon against page cache (i.e. no free memory<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;remains) vmscan.c will both shrink page cache, but also invoke the<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;shrinkers -- including the balloon's shrinker. So the balloon<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;driver allocates memory which requires reclaim, vmscan gets this<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;memory by shrinking the balloon, and then the driver adds the<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;memory back to the balloon. Basically a busy no-op."<br>
<br>
The name "deflate on OOM" makes it pretty clear when deflation should<br>
happen - after other approaches to reclaim memory failed, not while<br>
reclaiming. This allows to minimize the footprint of a guest - memory<br>
will only be taken out of the balloon when really needed.<br>
<br>
Especially, a drop_slab() will result in the whole balloon getting<br>
deflated - undesired. While handling it via the OOM handler might not be<br>
perfect, it keeps existing behavior. If we want a different behavior, then<br>
we need a new feature bit and document it properly (although, there should<br>
be a clear use case and the intended effects should be well described).<br>
<br>
Keep using the shrinker for VIRTIO_BALLOON_F_FREE_PAGE_HINT, because<br>
this has no such side effects. Always register the shrinker with<br>
VIRTIO_BALLOON_F_FREE_PAGE_HINT now. We are always allowed to reuse free<br>
pages that are still to be processed by the guest. The hypervisor takes<br>
care of identifying and resolving possible races between processing a<br>
hinting request and the guest reusing a page.<br>
<br>
In contrast to pre commit 71994620bb25 ("virtio_balloon: replace oom<br>
notifier with shrinker"), don't add a moodule parameter to configure the<br>
number of pages to deflate on OOM. Can be re-added if really needed.<br>
Also, pay attention that leak_balloon() returns the number of 4k pages -<br>
convert it properly in virtio_balloon_oom_notify().<br>
<br>
Note1: using the OOM handler is frowned upon, but it really is what we<br>
&nbsp; &nbsp; &nbsp; &nbsp;need for this feature.<br>
<br>
Note2: without VIRTIO_BALLOON_F_MUST_TELL_HOST (iow, always with QEMU) we<br>
&nbsp; &nbsp; &nbsp; &nbsp;could actually skip sending deflation requests to our hypervisor,<br>
&nbsp; &nbsp; &nbsp; &nbsp;making the OOM path *very* simple. Besically freeing pages and<br>
&nbsp; &nbsp; &nbsp; &nbsp;updating the balloon. If the communication with the host ever<br>
&nbsp; &nbsp; &nbsp; &nbsp;becomes a problem on this call path.<br>
<br>
[1] <a href="https://www.spinics.net/lists/linux-virtualization/msg40863.html" rel="noreferrer" target="_blank">https://www.spinics.net/lists/linux-virtualization/msg40863.html</a><br>
<br>
Reported-by: Tyler Sanderson &lt;<a href="mailto:tysand@google.com" target="_blank">tysand@google.com</a>&gt;<br>
Cc: Michael S. Tsirkin &lt;<a href="mailto:mst@redhat.com" target="_blank">mst@redhat.com</a>&gt;<br>
Cc: Wei Wang &lt;<a href="mailto:wei.w.wang@intel.com" target="_blank">wei.w.wang@intel.com</a>&gt;<br>
Cc: Alexander Duyck &lt;<a href="mailto:alexander.h.duyck@linux.intel.com" target="_blank">alexander.h.duyck@linux.intel.com</a>&gt;<br>
Cc: David Rientjes &lt;<a href="mailto:rientjes@google.com" target="_blank">rientjes@google.com</a>&gt;<br>
Cc: Nadav Amit &lt;<a href="mailto:namit@vmware.com" target="_blank">namit@vmware.com</a>&gt;<br>
Cc: Michal Hocko &lt;<a href="mailto:mhocko@kernel.org" target="_blank">mhocko@kernel.org</a>&gt;<br>
Signed-off-by: David Hildenbrand &lt;<a href="mailto:david@redhat.com" target="_blank">david@redhat.com</a>&gt;<br>
---<br>
&nbsp;drivers/virtio/virtio_balloon.c | 107 +++++++++++++-------------------<br>
&nbsp;1 file changed, 44 insertions(+), 63 deletions(-)<br>
<br>
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c<br>
index 7e5d84caeb94..e7b18f556c5e 100644<br>
--- a/drivers/virtio/virtio_balloon.c<br>
+++ b/drivers/virtio/virtio_balloon.c<br>
@@ -14,6 +14,7 @@<br>
&nbsp;#include &lt;linux/slab.h&gt;<br>
&nbsp;#include &lt;linux/module.h&gt;<br>
&nbsp;#include &lt;linux/balloon_compaction.h&gt;<br>
+#include &lt;linux/oom.h&gt;<br>
&nbsp;#include &lt;linux/wait.h&gt;<br>
&nbsp;#include &lt;linux/mm.h&gt;<br>
&nbsp;#include &lt;linux/mount.h&gt;<br>
@@ -27,7 +28,9 @@<br>
&nbsp; */<br>
&nbsp;#define VIRTIO_BALLOON_PAGES_PER_PAGE (unsigned)(PAGE_SIZE &gt;&gt; VIRTIO_BALLOON_PFN_SHIFT)<br>
&nbsp;#define VIRTIO_BALLOON_ARRAY_PFNS_MAX 256<br>
-#define VIRTBALLOON_OOM_NOTIFY_PRIORITY 80<br>
+/* Maximum number of (4k) pages to deflate on OOM notifications. */<br>
+#define VIRTIO_BALLOON_OOM_NR_PAGES 256<br>
+#define VIRTIO_BALLOON_OOM_NOTIFY_PRIORITY 80<br>
<br>
&nbsp;#define VIRTIO_BALLOON_FREE_PAGE_ALLOC_FLAG (__GFP_NORETRY | __GFP_NOWARN | \<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;__GFP_NOMEMALLOC)<br>
@@ -112,8 +115,11 @@ struct virtio_balloon {<br>
&nbsp; &nbsp; &nbsp; &nbsp; /* Memory statistics */<br>
&nbsp; &nbsp; &nbsp; &nbsp; struct virtio_balloon_stat stats[VIRTIO_BALLOON_S_NR];<br>
<br>
-&nbsp; &nbsp; &nbsp; &nbsp;/* To register a shrinker to shrink memory upon memory pressure */<br>
+&nbsp; &nbsp; &nbsp; &nbsp;/* Shrinker to return free pages - VIRTIO_BALLOON_F_FREE_PAGE_HINT */<br>
&nbsp; &nbsp; &nbsp; &nbsp; struct shrinker shrinker;<br>
+<br>
+&nbsp; &nbsp; &nbsp; &nbsp;/* OOM notifier to deflate on OOM - VIRTIO_BALLOON_F_DEFLATE_ON_OOM */<br>
+&nbsp; &nbsp; &nbsp; &nbsp;struct notifier_block oom_nb;<br>
&nbsp;};<br>
<br>
&nbsp;static struct virtio_device_id id_table[] = {<br>
@@ -786,50 +792,13 @@ static unsigned long shrink_free_pages(struct virtio_balloon *vb,<br>
&nbsp; &nbsp; &nbsp; &nbsp; return blocks_freed * VIRTIO_BALLOON_HINT_BLOCK_PAGES;<br>
&nbsp;}<br>
<br>
-static unsigned long leak_balloon_pages(struct virtio_balloon *vb,<br>
-&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; unsigned long pages_to_free)<br>
-{<br>
-&nbsp; &nbsp; &nbsp; &nbsp;return leak_balloon(vb, pages_to_free * VIRTIO_BALLOON_PAGES_PER_PAGE) /<br>
-&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;VIRTIO_BALLOON_PAGES_PER_PAGE;<br>
-}<br>
-<br>
-static unsigned long shrink_balloon_pages(struct virtio_balloon *vb,<br>
-&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;unsigned long pages_to_free)<br>
-{<br>
-&nbsp; &nbsp; &nbsp; &nbsp;unsigned long pages_freed = 0;<br>
-<br>
-&nbsp; &nbsp; &nbsp; &nbsp;/*<br>
-&nbsp; &nbsp; &nbsp; &nbsp; * One invocation of leak_balloon can deflate at most<br>
-&nbsp; &nbsp; &nbsp; &nbsp; * VIRTIO_BALLOON_ARRAY_PFNS_MAX balloon pages, so we call it<br>
-&nbsp; &nbsp; &nbsp; &nbsp; * multiple times to deflate pages till reaching pages_to_free.<br>
-&nbsp; &nbsp; &nbsp; &nbsp; */<br>
-&nbsp; &nbsp; &nbsp; &nbsp;while (vb-&gt;num_pages &amp;&amp; pages_freed &lt; pages_to_free)<br>
-&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;pages_freed += leak_balloon_pages(vb,<br>
-&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;pages_to_free - pages_freed);<br>
-<br>
-&nbsp; &nbsp; &nbsp; &nbsp;update_balloon_size(vb);<br>
-<br>
-&nbsp; &nbsp; &nbsp; &nbsp;return pages_freed;<br>
-}<br>
-<br>
&nbsp;static unsigned long virtio_balloon_shrinker_scan(struct shrinker *shrinker,<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; struct shrink_control *sc)<br>
&nbsp;{<br>
-&nbsp; &nbsp; &nbsp; &nbsp;unsigned long pages_to_free, pages_freed = 0;<br>
&nbsp; &nbsp; &nbsp; &nbsp; struct virtio_balloon *vb = container_of(shrinker,<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; struct virtio_balloon, shrinker);<br>
<br>
-&nbsp; &nbsp; &nbsp; &nbsp;pages_to_free = sc-&gt;nr_to_scan;<br>
-<br>
-&nbsp; &nbsp; &nbsp; &nbsp;if (virtio_has_feature(vb-&gt;vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT))<br>
-&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;pages_freed = shrink_free_pages(vb, pages_to_free);<br>
-<br>
-&nbsp; &nbsp; &nbsp; &nbsp;if (pages_freed &gt;= pages_to_free)<br>
-&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return pages_freed;<br>
-<br>
-&nbsp; &nbsp; &nbsp; &nbsp;pages_freed += shrink_balloon_pages(vb, pages_to_free - pages_freed);<br>
-<br>
-&nbsp; &nbsp; &nbsp; &nbsp;return pages_freed;<br>
+&nbsp; &nbsp; &nbsp; &nbsp;return shrink_free_pages(vb, sc-&gt;nr_to_scan);<br>
&nbsp;}<br>
<br>
&nbsp;static unsigned long virtio_balloon_shrinker_count(struct shrinker *shrinker,<br>
@@ -837,26 +806,22 @@ static unsigned long virtio_balloon_shrinker_count(struct shrinker *shrinker,<br>
&nbsp;{<br>
&nbsp; &nbsp; &nbsp; &nbsp; struct virtio_balloon *vb = container_of(shrinker,<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; struct virtio_balloon, shrinker);<br>
-&nbsp; &nbsp; &nbsp; &nbsp;unsigned long count;<br>
-<br>
-&nbsp; &nbsp; &nbsp; &nbsp;count = vb-&gt;num_pages / VIRTIO_BALLOON_PAGES_PER_PAGE;<br>
-&nbsp; &nbsp; &nbsp; &nbsp;count += vb-&gt;num_free_page_blocks * VIRTIO_BALLOON_HINT_BLOCK_PAGES;<br>
<br>
-&nbsp; &nbsp; &nbsp; &nbsp;return count;<br>
+&nbsp; &nbsp; &nbsp; &nbsp;return vb-&gt;num_free_page_blocks * VIRTIO_BALLOON_HINT_BLOCK_PAGES;<br>
&nbsp;}<br>
<br>
-static void virtio_balloon_unregister_shrinker(struct virtio_balloon *vb)<br>
+static int virtio_balloon_oom_notify(struct notifier_block *nb,<br>
+&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; unsigned long dummy, void *parm)<br>
&nbsp;{<br>
-&nbsp; &nbsp; &nbsp; &nbsp;unregister_shrinker(&amp;vb-&gt;shrinker);<br>
-}<br>
+&nbsp; &nbsp; &nbsp; &nbsp;struct virtio_balloon *vb = container_of(nb,<br>
+&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; struct virtio_balloon, oom_nb);<br>
+&nbsp; &nbsp; &nbsp; &nbsp;unsigned long *freed = parm;<br>
<br>
-static int virtio_balloon_register_shrinker(struct virtio_balloon *vb)<br>
-{<br>
-&nbsp; &nbsp; &nbsp; &nbsp;vb-&gt;shrinker.scan_objects = virtio_balloon_shrinker_scan;<br>
-&nbsp; &nbsp; &nbsp; &nbsp;vb-&gt;shrinker.count_objects = virtio_balloon_shrinker_count;<br>
-&nbsp; &nbsp; &nbsp; &nbsp;vb-&gt;shrinker.seeks = DEFAULT_SEEKS;<br>
+&nbsp; &nbsp; &nbsp; &nbsp;*freed += leak_balloon(vb, VIRTIO_BALLOON_OOM_NR_PAGES) /<br>
+&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;VIRTIO_BALLOON_PAGES_PER_PAGE;<br>
+&nbsp; &nbsp; &nbsp; &nbsp;update_balloon_size(vb);<br>
<br>
-&nbsp; &nbsp; &nbsp; &nbsp;return register_shrinker(&amp;vb-&gt;shrinker);<br>
+&nbsp; &nbsp; &nbsp; &nbsp;return NOTIFY_OK;<br>
&nbsp;}<br>
<br>
&nbsp;static int virtballoon_probe(struct virtio_device *vdev)<br>
@@ -933,22 +898,35 @@ static int virtballoon_probe(struct virtio_device *vdev)<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; virtio_cwrite(vb-&gt;vdev, struct virtio_balloon_config,<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; poison_val, &amp;poison_val);<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br>
-&nbsp; &nbsp; &nbsp; &nbsp;}<br>
-&nbsp; &nbsp; &nbsp; &nbsp;/*<br>
-&nbsp; &nbsp; &nbsp; &nbsp; * We continue to use VIRTIO_BALLOON_F_DEFLATE_ON_OOM to decide if a<br>
-&nbsp; &nbsp; &nbsp; &nbsp; * shrinker needs to be registered to relieve memory pressure.<br>
-&nbsp; &nbsp; &nbsp; &nbsp; */<br>
-&nbsp; &nbsp; &nbsp; &nbsp;if (virtio_has_feature(vb-&gt;vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM)) {<br>
-&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;err = virtio_balloon_register_shrinker(vb);<br>
+<br>
+&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;/*<br>
+&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; * We're allowed to reuse any free pages, even if they are<br>
+&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; * still to be processed by the host.<br></blockquote><div>It is important to clarify that pages that are on the inflate queue but not ACKed by the host (the queue entry has not been returned) are _not_ okay to reuse.</div><div>If the host is going to do something destructive to the page (like deback it) then that needs to happen before the entry is returned.</div></div></div>
</div></blockquote><br><div>While you are correct, this comment is in the „free page hinting“ section/if (not obvious by looking at the diff only), so it does not apply to inflate/deflate queues - but only free pages that are getting hinted. Or am I misreading your suggestion/missing something?</div><div><br></div><div>Thanks!</div><div><br></div><div><br></div></body></html>

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v1 3/3] virtio-balloon: Switch back to OOM handler for VIRTIO_BALLOON_F_DEFLATE_ON_OOM
  2020-02-05 22:52     ` David Hildenbrand
@ 2020-02-05 23:06       ` Tyler Sanderson
  0 siblings, 0 replies; 27+ messages in thread
From: Tyler Sanderson @ 2020-02-05 23:06 UTC (permalink / raw)
  To: David Hildenbrand
  Cc: linux-kernel, linux-mm, virtualization, Michael S . Tsirkin,
	Wei Wang, Alexander Duyck, David Rientjes, Nadav Amit,
	Michal Hocko

[-- Attachment #1: Type: text/plain, Size: 10633 bytes --]

On Wed, Feb 5, 2020 at 2:52 PM David Hildenbrand <david@redhat.com> wrote:

>
>
> Am 05.02.2020 um 23:37 schrieb Tyler Sanderson <tysand@google.com>:
>
> 
>
>
> On Wed, Feb 5, 2020 at 8:34 AM David Hildenbrand <david@redhat.com> wrote:
>
>> Commit 71994620bb25 ("virtio_balloon: replace oom notifier with shrinker")
>> changed the behavior when deflation happens automatically. Instead of
>> deflating when called by the OOM handler, the shrinker is used.
>>
>> However, the balloon is not simply some slab cache that should be
>> shrunk when under memory pressure. The shrinker does not have a concept of
>> priorities, so this behavior cannot be configured.
>>
>> There was a report that this results in undesired side effects when
>> inflating the balloon to shrink the page cache. [1]
>>         "When inflating the balloon against page cache (i.e. no free
>> memory
>>          remains) vmscan.c will both shrink page cache, but also invoke
>> the
>>          shrinkers -- including the balloon's shrinker. So the balloon
>>          driver allocates memory which requires reclaim, vmscan gets this
>>          memory by shrinking the balloon, and then the driver adds the
>>          memory back to the balloon. Basically a busy no-op."
>>
>> The name "deflate on OOM" makes it pretty clear when deflation should
>> happen - after other approaches to reclaim memory failed, not while
>> reclaiming. This allows to minimize the footprint of a guest - memory
>> will only be taken out of the balloon when really needed.
>>
>> Especially, a drop_slab() will result in the whole balloon getting
>> deflated - undesired. While handling it via the OOM handler might not be
>> perfect, it keeps existing behavior. If we want a different behavior, then
>> we need a new feature bit and document it properly (although, there should
>> be a clear use case and the intended effects should be well described).
>>
>> Keep using the shrinker for VIRTIO_BALLOON_F_FREE_PAGE_HINT, because
>> this has no such side effects. Always register the shrinker with
>> VIRTIO_BALLOON_F_FREE_PAGE_HINT now. We are always allowed to reuse free
>> pages that are still to be processed by the guest. The hypervisor takes
>> care of identifying and resolving possible races between processing a
>> hinting request and the guest reusing a page.
>>
>> In contrast to pre commit 71994620bb25 ("virtio_balloon: replace oom
>> notifier with shrinker"), don't add a moodule parameter to configure the
>> number of pages to deflate on OOM. Can be re-added if really needed.
>> Also, pay attention that leak_balloon() returns the number of 4k pages -
>> convert it properly in virtio_balloon_oom_notify().
>>
>> Note1: using the OOM handler is frowned upon, but it really is what we
>>        need for this feature.
>>
>> Note2: without VIRTIO_BALLOON_F_MUST_TELL_HOST (iow, always with QEMU) we
>>        could actually skip sending deflation requests to our hypervisor,
>>        making the OOM path *very* simple. Besically freeing pages and
>>        updating the balloon. If the communication with the host ever
>>        becomes a problem on this call path.
>>
>> [1] https://www.spinics.net/lists/linux-virtualization/msg40863.html
>>
>> Reported-by: Tyler Sanderson <tysand@google.com>
>> Cc: Michael S. Tsirkin <mst@redhat.com>
>> Cc: Wei Wang <wei.w.wang@intel.com>
>> Cc: Alexander Duyck <alexander.h.duyck@linux.intel.com>
>> Cc: David Rientjes <rientjes@google.com>
>> Cc: Nadav Amit <namit@vmware.com>
>> Cc: Michal Hocko <mhocko@kernel.org>
>> Signed-off-by: David Hildenbrand <david@redhat.com>
>> ---
>>  drivers/virtio/virtio_balloon.c | 107 +++++++++++++-------------------
>>  1 file changed, 44 insertions(+), 63 deletions(-)
>>
>> diff --git a/drivers/virtio/virtio_balloon.c
>> b/drivers/virtio/virtio_balloon.c
>> index 7e5d84caeb94..e7b18f556c5e 100644
>> --- a/drivers/virtio/virtio_balloon.c
>> +++ b/drivers/virtio/virtio_balloon.c
>> @@ -14,6 +14,7 @@
>>  #include <linux/slab.h>
>>  #include <linux/module.h>
>>  #include <linux/balloon_compaction.h>
>> +#include <linux/oom.h>
>>  #include <linux/wait.h>
>>  #include <linux/mm.h>
>>  #include <linux/mount.h>
>> @@ -27,7 +28,9 @@
>>   */
>>  #define VIRTIO_BALLOON_PAGES_PER_PAGE (unsigned)(PAGE_SIZE >>
>> VIRTIO_BALLOON_PFN_SHIFT)
>>  #define VIRTIO_BALLOON_ARRAY_PFNS_MAX 256
>> -#define VIRTBALLOON_OOM_NOTIFY_PRIORITY 80
>> +/* Maximum number of (4k) pages to deflate on OOM notifications. */
>> +#define VIRTIO_BALLOON_OOM_NR_PAGES 256
>> +#define VIRTIO_BALLOON_OOM_NOTIFY_PRIORITY 80
>>
>>  #define VIRTIO_BALLOON_FREE_PAGE_ALLOC_FLAG (__GFP_NORETRY |
>> __GFP_NOWARN | \
>>                                              __GFP_NOMEMALLOC)
>> @@ -112,8 +115,11 @@ struct virtio_balloon {
>>         /* Memory statistics */
>>         struct virtio_balloon_stat stats[VIRTIO_BALLOON_S_NR];
>>
>> -       /* To register a shrinker to shrink memory upon memory pressure */
>> +       /* Shrinker to return free pages -
>> VIRTIO_BALLOON_F_FREE_PAGE_HINT */
>>         struct shrinker shrinker;
>> +
>> +       /* OOM notifier to deflate on OOM -
>> VIRTIO_BALLOON_F_DEFLATE_ON_OOM */
>> +       struct notifier_block oom_nb;
>>  };
>>
>>  static struct virtio_device_id id_table[] = {
>> @@ -786,50 +792,13 @@ static unsigned long shrink_free_pages(struct
>> virtio_balloon *vb,
>>         return blocks_freed * VIRTIO_BALLOON_HINT_BLOCK_PAGES;
>>  }
>>
>> -static unsigned long leak_balloon_pages(struct virtio_balloon *vb,
>> -                                          unsigned long pages_to_free)
>> -{
>> -       return leak_balloon(vb, pages_to_free *
>> VIRTIO_BALLOON_PAGES_PER_PAGE) /
>> -               VIRTIO_BALLOON_PAGES_PER_PAGE;
>> -}
>> -
>> -static unsigned long shrink_balloon_pages(struct virtio_balloon *vb,
>> -                                         unsigned long pages_to_free)
>> -{
>> -       unsigned long pages_freed = 0;
>> -
>> -       /*
>> -        * One invocation of leak_balloon can deflate at most
>> -        * VIRTIO_BALLOON_ARRAY_PFNS_MAX balloon pages, so we call it
>> -        * multiple times to deflate pages till reaching pages_to_free.
>> -        */
>> -       while (vb->num_pages && pages_freed < pages_to_free)
>> -               pages_freed += leak_balloon_pages(vb,
>> -                                                 pages_to_free -
>> pages_freed);
>> -
>> -       update_balloon_size(vb);
>> -
>> -       return pages_freed;
>> -}
>> -
>>  static unsigned long virtio_balloon_shrinker_scan(struct shrinker
>> *shrinker,
>>                                                   struct shrink_control
>> *sc)
>>  {
>> -       unsigned long pages_to_free, pages_freed = 0;
>>         struct virtio_balloon *vb = container_of(shrinker,
>>                                         struct virtio_balloon, shrinker);
>>
>> -       pages_to_free = sc->nr_to_scan;
>> -
>> -       if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT))
>> -               pages_freed = shrink_free_pages(vb, pages_to_free);
>> -
>> -       if (pages_freed >= pages_to_free)
>> -               return pages_freed;
>> -
>> -       pages_freed += shrink_balloon_pages(vb, pages_to_free -
>> pages_freed);
>> -
>> -       return pages_freed;
>> +       return shrink_free_pages(vb, sc->nr_to_scan);
>>  }
>>
>>  static unsigned long virtio_balloon_shrinker_count(struct shrinker
>> *shrinker,
>> @@ -837,26 +806,22 @@ static unsigned long
>> virtio_balloon_shrinker_count(struct shrinker *shrinker,
>>  {
>>         struct virtio_balloon *vb = container_of(shrinker,
>>                                         struct virtio_balloon, shrinker);
>> -       unsigned long count;
>> -
>> -       count = vb->num_pages / VIRTIO_BALLOON_PAGES_PER_PAGE;
>> -       count += vb->num_free_page_blocks *
>> VIRTIO_BALLOON_HINT_BLOCK_PAGES;
>>
>> -       return count;
>> +       return vb->num_free_page_blocks * VIRTIO_BALLOON_HINT_BLOCK_PAGES;
>>  }
>>
>> -static void virtio_balloon_unregister_shrinker(struct virtio_balloon *vb)
>> +static int virtio_balloon_oom_notify(struct notifier_block *nb,
>> +                                    unsigned long dummy, void *parm)
>>  {
>> -       unregister_shrinker(&vb->shrinker);
>> -}
>> +       struct virtio_balloon *vb = container_of(nb,
>> +                                                struct virtio_balloon,
>> oom_nb);
>> +       unsigned long *freed = parm;
>>
>> -static int virtio_balloon_register_shrinker(struct virtio_balloon *vb)
>> -{
>> -       vb->shrinker.scan_objects = virtio_balloon_shrinker_scan;
>> -       vb->shrinker.count_objects = virtio_balloon_shrinker_count;
>> -       vb->shrinker.seeks = DEFAULT_SEEKS;
>> +       *freed += leak_balloon(vb, VIRTIO_BALLOON_OOM_NR_PAGES) /
>> +                 VIRTIO_BALLOON_PAGES_PER_PAGE;
>> +       update_balloon_size(vb);
>>
>> -       return register_shrinker(&vb->shrinker);
>> +       return NOTIFY_OK;
>>  }
>>
>>  static int virtballoon_probe(struct virtio_device *vdev)
>> @@ -933,22 +898,35 @@ static int virtballoon_probe(struct virtio_device
>> *vdev)
>>                         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
>> -        * shrinker needs to be registered to relieve memory pressure.
>> -        */
>> -       if (virtio_has_feature(vb->vdev,
>> VIRTIO_BALLOON_F_DEFLATE_ON_OOM)) {
>> -               err = virtio_balloon_register_shrinker(vb);
>> +
>> +               /*
>> +                * We're allowed to reuse any free pages, even if they are
>> +                * still to be processed by the host.
>>
> It is important to clarify that pages that are on the inflate queue but
> not ACKed by the host (the queue entry has not been returned) are _not_
> okay to reuse.
> If the host is going to do something destructive to the page (like deback
> it) then that needs to happen before the entry is returned.
>
>
> While you are correct, this comment is in the „free page hinting“
> section/if (not obvious by looking at the diff only), so it does not apply
> to inflate/deflate queues - but only free pages that are getting hinted. Or
> am I misreading your suggestion/missing something?
>
Ah you are right. Thanks!

>
> Thanks!
>
>
>

[-- Attachment #2: Type: text/html, Size: 13158 bytes --]

<div dir="ltr"><div dir="ltr"><br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, Feb 5, 2020 at 2:52 PM David Hildenbrand &lt;<a href="mailto:david@redhat.com">david@redhat.com</a>&gt; wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="auto"><div dir="ltr"><br></div><div dir="ltr"><br><blockquote type="cite">Am 05.02.2020 um 23:37 schrieb Tyler Sanderson &lt;<a href="mailto:tysand@google.com" target="_blank">tysand@google.com</a>&gt;:<br><br></blockquote></div><blockquote type="cite"><div dir="ltr"><div dir="ltr"><div dir="ltr"><br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, Feb 5, 2020 at 8:34 AM David Hildenbrand &lt;<a href="mailto:david@redhat.com" target="_blank">david@redhat.com</a>&gt; wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Commit 71994620bb25 (&quot;virtio_balloon: replace oom notifier with shrinker&quot;)<br>
changed the behavior when deflation happens automatically. Instead of<br>
deflating when called by the OOM handler, the shrinker is used.<br>
<br>
However, the balloon is not simply some slab cache that should be<br>
shrunk when under memory pressure. The shrinker does not have a concept of<br>
priorities, so this behavior cannot be configured.<br>
<br>
There was a report that this results in undesired side effects when<br>
inflating the balloon to shrink the page cache. [1]<br>
        &quot;When inflating the balloon against page cache (i.e. no free memory<br>
         remains) vmscan.c will both shrink page cache, but also invoke the<br>
         shrinkers -- including the balloon&#39;s shrinker. So the balloon<br>
         driver allocates memory which requires reclaim, vmscan gets this<br>
         memory by shrinking the balloon, and then the driver adds the<br>
         memory back to the balloon. Basically a busy no-op.&quot;<br>
<br>
The name &quot;deflate on OOM&quot; makes it pretty clear when deflation should<br>
happen - after other approaches to reclaim memory failed, not while<br>
reclaiming. This allows to minimize the footprint of a guest - memory<br>
will only be taken out of the balloon when really needed.<br>
<br>
Especially, a drop_slab() will result in the whole balloon getting<br>
deflated - undesired. While handling it via the OOM handler might not be<br>
perfect, it keeps existing behavior. If we want a different behavior, then<br>
we need a new feature bit and document it properly (although, there should<br>
be a clear use case and the intended effects should be well described).<br>
<br>
Keep using the shrinker for VIRTIO_BALLOON_F_FREE_PAGE_HINT, because<br>
this has no such side effects. Always register the shrinker with<br>
VIRTIO_BALLOON_F_FREE_PAGE_HINT now. We are always allowed to reuse free<br>
pages that are still to be processed by the guest. The hypervisor takes<br>
care of identifying and resolving possible races between processing a<br>
hinting request and the guest reusing a page.<br>
<br>
In contrast to pre commit 71994620bb25 (&quot;virtio_balloon: replace oom<br>
notifier with shrinker&quot;), don&#39;t add a moodule parameter to configure the<br>
number of pages to deflate on OOM. Can be re-added if really needed.<br>
Also, pay attention that leak_balloon() returns the number of 4k pages -<br>
convert it properly in virtio_balloon_oom_notify().<br>
<br>
Note1: using the OOM handler is frowned upon, but it really is what we<br>
       need for this feature.<br>
<br>
Note2: without VIRTIO_BALLOON_F_MUST_TELL_HOST (iow, always with QEMU) we<br>
       could actually skip sending deflation requests to our hypervisor,<br>
       making the OOM path *very* simple. Besically freeing pages and<br>
       updating the balloon. If the communication with the host ever<br>
       becomes a problem on this call path.<br>
<br>
[1] <a href="https://www.spinics.net/lists/linux-virtualization/msg40863.html" rel="noreferrer" target="_blank">https://www.spinics.net/lists/linux-virtualization/msg40863.html</a><br>
<br>
Reported-by: Tyler Sanderson &lt;<a href="mailto:tysand@google.com" target="_blank">tysand@google.com</a>&gt;<br>
Cc: Michael S. Tsirkin &lt;<a href="mailto:mst@redhat.com" target="_blank">mst@redhat.com</a>&gt;<br>
Cc: Wei Wang &lt;<a href="mailto:wei.w.wang@intel.com" target="_blank">wei.w.wang@intel.com</a>&gt;<br>
Cc: Alexander Duyck &lt;<a href="mailto:alexander.h.duyck@linux.intel.com" target="_blank">alexander.h.duyck@linux.intel.com</a>&gt;<br>
Cc: David Rientjes &lt;<a href="mailto:rientjes@google.com" target="_blank">rientjes@google.com</a>&gt;<br>
Cc: Nadav Amit &lt;<a href="mailto:namit@vmware.com" target="_blank">namit@vmware.com</a>&gt;<br>
Cc: Michal Hocko &lt;<a href="mailto:mhocko@kernel.org" target="_blank">mhocko@kernel.org</a>&gt;<br>
Signed-off-by: David Hildenbrand &lt;<a href="mailto:david@redhat.com" target="_blank">david@redhat.com</a>&gt;<br>
---<br>
 drivers/virtio/virtio_balloon.c | 107 +++++++++++++-------------------<br>
 1 file changed, 44 insertions(+), 63 deletions(-)<br>
<br>
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c<br>
index 7e5d84caeb94..e7b18f556c5e 100644<br>
--- a/drivers/virtio/virtio_balloon.c<br>
+++ b/drivers/virtio/virtio_balloon.c<br>
@@ -14,6 +14,7 @@<br>
 #include &lt;linux/slab.h&gt;<br>
 #include &lt;linux/module.h&gt;<br>
 #include &lt;linux/balloon_compaction.h&gt;<br>
+#include &lt;linux/oom.h&gt;<br>
 #include &lt;linux/wait.h&gt;<br>
 #include &lt;linux/mm.h&gt;<br>
 #include &lt;linux/mount.h&gt;<br>
@@ -27,7 +28,9 @@<br>
  */<br>
 #define VIRTIO_BALLOON_PAGES_PER_PAGE (unsigned)(PAGE_SIZE &gt;&gt; VIRTIO_BALLOON_PFN_SHIFT)<br>
 #define VIRTIO_BALLOON_ARRAY_PFNS_MAX 256<br>
-#define VIRTBALLOON_OOM_NOTIFY_PRIORITY 80<br>
+/* Maximum number of (4k) pages to deflate on OOM notifications. */<br>
+#define VIRTIO_BALLOON_OOM_NR_PAGES 256<br>
+#define VIRTIO_BALLOON_OOM_NOTIFY_PRIORITY 80<br>
<br>
 #define VIRTIO_BALLOON_FREE_PAGE_ALLOC_FLAG (__GFP_NORETRY | __GFP_NOWARN | \<br>
                                             __GFP_NOMEMALLOC)<br>
@@ -112,8 +115,11 @@ struct virtio_balloon {<br>
        /* Memory statistics */<br>
        struct virtio_balloon_stat stats[VIRTIO_BALLOON_S_NR];<br>
<br>
-       /* To register a shrinker to shrink memory upon memory pressure */<br>
+       /* Shrinker to return free pages - VIRTIO_BALLOON_F_FREE_PAGE_HINT */<br>
        struct shrinker shrinker;<br>
+<br>
+       /* OOM notifier to deflate on OOM - VIRTIO_BALLOON_F_DEFLATE_ON_OOM */<br>
+       struct notifier_block oom_nb;<br>
 };<br>
<br>
 static struct virtio_device_id id_table[] = {<br>
@@ -786,50 +792,13 @@ static unsigned long shrink_free_pages(struct virtio_balloon *vb,<br>
        return blocks_freed * VIRTIO_BALLOON_HINT_BLOCK_PAGES;<br>
 }<br>
<br>
-static unsigned long leak_balloon_pages(struct virtio_balloon *vb,<br>
-                                          unsigned long pages_to_free)<br>
-{<br>
-       return leak_balloon(vb, pages_to_free * VIRTIO_BALLOON_PAGES_PER_PAGE) /<br>
-               VIRTIO_BALLOON_PAGES_PER_PAGE;<br>
-}<br>
-<br>
-static unsigned long shrink_balloon_pages(struct virtio_balloon *vb,<br>
-                                         unsigned long pages_to_free)<br>
-{<br>
-       unsigned long pages_freed = 0;<br>
-<br>
-       /*<br>
-        * One invocation of leak_balloon can deflate at most<br>
-        * VIRTIO_BALLOON_ARRAY_PFNS_MAX balloon pages, so we call it<br>
-        * multiple times to deflate pages till reaching pages_to_free.<br>
-        */<br>
-       while (vb-&gt;num_pages &amp;&amp; pages_freed &lt; pages_to_free)<br>
-               pages_freed += leak_balloon_pages(vb,<br>
-                                                 pages_to_free - pages_freed);<br>
-<br>
-       update_balloon_size(vb);<br>
-<br>
-       return pages_freed;<br>
-}<br>
-<br>
 static unsigned long virtio_balloon_shrinker_scan(struct shrinker *shrinker,<br>
                                                  struct shrink_control *sc)<br>
 {<br>
-       unsigned long pages_to_free, pages_freed = 0;<br>
        struct virtio_balloon *vb = container_of(shrinker,<br>
                                        struct virtio_balloon, shrinker);<br>
<br>
-       pages_to_free = sc-&gt;nr_to_scan;<br>
-<br>
-       if (virtio_has_feature(vb-&gt;vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT))<br>
-               pages_freed = shrink_free_pages(vb, pages_to_free);<br>
-<br>
-       if (pages_freed &gt;= pages_to_free)<br>
-               return pages_freed;<br>
-<br>
-       pages_freed += shrink_balloon_pages(vb, pages_to_free - pages_freed);<br>
-<br>
-       return pages_freed;<br>
+       return shrink_free_pages(vb, sc-&gt;nr_to_scan);<br>
 }<br>
<br>
 static unsigned long virtio_balloon_shrinker_count(struct shrinker *shrinker,<br>
@@ -837,26 +806,22 @@ static unsigned long virtio_balloon_shrinker_count(struct shrinker *shrinker,<br>
 {<br>
        struct virtio_balloon *vb = container_of(shrinker,<br>
                                        struct virtio_balloon, shrinker);<br>
-       unsigned long count;<br>
-<br>
-       count = vb-&gt;num_pages / VIRTIO_BALLOON_PAGES_PER_PAGE;<br>
-       count += vb-&gt;num_free_page_blocks * VIRTIO_BALLOON_HINT_BLOCK_PAGES;<br>
<br>
-       return count;<br>
+       return vb-&gt;num_free_page_blocks * VIRTIO_BALLOON_HINT_BLOCK_PAGES;<br>
 }<br>
<br>
-static void virtio_balloon_unregister_shrinker(struct virtio_balloon *vb)<br>
+static int virtio_balloon_oom_notify(struct notifier_block *nb,<br>
+                                    unsigned long dummy, void *parm)<br>
 {<br>
-       unregister_shrinker(&amp;vb-&gt;shrinker);<br>
-}<br>
+       struct virtio_balloon *vb = container_of(nb,<br>
+                                                struct virtio_balloon, oom_nb);<br>
+       unsigned long *freed = parm;<br>
<br>
-static int virtio_balloon_register_shrinker(struct virtio_balloon *vb)<br>
-{<br>
-       vb-&gt;shrinker.scan_objects = virtio_balloon_shrinker_scan;<br>
-       vb-&gt;shrinker.count_objects = virtio_balloon_shrinker_count;<br>
-       vb-&gt;shrinker.seeks = DEFAULT_SEEKS;<br>
+       *freed += leak_balloon(vb, VIRTIO_BALLOON_OOM_NR_PAGES) /<br>
+                 VIRTIO_BALLOON_PAGES_PER_PAGE;<br>
+       update_balloon_size(vb);<br>
<br>
-       return register_shrinker(&amp;vb-&gt;shrinker);<br>
+       return NOTIFY_OK;<br>
 }<br>
<br>
 static int virtballoon_probe(struct virtio_device *vdev)<br>
@@ -933,22 +898,35 @@ static int virtballoon_probe(struct virtio_device *vdev)<br>
                        virtio_cwrite(vb-&gt;vdev, struct virtio_balloon_config,<br>
                                      poison_val, &amp;poison_val);<br>
                }<br>
-       }<br>
-       /*<br>
-        * We continue to use VIRTIO_BALLOON_F_DEFLATE_ON_OOM to decide if a<br>
-        * shrinker needs to be registered to relieve memory pressure.<br>
-        */<br>
-       if (virtio_has_feature(vb-&gt;vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM)) {<br>
-               err = virtio_balloon_register_shrinker(vb);<br>
+<br>
+               /*<br>
+                * We&#39;re allowed to reuse any free pages, even if they are<br>
+                * still to be processed by the host.<br></blockquote><div>It is important to clarify that pages that are on the inflate queue but not ACKed by the host (the queue entry has not been returned) are _not_ okay to reuse.</div><div>If the host is going to do something destructive to the page (like deback it) then that needs to happen before the entry is returned.</div></div></div>
</div></blockquote><br><div>While you are correct, this comment is in the „free page hinting“ section/if (not obvious by looking at the diff only), so it does not apply to inflate/deflate queues - but only free pages that are getting hinted. Or am I misreading your suggestion/missing something?</div></div></blockquote><div>Ah you are right. Thanks! </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="auto"><div><br></div><div>Thanks!</div><div><br></div><div><br></div></div></blockquote></div></div>

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v1 3/3] virtio-balloon: Switch back to OOM handler for VIRTIO_BALLOON_F_DEFLATE_ON_OOM
  2020-02-05 16:34 ` [PATCH v1 3/3] virtio-balloon: Switch back to OOM handler for VIRTIO_BALLOON_F_DEFLATE_ON_OOM David Hildenbrand
  2020-02-05 22:37   ` Tyler Sanderson
@ 2020-02-06  7:40   ` Michael S. Tsirkin
  2020-02-06  8:42     ` David Hildenbrand
  2020-02-06  8:57   ` Wang, Wei W
                     ` (4 subsequent siblings)
  6 siblings, 1 reply; 27+ messages in thread
From: Michael S. Tsirkin @ 2020-02-06  7:40 UTC (permalink / raw)
  To: David Hildenbrand
  Cc: linux-kernel, linux-mm, virtualization, Tyler Sanderson,
	Wei Wang, Alexander Duyck, David Rientjes, Nadav Amit,
	Michal Hocko

On Wed, Feb 05, 2020 at 05:34:02PM +0100, David Hildenbrand wrote:
> Commit 71994620bb25 ("virtio_balloon: replace oom notifier with shrinker")
> changed the behavior when deflation happens automatically. Instead of
> deflating when called by the OOM handler, the shrinker is used.
> 
> However, the balloon is not simply some slab cache that should be
> shrunk when under memory pressure. The shrinker does not have a concept of
> priorities, so this behavior cannot be configured.
> 
> There was a report that this results in undesired side effects when
> inflating the balloon to shrink the page cache. [1]
> 	"When inflating the balloon against page cache (i.e. no free memory
> 	 remains) vmscan.c will both shrink page cache, but also invoke the
> 	 shrinkers -- including the balloon's shrinker. So the balloon
> 	 driver allocates memory which requires reclaim, vmscan gets this
> 	 memory by shrinking the balloon, and then the driver adds the
> 	 memory back to the balloon. Basically a busy no-op."
> 
> The name "deflate on OOM" makes it pretty clear when deflation should
> happen - after other approaches to reclaim memory failed, not while
> reclaiming. This allows to minimize the footprint of a guest - memory
> will only be taken out of the balloon when really needed.
> 
> Especially, a drop_slab() will result in the whole balloon getting
> deflated - undesired. While handling it via the OOM handler might not be
> perfect, it keeps existing behavior. If we want a different behavior, then
> we need a new feature bit and document it properly (although, there should
> be a clear use case and the intended effects should be well described).
> 
> Keep using the shrinker for VIRTIO_BALLOON_F_FREE_PAGE_HINT, because
> this has no such side effects. Always register the shrinker with
> VIRTIO_BALLOON_F_FREE_PAGE_HINT now. We are always allowed to reuse free
> pages that are still to be processed by the guest. The hypervisor takes
> care of identifying and resolving possible races between processing a
> hinting request and the guest reusing a page.
> 
> In contrast to pre commit 71994620bb25 ("virtio_balloon: replace oom
> notifier with shrinker"), don't add a moodule parameter to configure the
> number of pages to deflate on OOM. Can be re-added if really needed.

I agree. And to make this case even stronger:

The oom_pages module parameter was known to be broken: whatever its
value, we return at most VIRTIO_BALLOON_ARRAY_PFNS_MAX.  So module
parameter values > 256 never worked, and it seems highly unlikely that
freeing 1Mbyte on OOM is too aggressive.
There was a patch
 virtio-balloon: deflate up to oom_pages on OOM
by Wei Wang to try to fix it:
https://lore.kernel.org/r/1508500466-21165-3-git-send-email-wei.w.wang@intel.com
but this was dropped.

> Also, pay attention that leak_balloon() returns the number of 4k pages -
> convert it properly in virtio_balloon_oom_notify().

Oh. So it was returning a wrong value originally (before 71994620bb25).
However what really matters for notifiers is whether the value is 0 -
whether we made progress. So it's cosmetic.

> Note1: using the OOM handler is frowned upon, but it really is what we
>        need for this feature.

Quite. However, I went back researching why we dropped the OOM notifier,
and found this:

https://lore.kernel.org/r/1508500466-21165-2-git-send-email-wei.w.wang@intel.com

To quote from there:

The balloon_lock was used to synchronize the access demand to elements
of struct virtio_balloon and its queue operations (please see commit
e22504296d). This prevents the concurrent run of the leak_balloon and
fill_balloon functions, thereby resulting in a deadlock issue on OOM:

fill_balloon: take balloon_lock and wait for OOM to get some memory;
oom_notify: release some inflated memory via leak_balloon();
leak_balloon: wait for balloon_lock to be released by fill_balloon.





> Note2: without VIRTIO_BALLOON_F_MUST_TELL_HOST (iow, always with QEMU) we
>        could actually skip sending deflation requests to our hypervisor,
>        making the OOM path *very* simple. Besically freeing pages and
>        updating the balloon.

Well not exactly. !VIRTIO_BALLOON_F_MUST_TELL_HOST does not actually
mean "never tell host". It means "host will not discard pages in the
balloon, you can defer host notification until after use".

This was the original implementation:

+       if (vb->tell_host_first) {
+               tell_host(vb, vb->deflate_vq);
+               release_pages_by_pfn(vb->pfns, vb->num_pfns);
+       } else {
+               release_pages_by_pfn(vb->pfns, vb->num_pfns);
+               tell_host(vb, vb->deflate_vq);
+       }
+}

I don't know whether completely skipping host notifications
when !VIRTIO_BALLOON_F_MUST_TELL_HOST will break any hosts.

>	 If the communication with the host ever
>        becomes a problem on this call path.
> 
> [1] https://www.spinics.net/lists/linux-virtualization/msg40863.html
> 
> Reported-by: Tyler Sanderson <tysand@google.com>
> Cc: Michael S. Tsirkin <mst@redhat.com>
> Cc: Wei Wang <wei.w.wang@intel.com>
> Cc: Alexander Duyck <alexander.h.duyck@linux.intel.com>
> Cc: David Rientjes <rientjes@google.com>
> Cc: Nadav Amit <namit@vmware.com>
> Cc: Michal Hocko <mhocko@kernel.org>
> Signed-off-by: David Hildenbrand <david@redhat.com>
> ---
>  drivers/virtio/virtio_balloon.c | 107 +++++++++++++-------------------
>  1 file changed, 44 insertions(+), 63 deletions(-)
> 
> diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
> index 7e5d84caeb94..e7b18f556c5e 100644
> --- a/drivers/virtio/virtio_balloon.c
> +++ b/drivers/virtio/virtio_balloon.c
> @@ -14,6 +14,7 @@
>  #include <linux/slab.h>
>  #include <linux/module.h>
>  #include <linux/balloon_compaction.h>
> +#include <linux/oom.h>
>  #include <linux/wait.h>
>  #include <linux/mm.h>
>  #include <linux/mount.h>
> @@ -27,7 +28,9 @@
>   */
>  #define VIRTIO_BALLOON_PAGES_PER_PAGE (unsigned)(PAGE_SIZE >> VIRTIO_BALLOON_PFN_SHIFT)
>  #define VIRTIO_BALLOON_ARRAY_PFNS_MAX 256
> -#define VIRTBALLOON_OOM_NOTIFY_PRIORITY 80
> +/* Maximum number of (4k) pages to deflate on OOM notifications. */
> +#define VIRTIO_BALLOON_OOM_NR_PAGES 256
> +#define VIRTIO_BALLOON_OOM_NOTIFY_PRIORITY 80
>  
>  #define VIRTIO_BALLOON_FREE_PAGE_ALLOC_FLAG (__GFP_NORETRY | __GFP_NOWARN | \
>  					     __GFP_NOMEMALLOC)
> @@ -112,8 +115,11 @@ struct virtio_balloon {
>  	/* Memory statistics */
>  	struct virtio_balloon_stat stats[VIRTIO_BALLOON_S_NR];
>  
> -	/* To register a shrinker to shrink memory upon memory pressure */
> +	/* Shrinker to return free pages - VIRTIO_BALLOON_F_FREE_PAGE_HINT */
>  	struct shrinker shrinker;
> +
> +	/* OOM notifier to deflate on OOM - VIRTIO_BALLOON_F_DEFLATE_ON_OOM */
> +	struct notifier_block oom_nb;
>  };
>  
>  static struct virtio_device_id id_table[] = {
> @@ -786,50 +792,13 @@ static unsigned long shrink_free_pages(struct virtio_balloon *vb,
>  	return blocks_freed * VIRTIO_BALLOON_HINT_BLOCK_PAGES;
>  }
>  
> -static unsigned long leak_balloon_pages(struct virtio_balloon *vb,
> -                                          unsigned long pages_to_free)
> -{
> -	return leak_balloon(vb, pages_to_free * VIRTIO_BALLOON_PAGES_PER_PAGE) /
> -		VIRTIO_BALLOON_PAGES_PER_PAGE;
> -}
> -
> -static unsigned long shrink_balloon_pages(struct virtio_balloon *vb,
> -					  unsigned long pages_to_free)
> -{
> -	unsigned long pages_freed = 0;
> -
> -	/*
> -	 * One invocation of leak_balloon can deflate at most
> -	 * VIRTIO_BALLOON_ARRAY_PFNS_MAX balloon pages, so we call it
> -	 * multiple times to deflate pages till reaching pages_to_free.
> -	 */
> -	while (vb->num_pages && pages_freed < pages_to_free)
> -		pages_freed += leak_balloon_pages(vb,
> -						  pages_to_free - pages_freed);
> -
> -	update_balloon_size(vb);
> -
> -	return pages_freed;
> -}
> -
>  static unsigned long virtio_balloon_shrinker_scan(struct shrinker *shrinker,
>  						  struct shrink_control *sc)
>  {
> -	unsigned long pages_to_free, pages_freed = 0;
>  	struct virtio_balloon *vb = container_of(shrinker,
>  					struct virtio_balloon, shrinker);
>  
> -	pages_to_free = sc->nr_to_scan;
> -
> -	if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT))
> -		pages_freed = shrink_free_pages(vb, pages_to_free);
> -
> -	if (pages_freed >= pages_to_free)
> -		return pages_freed;
> -
> -	pages_freed += shrink_balloon_pages(vb, pages_to_free - pages_freed);
> -
> -	return pages_freed;
> +	return shrink_free_pages(vb, sc->nr_to_scan);
>  }
>  
>  static unsigned long virtio_balloon_shrinker_count(struct shrinker *shrinker,
> @@ -837,26 +806,22 @@ static unsigned long virtio_balloon_shrinker_count(struct shrinker *shrinker,
>  {
>  	struct virtio_balloon *vb = container_of(shrinker,
>  					struct virtio_balloon, shrinker);
> -	unsigned long count;
> -
> -	count = vb->num_pages / VIRTIO_BALLOON_PAGES_PER_PAGE;
> -	count += vb->num_free_page_blocks * VIRTIO_BALLOON_HINT_BLOCK_PAGES;
>  
> -	return count;
> +	return vb->num_free_page_blocks * VIRTIO_BALLOON_HINT_BLOCK_PAGES;
>  }
>  
> -static void virtio_balloon_unregister_shrinker(struct virtio_balloon *vb)
> +static int virtio_balloon_oom_notify(struct notifier_block *nb,
> +				     unsigned long dummy, void *parm)
>  {
> -	unregister_shrinker(&vb->shrinker);
> -}
> +	struct virtio_balloon *vb = container_of(nb,
> +						 struct virtio_balloon, oom_nb);
> +	unsigned long *freed = parm;
>  
> -static int virtio_balloon_register_shrinker(struct virtio_balloon *vb)
> -{
> -	vb->shrinker.scan_objects = virtio_balloon_shrinker_scan;
> -	vb->shrinker.count_objects = virtio_balloon_shrinker_count;
> -	vb->shrinker.seeks = DEFAULT_SEEKS;
> +	*freed += leak_balloon(vb, VIRTIO_BALLOON_OOM_NR_PAGES) /
> +		  VIRTIO_BALLOON_PAGES_PER_PAGE;
> +	update_balloon_size(vb);
>  
> -	return register_shrinker(&vb->shrinker);
> +	return NOTIFY_OK;
>  }
>  
>  static int virtballoon_probe(struct virtio_device *vdev)
> @@ -933,22 +898,35 @@ static int virtballoon_probe(struct virtio_device *vdev)
>  			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
> -	 * shrinker needs to be registered to relieve memory pressure.
> -	 */
> -	if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM)) {
> -		err = virtio_balloon_register_shrinker(vb);
> +
> +		/*
> +		 * We're allowed to reuse any free pages, even if they are
> +		 * still to be processed by the host.
> +		 */
> +		vb->shrinker.scan_objects = virtio_balloon_shrinker_scan;
> +		vb->shrinker.count_objects = virtio_balloon_shrinker_count;
> +		vb->shrinker.seeks = DEFAULT_SEEKS;
> +		err = register_shrinker(&vb->shrinker);
>  		if (err)
>  			goto out_del_balloon_wq;
>  	}
> +	if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM)) {
> +		vb->oom_nb.notifier_call = virtio_balloon_oom_notify;
> +		vb->oom_nb.priority = VIRTIO_BALLOON_OOM_NOTIFY_PRIORITY;
> +		err = register_oom_notifier(&vb->oom_nb);
> +		if (err < 0)
> +			goto out_unregister_shrinker;
> +	}
> +
>  	virtio_device_ready(vdev);
>  
>  	if (towards_target(vb))
>  		virtballoon_changed(vdev);
>  	return 0;
>  
> +out_unregister_shrinker:
> +	if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT))
> +		unregister_shrinker(&vb->shrinker);
>  out_del_balloon_wq:
>  	if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT))
>  		destroy_workqueue(vb->balloon_wq);
> @@ -987,8 +965,11 @@ static void virtballoon_remove(struct virtio_device *vdev)
>  {
>  	struct virtio_balloon *vb = vdev->priv;
>  
> -	if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM))
> -		virtio_balloon_unregister_shrinker(vb);
> +	if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM))
> +		unregister_oom_notifier(&vb->oom_nb);
> +	if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT))
> +		unregister_shrinker(&vb->shrinker);
> +
>  	spin_lock_irq(&vb->stop_update_lock);
>  	vb->stop_update = true;
>  	spin_unlock_irq(&vb->stop_update_lock);
> -- 
> 2.24.1



^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v1 1/3] virtio-balloon: Fix memory leak when unloading while hinting is in progress
  2020-02-05 16:34 ` [PATCH v1 1/3] virtio-balloon: Fix memory leak when unloading while hinting is in progress David Hildenbrand
@ 2020-02-06  8:36   ` Michael S. Tsirkin
  0 siblings, 0 replies; 27+ messages in thread
From: Michael S. Tsirkin @ 2020-02-06  8:36 UTC (permalink / raw)
  To: David Hildenbrand
  Cc: linux-kernel, linux-mm, virtualization, Jason Wang, Wei Wang, Liang Li

On Wed, Feb 05, 2020 at 05:34:00PM +0100, David Hildenbrand wrote:
> When unloading the driver while hinting is in progress, we will not
> release the free page blocks back to MM, resulting in a memory leak.
> 
> Fixes: 86a559787e6f ("virtio-balloon: VIRTIO_BALLOON_F_FREE_PAGE_HINT")
> Cc: "Michael S. Tsirkin" <mst@redhat.com>
> Cc: Jason Wang <jasowang@redhat.com>
> Cc: Wei Wang <wei.w.wang@intel.com>
> Cc: Liang Li <liang.z.li@intel.com>
> Signed-off-by: David Hildenbrand <david@redhat.com>

Applied, thanks!

> ---
>  drivers/virtio/virtio_balloon.c | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
> index 8e400ece9273..abef2306c899 100644
> --- a/drivers/virtio/virtio_balloon.c
> +++ b/drivers/virtio/virtio_balloon.c
> @@ -968,6 +968,10 @@ static void remove_common(struct virtio_balloon *vb)
>  		leak_balloon(vb, vb->num_pages);
>  	update_balloon_size(vb);
>  
> +	/* There might be free pages that are being reported: release them. */
> +	if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT))
> +		return_free_pages_to_mm(vb, ULONG_MAX);
> +
>  	/* Now we reset the device so we can clean up the queues. */
>  	vb->vdev->config->reset(vb->vdev);
>  
> -- 
> 2.24.1



^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v1 2/3] virtio_balloon: Fix memory leaks on errors in virtballoon_probe()
  2020-02-05 16:34 ` [PATCH v1 2/3] virtio_balloon: Fix memory leaks on errors in virtballoon_probe() David Hildenbrand
@ 2020-02-06  8:36   ` Michael S. Tsirkin
  0 siblings, 0 replies; 27+ messages in thread
From: Michael S. Tsirkin @ 2020-02-06  8:36 UTC (permalink / raw)
  To: David Hildenbrand
  Cc: linux-kernel, linux-mm, virtualization, Jason Wang, Wei Wang, Liang Li

On Wed, Feb 05, 2020 at 05:34:01PM +0100, David Hildenbrand wrote:
> We forget to put the inode and unmount the kernfs used for compaction.
> 
> Fixes: 71994620bb25 ("virtio_balloon: replace oom notifier with shrinker")
> Cc: "Michael S. Tsirkin" <mst@redhat.com>
> Cc: Jason Wang <jasowang@redhat.com>
> Cc: Wei Wang <wei.w.wang@intel.com>
> Cc: Liang Li <liang.z.li@intel.com>
> Signed-off-by: David Hildenbrand <david@redhat.com>

Applied, thanks!

> ---
>  drivers/virtio/virtio_balloon.c | 13 +++++++++----
>  1 file changed, 9 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
> index abef2306c899..7e5d84caeb94 100644
> --- a/drivers/virtio/virtio_balloon.c
> +++ b/drivers/virtio/virtio_balloon.c
> @@ -901,8 +901,7 @@ static int virtballoon_probe(struct virtio_device *vdev)
>  	vb->vb_dev_info.inode = alloc_anon_inode(balloon_mnt->mnt_sb);
>  	if (IS_ERR(vb->vb_dev_info.inode)) {
>  		err = PTR_ERR(vb->vb_dev_info.inode);
> -		kern_unmount(balloon_mnt);
> -		goto out_del_vqs;
> +		goto out_kern_unmount;
>  	}
>  	vb->vb_dev_info.inode->i_mapping->a_ops = &balloon_aops;
>  #endif
> @@ -913,13 +912,13 @@ static int virtballoon_probe(struct virtio_device *vdev)
>  		 */
>  		if (virtqueue_get_vring_size(vb->free_page_vq) < 2) {
>  			err = -ENOSPC;
> -			goto out_del_vqs;
> +			goto out_iput;
>  		}
>  		vb->balloon_wq = alloc_workqueue("balloon-wq",
>  					WQ_FREEZABLE | WQ_CPU_INTENSIVE, 0);
>  		if (!vb->balloon_wq) {
>  			err = -ENOMEM;
> -			goto out_del_vqs;
> +			goto out_iput;
>  		}
>  		INIT_WORK(&vb->report_free_page_work, report_free_page_func);
>  		vb->cmd_id_received_cache = VIRTIO_BALLOON_CMD_ID_STOP;
> @@ -953,6 +952,12 @@ static int virtballoon_probe(struct virtio_device *vdev)
>  out_del_balloon_wq:
>  	if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT))
>  		destroy_workqueue(vb->balloon_wq);
> +out_iput:
> +#ifdef CONFIG_BALLOON_COMPACTION
> +	iput(vb->vb_dev_info.inode);
> +out_kern_unmount:
> +	kern_unmount(balloon_mnt);
> +#endif
>  out_del_vqs:
>  	vdev->config->del_vqs(vdev);
>  out_free_vb:
> -- 
> 2.24.1



^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v1 3/3] virtio-balloon: Switch back to OOM handler for VIRTIO_BALLOON_F_DEFLATE_ON_OOM
  2020-02-06  7:40   ` Michael S. Tsirkin
@ 2020-02-06  8:42     ` David Hildenbrand
  2020-02-06  8:57       ` Michael S. Tsirkin
  0 siblings, 1 reply; 27+ messages in thread
From: David Hildenbrand @ 2020-02-06  8:42 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: linux-kernel, linux-mm, virtualization, Tyler Sanderson,
	Wei Wang, Alexander Duyck, David Rientjes, Nadav Amit,
	Michal Hocko

On 06.02.20 08:40, Michael S. Tsirkin wrote:
> On Wed, Feb 05, 2020 at 05:34:02PM +0100, David Hildenbrand wrote:
>> Commit 71994620bb25 ("virtio_balloon: replace oom notifier with shrinker")
>> changed the behavior when deflation happens automatically. Instead of
>> deflating when called by the OOM handler, the shrinker is used.
>>
>> However, the balloon is not simply some slab cache that should be
>> shrunk when under memory pressure. The shrinker does not have a concept of
>> priorities, so this behavior cannot be configured.
>>
>> There was a report that this results in undesired side effects when
>> inflating the balloon to shrink the page cache. [1]
>> 	"When inflating the balloon against page cache (i.e. no free memory
>> 	 remains) vmscan.c will both shrink page cache, but also invoke the
>> 	 shrinkers -- including the balloon's shrinker. So the balloon
>> 	 driver allocates memory which requires reclaim, vmscan gets this
>> 	 memory by shrinking the balloon, and then the driver adds the
>> 	 memory back to the balloon. Basically a busy no-op."
>>
>> The name "deflate on OOM" makes it pretty clear when deflation should
>> happen - after other approaches to reclaim memory failed, not while
>> reclaiming. This allows to minimize the footprint of a guest - memory
>> will only be taken out of the balloon when really needed.
>>
>> Especially, a drop_slab() will result in the whole balloon getting
>> deflated - undesired. While handling it via the OOM handler might not be
>> perfect, it keeps existing behavior. If we want a different behavior, then
>> we need a new feature bit and document it properly (although, there should
>> be a clear use case and the intended effects should be well described).
>>
>> Keep using the shrinker for VIRTIO_BALLOON_F_FREE_PAGE_HINT, because
>> this has no such side effects. Always register the shrinker with
>> VIRTIO_BALLOON_F_FREE_PAGE_HINT now. We are always allowed to reuse free
>> pages that are still to be processed by the guest. The hypervisor takes
>> care of identifying and resolving possible races between processing a
>> hinting request and the guest reusing a page.
>>
>> In contrast to pre commit 71994620bb25 ("virtio_balloon: replace oom
>> notifier with shrinker"), don't add a moodule parameter to configure the
>> number of pages to deflate on OOM. Can be re-added if really needed.
> 
> I agree. And to make this case even stronger:
> 
> The oom_pages module parameter was known to be broken: whatever its
> value, we return at most VIRTIO_BALLOON_ARRAY_PFNS_MAX.  So module
> parameter values > 256 never worked, and it seems highly unlikely that
> freeing 1Mbyte on OOM is too aggressive.
> There was a patch
>  virtio-balloon: deflate up to oom_pages on OOM
> by Wei Wang to try to fix it:
> https://lore.kernel.org/r/1508500466-21165-3-git-send-email-wei.w.wang@intel.com
> but this was dropped.

Makes sense. 1MB is usually good enough.

> 
>> Also, pay attention that leak_balloon() returns the number of 4k pages -
>> convert it properly in virtio_balloon_oom_notify().
> 
> Oh. So it was returning a wrong value originally (before 71994620bb25).
> However what really matters for notifiers is whether the value is 0 -
> whether we made progress. So it's cosmetic.

Yes, that's also my understanding.

> 
>> Note1: using the OOM handler is frowned upon, but it really is what we
>>        need for this feature.
> 
> Quite. However, I went back researching why we dropped the OOM notifier,
> and found this:
> 
> https://lore.kernel.org/r/1508500466-21165-2-git-send-email-wei.w.wang@intel.com
> 
> To quote from there:
> 
> The balloon_lock was used to synchronize the access demand to elements
> of struct virtio_balloon and its queue operations (please see commit
> e22504296d). This prevents the concurrent run of the leak_balloon and
> fill_balloon functions, thereby resulting in a deadlock issue on OOM:
> 
> fill_balloon: take balloon_lock and wait for OOM to get some memory;
> oom_notify: release some inflated memory via leak_balloon();
> leak_balloon: wait for balloon_lock to be released by fill_balloon.

fill_balloon does the allocation *before* taking the lock. tell_host()
should not allocate memory AFAIR. So how could this ever happen?

Anyhow, we could simply work around this by doing a trylock in
fill_balloon() and retrying in the caller. That should be easy. But I
want to understand first, how something like that would even be possible.

>> Note2: without VIRTIO_BALLOON_F_MUST_TELL_HOST (iow, always with QEMU) we
>>        could actually skip sending deflation requests to our hypervisor,
>>        making the OOM path *very* simple. Besically freeing pages and
>>        updating the balloon.
> 
> Well not exactly. !VIRTIO_BALLOON_F_MUST_TELL_HOST does not actually
> mean "never tell host". It means "host will not discard pages in the
> balloon, you can defer host notification until after use".
> 
> This was the original implementation:
> 
> +       if (vb->tell_host_first) {
> +               tell_host(vb, vb->deflate_vq);
> +               release_pages_by_pfn(vb->pfns, vb->num_pfns);
> +       } else {
> +               release_pages_by_pfn(vb->pfns, vb->num_pfns);
> +               tell_host(vb, vb->deflate_vq);
> +       }
> +}
> 
> I don't know whether completely skipping host notifications
> when !VIRTIO_BALLOON_F_MUST_TELL_HOST will break any hosts.

We discussed this already somewhere else, but here is again what I found.

commit bf50e69f63d21091e525185c3ae761412be0ba72
Author: Dave Hansen <dave@linux.vnet.ibm.com>
Date:   Thu Apr 7 10:43:25 2011 -0700

    virtio balloon: kill tell-host-first logic

    The virtio balloon driver has a VIRTIO_BALLOON_F_MUST_TELL_HOST
    feature bit.  Whenever the bit is set, the guest kernel must
    always tell the host before we free pages back to the allocator.
    Without this feature, we might free a page (and have another
    user touch it) while the hypervisor is unprepared for it.

    But, if the bit is _not_ set, we are under no obligation to
    reverse the order; we're under no obligation to do _anything_.
    As of now, qemu-kvm defines the bit, but doesn't set it.

MUST_TELL_HOST really means "no need to deflate, just reuse a page". We
should finally document this somewhere.

-- 
Thanks,

David / dhildenb



^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v1 3/3] virtio-balloon: Switch back to OOM handler for VIRTIO_BALLOON_F_DEFLATE_ON_OOM
  2020-02-06  8:42     ` David Hildenbrand
@ 2020-02-06  8:57       ` Michael S. Tsirkin
  2020-02-06  9:05         ` David Hildenbrand
  0 siblings, 1 reply; 27+ messages in thread
From: Michael S. Tsirkin @ 2020-02-06  8:57 UTC (permalink / raw)
  To: David Hildenbrand
  Cc: linux-kernel, linux-mm, virtualization, Tyler Sanderson,
	Wei Wang, Alexander Duyck, David Rientjes, Nadav Amit,
	Michal Hocko

On Thu, Feb 06, 2020 at 09:42:34AM +0100, David Hildenbrand wrote:
> On 06.02.20 08:40, Michael S. Tsirkin wrote:
> > On Wed, Feb 05, 2020 at 05:34:02PM +0100, David Hildenbrand wrote:
> >> Commit 71994620bb25 ("virtio_balloon: replace oom notifier with shrinker")
> >> changed the behavior when deflation happens automatically. Instead of
> >> deflating when called by the OOM handler, the shrinker is used.
> >>
> >> However, the balloon is not simply some slab cache that should be
> >> shrunk when under memory pressure. The shrinker does not have a concept of
> >> priorities, so this behavior cannot be configured.
> >>
> >> There was a report that this results in undesired side effects when
> >> inflating the balloon to shrink the page cache. [1]
> >> 	"When inflating the balloon against page cache (i.e. no free memory
> >> 	 remains) vmscan.c will both shrink page cache, but also invoke the
> >> 	 shrinkers -- including the balloon's shrinker. So the balloon
> >> 	 driver allocates memory which requires reclaim, vmscan gets this
> >> 	 memory by shrinking the balloon, and then the driver adds the
> >> 	 memory back to the balloon. Basically a busy no-op."
> >>
> >> The name "deflate on OOM" makes it pretty clear when deflation should
> >> happen - after other approaches to reclaim memory failed, not while
> >> reclaiming. This allows to minimize the footprint of a guest - memory
> >> will only be taken out of the balloon when really needed.
> >>
> >> Especially, a drop_slab() will result in the whole balloon getting
> >> deflated - undesired. While handling it via the OOM handler might not be
> >> perfect, it keeps existing behavior. If we want a different behavior, then
> >> we need a new feature bit and document it properly (although, there should
> >> be a clear use case and the intended effects should be well described).
> >>
> >> Keep using the shrinker for VIRTIO_BALLOON_F_FREE_PAGE_HINT, because
> >> this has no such side effects. Always register the shrinker with
> >> VIRTIO_BALLOON_F_FREE_PAGE_HINT now. We are always allowed to reuse free
> >> pages that are still to be processed by the guest. The hypervisor takes
> >> care of identifying and resolving possible races between processing a
> >> hinting request and the guest reusing a page.
> >>
> >> In contrast to pre commit 71994620bb25 ("virtio_balloon: replace oom
> >> notifier with shrinker"), don't add a moodule parameter to configure the
> >> number of pages to deflate on OOM. Can be re-added if really needed.
> > 
> > I agree. And to make this case even stronger:
> > 
> > The oom_pages module parameter was known to be broken: whatever its
> > value, we return at most VIRTIO_BALLOON_ARRAY_PFNS_MAX.  So module
> > parameter values > 256 never worked, and it seems highly unlikely that
> > freeing 1Mbyte on OOM is too aggressive.
> > There was a patch
> >  virtio-balloon: deflate up to oom_pages on OOM
> > by Wei Wang to try to fix it:
> > https://lore.kernel.org/r/1508500466-21165-3-git-send-email-wei.w.wang@intel.com
> > but this was dropped.
> 
> Makes sense. 1MB is usually good enough.
> 
> > 
> >> Also, pay attention that leak_balloon() returns the number of 4k pages -
> >> convert it properly in virtio_balloon_oom_notify().
> > 
> > Oh. So it was returning a wrong value originally (before 71994620bb25).
> > However what really matters for notifiers is whether the value is 0 -
> > whether we made progress. So it's cosmetic.
> 
> Yes, that's also my understanding.
> 
> > 
> >> Note1: using the OOM handler is frowned upon, but it really is what we
> >>        need for this feature.
> > 
> > Quite. However, I went back researching why we dropped the OOM notifier,
> > and found this:
> > 
> > https://lore.kernel.org/r/1508500466-21165-2-git-send-email-wei.w.wang@intel.com
> > 
> > To quote from there:
> > 
> > The balloon_lock was used to synchronize the access demand to elements
> > of struct virtio_balloon and its queue operations (please see commit
> > e22504296d). This prevents the concurrent run of the leak_balloon and
> > fill_balloon functions, thereby resulting in a deadlock issue on OOM:
> > 
> > fill_balloon: take balloon_lock and wait for OOM to get some memory;
> > oom_notify: release some inflated memory via leak_balloon();
> > leak_balloon: wait for balloon_lock to be released by fill_balloon.
> 
> fill_balloon does the allocation *before* taking the lock. tell_host()
> should not allocate memory AFAIR. So how could this ever happen?
> 
> Anyhow, we could simply work around this by doing a trylock in
> fill_balloon() and retrying in the caller. That should be easy. But I
> want to understand first, how something like that would even be possible.

Hmm it looks like you are right.  Sorry!


> >> Note2: without VIRTIO_BALLOON_F_MUST_TELL_HOST (iow, always with QEMU) we
> >>        could actually skip sending deflation requests to our hypervisor,
> >>        making the OOM path *very* simple. Besically freeing pages and
> >>        updating the balloon.
> > 
> > Well not exactly. !VIRTIO_BALLOON_F_MUST_TELL_HOST does not actually
> > mean "never tell host". It means "host will not discard pages in the
> > balloon, you can defer host notification until after use".
> > 
> > This was the original implementation:
> > 
> > +       if (vb->tell_host_first) {
> > +               tell_host(vb, vb->deflate_vq);
> > +               release_pages_by_pfn(vb->pfns, vb->num_pfns);
> > +       } else {
> > +               release_pages_by_pfn(vb->pfns, vb->num_pfns);
> > +               tell_host(vb, vb->deflate_vq);
> > +       }
> > +}
> > 
> > I don't know whether completely skipping host notifications
> > when !VIRTIO_BALLOON_F_MUST_TELL_HOST will break any hosts.
> 
> We discussed this already somewhere else, but here is again what I found.
> 
> commit bf50e69f63d21091e525185c3ae761412be0ba72
> Author: Dave Hansen <dave@linux.vnet.ibm.com>
> Date:   Thu Apr 7 10:43:25 2011 -0700
> 
>     virtio balloon: kill tell-host-first logic
> 
>     The virtio balloon driver has a VIRTIO_BALLOON_F_MUST_TELL_HOST
>     feature bit.  Whenever the bit is set, the guest kernel must
>     always tell the host before we free pages back to the allocator.
>     Without this feature, we might free a page (and have another
>     user touch it) while the hypervisor is unprepared for it.
> 
>     But, if the bit is _not_ set, we are under no obligation to
>     reverse the order; we're under no obligation to do _anything_.
>     As of now, qemu-kvm defines the bit, but doesn't set it.

Well this is not what the spec says in the end.
To continue that commit message:

    This patch makes the "tell host first" logic the only case.  This
    should make everybody happy, and reduce the amount of untested or
    untestable code in the kernel.

you can try proposing the change to the virtio TC, see what do others
think.


> MUST_TELL_HOST really means "no need to deflate, just reuse a page". We
> should finally document this somewhere.

I'm not sure it's not too late to change what that flag means.  If not
sending deflate messages at all is a useful optimization, it seems
safer to add a feature flag for that.

> -- 
> Thanks,
> 
> David / dhildenb



^ permalink raw reply	[flat|nested] 27+ messages in thread

* RE: [PATCH v1 3/3] virtio-balloon: Switch back to OOM handler for VIRTIO_BALLOON_F_DEFLATE_ON_OOM
  2020-02-05 16:34 ` [PATCH v1 3/3] virtio-balloon: Switch back to OOM handler for VIRTIO_BALLOON_F_DEFLATE_ON_OOM David Hildenbrand
  2020-02-05 22:37   ` Tyler Sanderson
  2020-02-06  7:40   ` Michael S. Tsirkin
@ 2020-02-06  8:57   ` Wang, Wei W
  2020-02-06  9:11   ` Michael S. Tsirkin
                     ` (3 subsequent siblings)
  6 siblings, 0 replies; 27+ messages in thread
From: Wang, Wei W @ 2020-02-06  8:57 UTC (permalink / raw)
  To: David Hildenbrand, linux-kernel
  Cc: linux-mm, virtualization, Tyler Sanderson, Michael S . Tsirkin,
	Alexander Duyck, David Rientjes, Nadav Amit, Michal Hocko

On Thursday, February 6, 2020 12:34 AM, David Hildenbrand wrote:
> Commit 71994620bb25 ("virtio_balloon: replace oom notifier with shrinker")
> changed the behavior when deflation happens automatically. Instead of
> deflating when called by the OOM handler, the shrinker is used.
> 
> However, the balloon is not simply some slab cache that should be shrunk
> when under memory pressure. The shrinker does not have a concept of
> priorities, so this behavior cannot be configured.
> 
> There was a report that this results in undesired side effects when inflating
> the balloon to shrink the page cache. [1]
> 	"When inflating the balloon against page cache (i.e. no free memory
> 	 remains) vmscan.c will both shrink page cache, but also invoke the
> 	 shrinkers -- including the balloon's shrinker. So the balloon
> 	 driver allocates memory which requires reclaim, vmscan gets this
> 	 memory by shrinking the balloon, and then the driver adds the
> 	 memory back to the balloon. Basically a busy no-op."

Not sure if we need to go back to OOM, which has many drawbacks as we discussed.
Just posted out another approach, which is simple.

Best,
Wei


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v1 3/3] virtio-balloon: Switch back to OOM handler for VIRTIO_BALLOON_F_DEFLATE_ON_OOM
  2020-02-06  8:57       ` Michael S. Tsirkin
@ 2020-02-06  9:05         ` David Hildenbrand
  2020-02-06  9:09           ` Michael S. Tsirkin
  0 siblings, 1 reply; 27+ messages in thread
From: David Hildenbrand @ 2020-02-06  9:05 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: linux-kernel, linux-mm, virtualization, Tyler Sanderson,
	Wei Wang, Alexander Duyck, David Rientjes, Nadav Amit,
	Michal Hocko

>> commit bf50e69f63d21091e525185c3ae761412be0ba72
>> Author: Dave Hansen <dave@linux.vnet.ibm.com>
>> Date:   Thu Apr 7 10:43:25 2011 -0700
>>
>>     virtio balloon: kill tell-host-first logic
>>
>>     The virtio balloon driver has a VIRTIO_BALLOON_F_MUST_TELL_HOST
>>     feature bit.  Whenever the bit is set, the guest kernel must
>>     always tell the host before we free pages back to the allocator.
>>     Without this feature, we might free a page (and have another
>>     user touch it) while the hypervisor is unprepared for it.
>>
>>     But, if the bit is _not_ set, we are under no obligation to
>>     reverse the order; we're under no obligation to do _anything_.
>>     As of now, qemu-kvm defines the bit, but doesn't set it.
> 
> Well this is not what the spec says in the end.

I didn't check the spec, maybe I should do that :)

> To continue that commit message:
> 
>     This patch makes the "tell host first" logic the only case.  This
>     should make everybody happy, and reduce the amount of untested or
>     untestable code in the kernel.

Yeah, but this comment explains that the current deflate is only in
place, because it makes the code simpler (to support both cases). Of
course, doing the deflate might result in performance improvements.
(e.g., MADV_WILLNEED)

> 
> you can try proposing the change to the virtio TC, see what do others
> think.

We can just drop the comment from this patch for now. The tell_host host
not be an issue AFAIKS.

-- 
Thanks,

David / dhildenb



^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v1 3/3] virtio-balloon: Switch back to OOM handler for VIRTIO_BALLOON_F_DEFLATE_ON_OOM
  2020-02-06  9:05         ` David Hildenbrand
@ 2020-02-06  9:09           ` Michael S. Tsirkin
  0 siblings, 0 replies; 27+ messages in thread
From: Michael S. Tsirkin @ 2020-02-06  9:09 UTC (permalink / raw)
  To: David Hildenbrand
  Cc: linux-kernel, linux-mm, virtualization, Tyler Sanderson,
	Wei Wang, Alexander Duyck, David Rientjes, Nadav Amit,
	Michal Hocko

On Thu, Feb 06, 2020 at 10:05:43AM +0100, David Hildenbrand wrote:
> >> commit bf50e69f63d21091e525185c3ae761412be0ba72
> >> Author: Dave Hansen <dave@linux.vnet.ibm.com>
> >> Date:   Thu Apr 7 10:43:25 2011 -0700
> >>
> >>     virtio balloon: kill tell-host-first logic
> >>
> >>     The virtio balloon driver has a VIRTIO_BALLOON_F_MUST_TELL_HOST
> >>     feature bit.  Whenever the bit is set, the guest kernel must
> >>     always tell the host before we free pages back to the allocator.
> >>     Without this feature, we might free a page (and have another
> >>     user touch it) while the hypervisor is unprepared for it.
> >>
> >>     But, if the bit is _not_ set, we are under no obligation to
> >>     reverse the order; we're under no obligation to do _anything_.
> >>     As of now, qemu-kvm defines the bit, but doesn't set it.
> > 
> > Well this is not what the spec says in the end.
> 
> I didn't check the spec, maybe I should do that :)
> 
> > To continue that commit message:
> > 
> >     This patch makes the "tell host first" logic the only case.  This
> >     should make everybody happy, and reduce the amount of untested or
> >     untestable code in the kernel.
> 
> Yeah, but this comment explains that the current deflate is only in
> place, because it makes the code simpler (to support both cases). Of
> course, doing the deflate might result in performance improvements.
> (e.g., MADV_WILLNEED)
> 
> > 
> > you can try proposing the change to the virtio TC, see what do others
> > think.
> 
> We can just drop the comment from this patch for now. The tell_host host
> not be an issue AFAIKS.

I guess it's a good idea.


> -- 
> Thanks,
> 
> David / dhildenb



^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v1 3/3] virtio-balloon: Switch back to OOM handler for VIRTIO_BALLOON_F_DEFLATE_ON_OOM
  2020-02-05 16:34 ` [PATCH v1 3/3] virtio-balloon: Switch back to OOM handler for VIRTIO_BALLOON_F_DEFLATE_ON_OOM David Hildenbrand
                     ` (2 preceding siblings ...)
  2020-02-06  8:57   ` Wang, Wei W
@ 2020-02-06  9:11   ` Michael S. Tsirkin
  2020-02-06  9:12   ` Michael S. Tsirkin
                     ` (2 subsequent siblings)
  6 siblings, 0 replies; 27+ messages in thread
From: Michael S. Tsirkin @ 2020-02-06  9:11 UTC (permalink / raw)
  To: David Hildenbrand
  Cc: linux-kernel, linux-mm, virtualization, Tyler Sanderson,
	Wei Wang, Alexander Duyck, David Rientjes, Nadav Amit,
	Michal Hocko

On Wed, Feb 05, 2020 at 05:34:02PM +0100, David Hildenbrand wrote:
> Commit 71994620bb25 ("virtio_balloon: replace oom notifier with shrinker")
> changed the behavior when deflation happens automatically. Instead of
> deflating when called by the OOM handler, the shrinker is used.
> 
> However, the balloon is not simply some slab cache that should be
> shrunk when under memory pressure. The shrinker does not have a concept of
> priorities, so this behavior cannot be configured.
> 
> There was a report that this results in undesired side effects when
> inflating the balloon to shrink the page cache. [1]
> 	"When inflating the balloon against page cache (i.e. no free memory
> 	 remains) vmscan.c will both shrink page cache, but also invoke the
> 	 shrinkers -- including the balloon's shrinker. So the balloon
> 	 driver allocates memory which requires reclaim, vmscan gets this
> 	 memory by shrinking the balloon, and then the driver adds the
> 	 memory back to the balloon. Basically a busy no-op."
> 
> The name "deflate on OOM" makes it pretty clear when deflation should
> happen - after other approaches to reclaim memory failed, not while
> reclaiming. This allows to minimize the footprint of a guest - memory
> will only be taken out of the balloon when really needed.
> 
> Especially, a drop_slab() will result in the whole balloon getting
> deflated - undesired. While handling it via the OOM handler might not be
> perfect, it keeps existing behavior. If we want a different behavior, then
> we need a new feature bit and document it properly (although, there should
> be a clear use case and the intended effects should be well described).
> 
> Keep using the shrinker for VIRTIO_BALLOON_F_FREE_PAGE_HINT, because
> this has no such side effects. Always register the shrinker with
> VIRTIO_BALLOON_F_FREE_PAGE_HINT now. We are always allowed to reuse free
> pages that are still to be processed by the guest. The hypervisor takes
> care of identifying and resolving possible races between processing a
> hinting request and the guest reusing a page.
> 
> In contrast to pre commit 71994620bb25 ("virtio_balloon: replace oom
> notifier with shrinker"), don't add a moodule parameter to configure the
> number of pages to deflate on OOM. Can be re-added if really needed.
> Also, pay attention that leak_balloon() returns the number of 4k pages -
> convert it properly in virtio_balloon_oom_notify().
> 
> Note1: using the OOM handler is frowned upon, but it really is what we
>        need for this feature.
> 
> Note2: without VIRTIO_BALLOON_F_MUST_TELL_HOST (iow, always with QEMU) we
>        could actually skip sending deflation requests to our hypervisor,
>        making the OOM path *very* simple. Besically freeing pages and
>        updating the balloon. If the communication with the host ever
>        becomes a problem on this call path.
> 
> [1] https://www.spinics.net/lists/linux-virtualization/msg40863.html
> 
> Reported-by: Tyler Sanderson <tysand@google.com>
> Cc: Michael S. Tsirkin <mst@redhat.com>
> Cc: Wei Wang <wei.w.wang@intel.com>
> Cc: Alexander Duyck <alexander.h.duyck@linux.intel.com>
> Cc: David Rientjes <rientjes@google.com>
> Cc: Nadav Amit <namit@vmware.com>
> Cc: Michal Hocko <mhocko@kernel.org>
> Signed-off-by: David Hildenbrand <david@redhat.com>

So the revert looks ok, from that POV and with commit log changes

Acked-by: Michael S. Tsirkin <mst@redhat.com>

however, let's see what do others think, and whether Wei can come
up with a fixup for the shrinker.


> ---
>  drivers/virtio/virtio_balloon.c | 107 +++++++++++++-------------------
>  1 file changed, 44 insertions(+), 63 deletions(-)
> 
> diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
> index 7e5d84caeb94..e7b18f556c5e 100644
> --- a/drivers/virtio/virtio_balloon.c
> +++ b/drivers/virtio/virtio_balloon.c
> @@ -14,6 +14,7 @@
>  #include <linux/slab.h>
>  #include <linux/module.h>
>  #include <linux/balloon_compaction.h>
> +#include <linux/oom.h>
>  #include <linux/wait.h>
>  #include <linux/mm.h>
>  #include <linux/mount.h>
> @@ -27,7 +28,9 @@
>   */
>  #define VIRTIO_BALLOON_PAGES_PER_PAGE (unsigned)(PAGE_SIZE >> VIRTIO_BALLOON_PFN_SHIFT)
>  #define VIRTIO_BALLOON_ARRAY_PFNS_MAX 256
> -#define VIRTBALLOON_OOM_NOTIFY_PRIORITY 80
> +/* Maximum number of (4k) pages to deflate on OOM notifications. */
> +#define VIRTIO_BALLOON_OOM_NR_PAGES 256
> +#define VIRTIO_BALLOON_OOM_NOTIFY_PRIORITY 80
>  
>  #define VIRTIO_BALLOON_FREE_PAGE_ALLOC_FLAG (__GFP_NORETRY | __GFP_NOWARN | \
>  					     __GFP_NOMEMALLOC)
> @@ -112,8 +115,11 @@ struct virtio_balloon {
>  	/* Memory statistics */
>  	struct virtio_balloon_stat stats[VIRTIO_BALLOON_S_NR];
>  
> -	/* To register a shrinker to shrink memory upon memory pressure */
> +	/* Shrinker to return free pages - VIRTIO_BALLOON_F_FREE_PAGE_HINT */
>  	struct shrinker shrinker;
> +
> +	/* OOM notifier to deflate on OOM - VIRTIO_BALLOON_F_DEFLATE_ON_OOM */
> +	struct notifier_block oom_nb;
>  };
>  
>  static struct virtio_device_id id_table[] = {
> @@ -786,50 +792,13 @@ static unsigned long shrink_free_pages(struct virtio_balloon *vb,
>  	return blocks_freed * VIRTIO_BALLOON_HINT_BLOCK_PAGES;
>  }
>  
> -static unsigned long leak_balloon_pages(struct virtio_balloon *vb,
> -                                          unsigned long pages_to_free)
> -{
> -	return leak_balloon(vb, pages_to_free * VIRTIO_BALLOON_PAGES_PER_PAGE) /
> -		VIRTIO_BALLOON_PAGES_PER_PAGE;
> -}
> -
> -static unsigned long shrink_balloon_pages(struct virtio_balloon *vb,
> -					  unsigned long pages_to_free)
> -{
> -	unsigned long pages_freed = 0;
> -
> -	/*
> -	 * One invocation of leak_balloon can deflate at most
> -	 * VIRTIO_BALLOON_ARRAY_PFNS_MAX balloon pages, so we call it
> -	 * multiple times to deflate pages till reaching pages_to_free.
> -	 */
> -	while (vb->num_pages && pages_freed < pages_to_free)
> -		pages_freed += leak_balloon_pages(vb,
> -						  pages_to_free - pages_freed);
> -
> -	update_balloon_size(vb);
> -
> -	return pages_freed;
> -}
> -
>  static unsigned long virtio_balloon_shrinker_scan(struct shrinker *shrinker,
>  						  struct shrink_control *sc)
>  {
> -	unsigned long pages_to_free, pages_freed = 0;
>  	struct virtio_balloon *vb = container_of(shrinker,
>  					struct virtio_balloon, shrinker);
>  
> -	pages_to_free = sc->nr_to_scan;
> -
> -	if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT))
> -		pages_freed = shrink_free_pages(vb, pages_to_free);
> -
> -	if (pages_freed >= pages_to_free)
> -		return pages_freed;
> -
> -	pages_freed += shrink_balloon_pages(vb, pages_to_free - pages_freed);
> -
> -	return pages_freed;
> +	return shrink_free_pages(vb, sc->nr_to_scan);
>  }
>  
>  static unsigned long virtio_balloon_shrinker_count(struct shrinker *shrinker,
> @@ -837,26 +806,22 @@ static unsigned long virtio_balloon_shrinker_count(struct shrinker *shrinker,
>  {
>  	struct virtio_balloon *vb = container_of(shrinker,
>  					struct virtio_balloon, shrinker);
> -	unsigned long count;
> -
> -	count = vb->num_pages / VIRTIO_BALLOON_PAGES_PER_PAGE;
> -	count += vb->num_free_page_blocks * VIRTIO_BALLOON_HINT_BLOCK_PAGES;
>  
> -	return count;
> +	return vb->num_free_page_blocks * VIRTIO_BALLOON_HINT_BLOCK_PAGES;
>  }
>  
> -static void virtio_balloon_unregister_shrinker(struct virtio_balloon *vb)
> +static int virtio_balloon_oom_notify(struct notifier_block *nb,
> +				     unsigned long dummy, void *parm)
>  {
> -	unregister_shrinker(&vb->shrinker);
> -}
> +	struct virtio_balloon *vb = container_of(nb,
> +						 struct virtio_balloon, oom_nb);
> +	unsigned long *freed = parm;
>  
> -static int virtio_balloon_register_shrinker(struct virtio_balloon *vb)
> -{
> -	vb->shrinker.scan_objects = virtio_balloon_shrinker_scan;
> -	vb->shrinker.count_objects = virtio_balloon_shrinker_count;
> -	vb->shrinker.seeks = DEFAULT_SEEKS;
> +	*freed += leak_balloon(vb, VIRTIO_BALLOON_OOM_NR_PAGES) /
> +		  VIRTIO_BALLOON_PAGES_PER_PAGE;
> +	update_balloon_size(vb);
>  
> -	return register_shrinker(&vb->shrinker);
> +	return NOTIFY_OK;
>  }
>  
>  static int virtballoon_probe(struct virtio_device *vdev)
> @@ -933,22 +898,35 @@ static int virtballoon_probe(struct virtio_device *vdev)
>  			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
> -	 * shrinker needs to be registered to relieve memory pressure.
> -	 */
> -	if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM)) {
> -		err = virtio_balloon_register_shrinker(vb);
> +
> +		/*
> +		 * We're allowed to reuse any free pages, even if they are
> +		 * still to be processed by the host.
> +		 */
> +		vb->shrinker.scan_objects = virtio_balloon_shrinker_scan;
> +		vb->shrinker.count_objects = virtio_balloon_shrinker_count;
> +		vb->shrinker.seeks = DEFAULT_SEEKS;
> +		err = register_shrinker(&vb->shrinker);
>  		if (err)
>  			goto out_del_balloon_wq;
>  	}
> +	if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM)) {
> +		vb->oom_nb.notifier_call = virtio_balloon_oom_notify;
> +		vb->oom_nb.priority = VIRTIO_BALLOON_OOM_NOTIFY_PRIORITY;
> +		err = register_oom_notifier(&vb->oom_nb);
> +		if (err < 0)
> +			goto out_unregister_shrinker;
> +	}
> +
>  	virtio_device_ready(vdev);
>  
>  	if (towards_target(vb))
>  		virtballoon_changed(vdev);
>  	return 0;
>  
> +out_unregister_shrinker:
> +	if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT))
> +		unregister_shrinker(&vb->shrinker);
>  out_del_balloon_wq:
>  	if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT))
>  		destroy_workqueue(vb->balloon_wq);
> @@ -987,8 +965,11 @@ static void virtballoon_remove(struct virtio_device *vdev)
>  {
>  	struct virtio_balloon *vb = vdev->priv;
>  
> -	if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM))
> -		virtio_balloon_unregister_shrinker(vb);
> +	if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM))
> +		unregister_oom_notifier(&vb->oom_nb);
> +	if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT))
> +		unregister_shrinker(&vb->shrinker);
> +
>  	spin_lock_irq(&vb->stop_update_lock);
>  	vb->stop_update = true;
>  	spin_unlock_irq(&vb->stop_update_lock);
> -- 
> 2.24.1



^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v1 3/3] virtio-balloon: Switch back to OOM handler for VIRTIO_BALLOON_F_DEFLATE_ON_OOM
  2020-02-05 16:34 ` [PATCH v1 3/3] virtio-balloon: Switch back to OOM handler for VIRTIO_BALLOON_F_DEFLATE_ON_OOM David Hildenbrand
                     ` (3 preceding siblings ...)
  2020-02-06  9:11   ` Michael S. Tsirkin
@ 2020-02-06  9:12   ` Michael S. Tsirkin
  2020-02-06  9:21     ` David Hildenbrand
  2020-02-14  9:51   ` David Hildenbrand
  2020-02-14 14:06   ` Michal Hocko
  6 siblings, 1 reply; 27+ messages in thread
From: Michael S. Tsirkin @ 2020-02-06  9:12 UTC (permalink / raw)
  To: David Hildenbrand
  Cc: linux-kernel, linux-mm, virtualization, Tyler Sanderson,
	Wei Wang, Alexander Duyck, David Rientjes, Nadav Amit,
	Michal Hocko

On Wed, Feb 05, 2020 at 05:34:02PM +0100, David Hildenbrand wrote:
> Commit 71994620bb25 ("virtio_balloon: replace oom notifier with shrinker")
> changed the behavior when deflation happens automatically. Instead of
> deflating when called by the OOM handler, the shrinker is used.
> 
> However, the balloon is not simply some slab cache that should be
> shrunk when under memory pressure. The shrinker does not have a concept of
> priorities, so this behavior cannot be configured.
> 
> There was a report that this results in undesired side effects when
> inflating the balloon to shrink the page cache. [1]
> 	"When inflating the balloon against page cache (i.e. no free memory
> 	 remains) vmscan.c will both shrink page cache, but also invoke the
> 	 shrinkers -- including the balloon's shrinker. So the balloon
> 	 driver allocates memory which requires reclaim, vmscan gets this
> 	 memory by shrinking the balloon, and then the driver adds the
> 	 memory back to the balloon. Basically a busy no-op."
> 
> The name "deflate on OOM" makes it pretty clear when deflation should
> happen - after other approaches to reclaim memory failed, not while
> reclaiming. This allows to minimize the footprint of a guest - memory
> will only be taken out of the balloon when really needed.
> 
> Especially, a drop_slab() will result in the whole balloon getting
> deflated - undesired. While handling it via the OOM handler might not be
> perfect, it keeps existing behavior. If we want a different behavior, then
> we need a new feature bit and document it properly (although, there should
> be a clear use case and the intended effects should be well described).
> 
> Keep using the shrinker for VIRTIO_BALLOON_F_FREE_PAGE_HINT, because
> this has no such side effects. Always register the shrinker with
> VIRTIO_BALLOON_F_FREE_PAGE_HINT now. We are always allowed to reuse free
> pages that are still to be processed by the guest. The hypervisor takes
> care of identifying and resolving possible races between processing a
> hinting request and the guest reusing a page.
> 
> In contrast to pre commit 71994620bb25 ("virtio_balloon: replace oom
> notifier with shrinker"), don't add a moodule parameter to configure the
> number of pages to deflate on OOM. Can be re-added if really needed.
> Also, pay attention that leak_balloon() returns the number of 4k pages -
> convert it properly in virtio_balloon_oom_notify().
> 
> Note1: using the OOM handler is frowned upon, but it really is what we
>        need for this feature.
> 
> Note2: without VIRTIO_BALLOON_F_MUST_TELL_HOST (iow, always with QEMU) we
>        could actually skip sending deflation requests to our hypervisor,
>        making the OOM path *very* simple. Besically freeing pages and
>        updating the balloon. If the communication with the host ever
>        becomes a problem on this call path.
> 
> [1] https://www.spinics.net/lists/linux-virtualization/msg40863.html
> 
> Reported-by: Tyler Sanderson <tysand@google.com>
> Cc: Michael S. Tsirkin <mst@redhat.com>
> Cc: Wei Wang <wei.w.wang@intel.com>
> Cc: Alexander Duyck <alexander.h.duyck@linux.intel.com>
> Cc: David Rientjes <rientjes@google.com>
> Cc: Nadav Amit <namit@vmware.com>
> Cc: Michal Hocko <mhocko@kernel.org>
> Signed-off-by: David Hildenbrand <david@redhat.com>


I guess we should add a Fixes tag to the patch it's reverting,
this way it's backported and hypervisors will be able to rely on OOM
behaviour.

> ---
>  drivers/virtio/virtio_balloon.c | 107 +++++++++++++-------------------
>  1 file changed, 44 insertions(+), 63 deletions(-)
> 
> diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
> index 7e5d84caeb94..e7b18f556c5e 100644
> --- a/drivers/virtio/virtio_balloon.c
> +++ b/drivers/virtio/virtio_balloon.c
> @@ -14,6 +14,7 @@
>  #include <linux/slab.h>
>  #include <linux/module.h>
>  #include <linux/balloon_compaction.h>
> +#include <linux/oom.h>
>  #include <linux/wait.h>
>  #include <linux/mm.h>
>  #include <linux/mount.h>
> @@ -27,7 +28,9 @@
>   */
>  #define VIRTIO_BALLOON_PAGES_PER_PAGE (unsigned)(PAGE_SIZE >> VIRTIO_BALLOON_PFN_SHIFT)
>  #define VIRTIO_BALLOON_ARRAY_PFNS_MAX 256
> -#define VIRTBALLOON_OOM_NOTIFY_PRIORITY 80
> +/* Maximum number of (4k) pages to deflate on OOM notifications. */
> +#define VIRTIO_BALLOON_OOM_NR_PAGES 256
> +#define VIRTIO_BALLOON_OOM_NOTIFY_PRIORITY 80
>  
>  #define VIRTIO_BALLOON_FREE_PAGE_ALLOC_FLAG (__GFP_NORETRY | __GFP_NOWARN | \
>  					     __GFP_NOMEMALLOC)
> @@ -112,8 +115,11 @@ struct virtio_balloon {
>  	/* Memory statistics */
>  	struct virtio_balloon_stat stats[VIRTIO_BALLOON_S_NR];
>  
> -	/* To register a shrinker to shrink memory upon memory pressure */
> +	/* Shrinker to return free pages - VIRTIO_BALLOON_F_FREE_PAGE_HINT */
>  	struct shrinker shrinker;
> +
> +	/* OOM notifier to deflate on OOM - VIRTIO_BALLOON_F_DEFLATE_ON_OOM */
> +	struct notifier_block oom_nb;
>  };
>  
>  static struct virtio_device_id id_table[] = {
> @@ -786,50 +792,13 @@ static unsigned long shrink_free_pages(struct virtio_balloon *vb,
>  	return blocks_freed * VIRTIO_BALLOON_HINT_BLOCK_PAGES;
>  }
>  
> -static unsigned long leak_balloon_pages(struct virtio_balloon *vb,
> -                                          unsigned long pages_to_free)
> -{
> -	return leak_balloon(vb, pages_to_free * VIRTIO_BALLOON_PAGES_PER_PAGE) /
> -		VIRTIO_BALLOON_PAGES_PER_PAGE;
> -}
> -
> -static unsigned long shrink_balloon_pages(struct virtio_balloon *vb,
> -					  unsigned long pages_to_free)
> -{
> -	unsigned long pages_freed = 0;
> -
> -	/*
> -	 * One invocation of leak_balloon can deflate at most
> -	 * VIRTIO_BALLOON_ARRAY_PFNS_MAX balloon pages, so we call it
> -	 * multiple times to deflate pages till reaching pages_to_free.
> -	 */
> -	while (vb->num_pages && pages_freed < pages_to_free)
> -		pages_freed += leak_balloon_pages(vb,
> -						  pages_to_free - pages_freed);
> -
> -	update_balloon_size(vb);
> -
> -	return pages_freed;
> -}
> -
>  static unsigned long virtio_balloon_shrinker_scan(struct shrinker *shrinker,
>  						  struct shrink_control *sc)
>  {
> -	unsigned long pages_to_free, pages_freed = 0;
>  	struct virtio_balloon *vb = container_of(shrinker,
>  					struct virtio_balloon, shrinker);
>  
> -	pages_to_free = sc->nr_to_scan;
> -
> -	if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT))
> -		pages_freed = shrink_free_pages(vb, pages_to_free);
> -
> -	if (pages_freed >= pages_to_free)
> -		return pages_freed;
> -
> -	pages_freed += shrink_balloon_pages(vb, pages_to_free - pages_freed);
> -
> -	return pages_freed;
> +	return shrink_free_pages(vb, sc->nr_to_scan);
>  }
>  
>  static unsigned long virtio_balloon_shrinker_count(struct shrinker *shrinker,
> @@ -837,26 +806,22 @@ static unsigned long virtio_balloon_shrinker_count(struct shrinker *shrinker,
>  {
>  	struct virtio_balloon *vb = container_of(shrinker,
>  					struct virtio_balloon, shrinker);
> -	unsigned long count;
> -
> -	count = vb->num_pages / VIRTIO_BALLOON_PAGES_PER_PAGE;
> -	count += vb->num_free_page_blocks * VIRTIO_BALLOON_HINT_BLOCK_PAGES;
>  
> -	return count;
> +	return vb->num_free_page_blocks * VIRTIO_BALLOON_HINT_BLOCK_PAGES;
>  }
>  
> -static void virtio_balloon_unregister_shrinker(struct virtio_balloon *vb)
> +static int virtio_balloon_oom_notify(struct notifier_block *nb,
> +				     unsigned long dummy, void *parm)
>  {
> -	unregister_shrinker(&vb->shrinker);
> -}
> +	struct virtio_balloon *vb = container_of(nb,
> +						 struct virtio_balloon, oom_nb);
> +	unsigned long *freed = parm;
>  
> -static int virtio_balloon_register_shrinker(struct virtio_balloon *vb)
> -{
> -	vb->shrinker.scan_objects = virtio_balloon_shrinker_scan;
> -	vb->shrinker.count_objects = virtio_balloon_shrinker_count;
> -	vb->shrinker.seeks = DEFAULT_SEEKS;
> +	*freed += leak_balloon(vb, VIRTIO_BALLOON_OOM_NR_PAGES) /
> +		  VIRTIO_BALLOON_PAGES_PER_PAGE;
> +	update_balloon_size(vb);
>  
> -	return register_shrinker(&vb->shrinker);
> +	return NOTIFY_OK;
>  }
>  
>  static int virtballoon_probe(struct virtio_device *vdev)
> @@ -933,22 +898,35 @@ static int virtballoon_probe(struct virtio_device *vdev)
>  			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
> -	 * shrinker needs to be registered to relieve memory pressure.
> -	 */
> -	if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM)) {
> -		err = virtio_balloon_register_shrinker(vb);
> +
> +		/*
> +		 * We're allowed to reuse any free pages, even if they are
> +		 * still to be processed by the host.
> +		 */
> +		vb->shrinker.scan_objects = virtio_balloon_shrinker_scan;
> +		vb->shrinker.count_objects = virtio_balloon_shrinker_count;
> +		vb->shrinker.seeks = DEFAULT_SEEKS;
> +		err = register_shrinker(&vb->shrinker);
>  		if (err)
>  			goto out_del_balloon_wq;
>  	}
> +	if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM)) {
> +		vb->oom_nb.notifier_call = virtio_balloon_oom_notify;
> +		vb->oom_nb.priority = VIRTIO_BALLOON_OOM_NOTIFY_PRIORITY;
> +		err = register_oom_notifier(&vb->oom_nb);
> +		if (err < 0)
> +			goto out_unregister_shrinker;
> +	}
> +
>  	virtio_device_ready(vdev);
>  
>  	if (towards_target(vb))
>  		virtballoon_changed(vdev);
>  	return 0;
>  
> +out_unregister_shrinker:
> +	if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT))
> +		unregister_shrinker(&vb->shrinker);
>  out_del_balloon_wq:
>  	if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT))
>  		destroy_workqueue(vb->balloon_wq);
> @@ -987,8 +965,11 @@ static void virtballoon_remove(struct virtio_device *vdev)
>  {
>  	struct virtio_balloon *vb = vdev->priv;
>  
> -	if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM))
> -		virtio_balloon_unregister_shrinker(vb);
> +	if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM))
> +		unregister_oom_notifier(&vb->oom_nb);
> +	if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT))
> +		unregister_shrinker(&vb->shrinker);
> +
>  	spin_lock_irq(&vb->stop_update_lock);
>  	vb->stop_update = true;
>  	spin_unlock_irq(&vb->stop_update_lock);
> -- 
> 2.24.1



^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v1 3/3] virtio-balloon: Switch back to OOM handler for VIRTIO_BALLOON_F_DEFLATE_ON_OOM
  2020-02-06  9:12   ` Michael S. Tsirkin
@ 2020-02-06  9:21     ` David Hildenbrand
  0 siblings, 0 replies; 27+ messages in thread
From: David Hildenbrand @ 2020-02-06  9:21 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: linux-kernel, linux-mm, virtualization, Tyler Sanderson,
	Wei Wang, Alexander Duyck, David Rientjes, Nadav Amit,
	Michal Hocko

On 06.02.20 10:12, Michael S. Tsirkin wrote:
> On Wed, Feb 05, 2020 at 05:34:02PM +0100, David Hildenbrand wrote:
>> Commit 71994620bb25 ("virtio_balloon: replace oom notifier with shrinker")
>> changed the behavior when deflation happens automatically. Instead of
>> deflating when called by the OOM handler, the shrinker is used.
>>
>> However, the balloon is not simply some slab cache that should be
>> shrunk when under memory pressure. The shrinker does not have a concept of
>> priorities, so this behavior cannot be configured.
>>
>> There was a report that this results in undesired side effects when
>> inflating the balloon to shrink the page cache. [1]
>> 	"When inflating the balloon against page cache (i.e. no free memory
>> 	 remains) vmscan.c will both shrink page cache, but also invoke the
>> 	 shrinkers -- including the balloon's shrinker. So the balloon
>> 	 driver allocates memory which requires reclaim, vmscan gets this
>> 	 memory by shrinking the balloon, and then the driver adds the
>> 	 memory back to the balloon. Basically a busy no-op."
>>
>> The name "deflate on OOM" makes it pretty clear when deflation should
>> happen - after other approaches to reclaim memory failed, not while
>> reclaiming. This allows to minimize the footprint of a guest - memory
>> will only be taken out of the balloon when really needed.
>>
>> Especially, a drop_slab() will result in the whole balloon getting
>> deflated - undesired. While handling it via the OOM handler might not be
>> perfect, it keeps existing behavior. If we want a different behavior, then
>> we need a new feature bit and document it properly (although, there should
>> be a clear use case and the intended effects should be well described).
>>
>> Keep using the shrinker for VIRTIO_BALLOON_F_FREE_PAGE_HINT, because
>> this has no such side effects. Always register the shrinker with
>> VIRTIO_BALLOON_F_FREE_PAGE_HINT now. We are always allowed to reuse free
>> pages that are still to be processed by the guest. The hypervisor takes
>> care of identifying and resolving possible races between processing a
>> hinting request and the guest reusing a page.
>>
>> In contrast to pre commit 71994620bb25 ("virtio_balloon: replace oom
>> notifier with shrinker"), don't add a moodule parameter to configure the
>> number of pages to deflate on OOM. Can be re-added if really needed.
>> Also, pay attention that leak_balloon() returns the number of 4k pages -
>> convert it properly in virtio_balloon_oom_notify().
>>
>> Note1: using the OOM handler is frowned upon, but it really is what we
>>        need for this feature.
>>
>> Note2: without VIRTIO_BALLOON_F_MUST_TELL_HOST (iow, always with QEMU) we
>>        could actually skip sending deflation requests to our hypervisor,
>>        making the OOM path *very* simple. Besically freeing pages and
>>        updating the balloon. If the communication with the host ever
>>        becomes a problem on this call path.
>>
>> [1] https://www.spinics.net/lists/linux-virtualization/msg40863.html
>>
>> Reported-by: Tyler Sanderson <tysand@google.com>
>> Cc: Michael S. Tsirkin <mst@redhat.com>
>> Cc: Wei Wang <wei.w.wang@intel.com>
>> Cc: Alexander Duyck <alexander.h.duyck@linux.intel.com>
>> Cc: David Rientjes <rientjes@google.com>
>> Cc: Nadav Amit <namit@vmware.com>
>> Cc: Michal Hocko <mhocko@kernel.org>
>> Signed-off-by: David Hildenbrand <david@redhat.com>
> 
> 
> I guess we should add a Fixes tag to the patch it's reverting,
> this way it's backported and hypervisors will be able to rely on OOM
> behaviour.

Makes sense,

Fixes: 71994620bb25 ("virtio_balloon: replace oom notifier with shrinker")

-- 
Thanks,

David / dhildenb



^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v1 3/3] virtio-balloon: Switch back to OOM handler for VIRTIO_BALLOON_F_DEFLATE_ON_OOM
  2020-02-05 16:34 ` [PATCH v1 3/3] virtio-balloon: Switch back to OOM handler for VIRTIO_BALLOON_F_DEFLATE_ON_OOM David Hildenbrand
                     ` (4 preceding siblings ...)
  2020-02-06  9:12   ` Michael S. Tsirkin
@ 2020-02-14  9:51   ` David Hildenbrand
  2020-02-14 13:31     ` Wang, Wei W
  2020-02-16  9:47     ` Michael S. Tsirkin
  2020-02-14 14:06   ` Michal Hocko
  6 siblings, 2 replies; 27+ messages in thread
From: David Hildenbrand @ 2020-02-14  9:51 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-mm, virtualization, Tyler Sanderson, Michael S . Tsirkin,
	Wei Wang, Alexander Duyck, David Rientjes, Nadav Amit,
	Michal Hocko

On 05.02.20 17:34, David Hildenbrand wrote:
> Commit 71994620bb25 ("virtio_balloon: replace oom notifier with shrinker")
> changed the behavior when deflation happens automatically. Instead of
> deflating when called by the OOM handler, the shrinker is used.
> 
> However, the balloon is not simply some slab cache that should be
> shrunk when under memory pressure. The shrinker does not have a concept of
> priorities, so this behavior cannot be configured.
> 
> There was a report that this results in undesired side effects when
> inflating the balloon to shrink the page cache. [1]
> 	"When inflating the balloon against page cache (i.e. no free memory
> 	 remains) vmscan.c will both shrink page cache, but also invoke the
> 	 shrinkers -- including the balloon's shrinker. So the balloon
> 	 driver allocates memory which requires reclaim, vmscan gets this
> 	 memory by shrinking the balloon, and then the driver adds the
> 	 memory back to the balloon. Basically a busy no-op."
> 
> The name "deflate on OOM" makes it pretty clear when deflation should
> happen - after other approaches to reclaim memory failed, not while
> reclaiming. This allows to minimize the footprint of a guest - memory
> will only be taken out of the balloon when really needed.
> 
> Especially, a drop_slab() will result in the whole balloon getting
> deflated - undesired. While handling it via the OOM handler might not be
> perfect, it keeps existing behavior. If we want a different behavior, then
> we need a new feature bit and document it properly (although, there should
> be a clear use case and the intended effects should be well described).
> 
> Keep using the shrinker for VIRTIO_BALLOON_F_FREE_PAGE_HINT, because
> this has no such side effects. Always register the shrinker with
> VIRTIO_BALLOON_F_FREE_PAGE_HINT now. We are always allowed to reuse free
> pages that are still to be processed by the guest. The hypervisor takes
> care of identifying and resolving possible races between processing a
> hinting request and the guest reusing a page.
> 
> In contrast to pre commit 71994620bb25 ("virtio_balloon: replace oom
> notifier with shrinker"), don't add a moodule parameter to configure the
> number of pages to deflate on OOM. Can be re-added if really needed.
> Also, pay attention that leak_balloon() returns the number of 4k pages -
> convert it properly in virtio_balloon_oom_notify().
> 
> Note1: using the OOM handler is frowned upon, but it really is what we
>        need for this feature.
> 
> Note2: without VIRTIO_BALLOON_F_MUST_TELL_HOST (iow, always with QEMU) we
>        could actually skip sending deflation requests to our hypervisor,
>        making the OOM path *very* simple. Besically freeing pages and
>        updating the balloon. If the communication with the host ever
>        becomes a problem on this call path.
> 

@Michael, how to proceed with this?


-- 
Thanks,

David / dhildenb



^ permalink raw reply	[flat|nested] 27+ messages in thread

* RE: [PATCH v1 3/3] virtio-balloon: Switch back to OOM handler for VIRTIO_BALLOON_F_DEFLATE_ON_OOM
  2020-02-14  9:51   ` David Hildenbrand
@ 2020-02-14 13:31     ` Wang, Wei W
  2020-02-16  9:47     ` Michael S. Tsirkin
  1 sibling, 0 replies; 27+ messages in thread
From: Wang, Wei W @ 2020-02-14 13:31 UTC (permalink / raw)
  To: David Hildenbrand, linux-kernel
  Cc: linux-mm, virtualization, Tyler Sanderson, Michael S . Tsirkin,
	Alexander Duyck, David Rientjes, Nadav Amit, Michal Hocko

On Friday, February 14, 2020 5:52 PM, David Hildenbrand wrote:
> > Commit 71994620bb25 ("virtio_balloon: replace oom notifier with
> > shrinker") changed the behavior when deflation happens automatically.
> > Instead of deflating when called by the OOM handler, the shrinker is used.
> >
> > However, the balloon is not simply some slab cache that should be
> > shrunk when under memory pressure. The shrinker does not have a
> > concept of priorities, so this behavior cannot be configured.
> >
> > There was a report that this results in undesired side effects when
> > inflating the balloon to shrink the page cache. [1]
> > 	"When inflating the balloon against page cache (i.e. no free memory
> > 	 remains) vmscan.c will both shrink page cache, but also invoke the
> > 	 shrinkers -- including the balloon's shrinker. So the balloon
> > 	 driver allocates memory which requires reclaim, vmscan gets this
> > 	 memory by shrinking the balloon, and then the driver adds the
> > 	 memory back to the balloon. Basically a busy no-op."
> >
> > The name "deflate on OOM" makes it pretty clear when deflation should
> > happen - after other approaches to reclaim memory failed, not while
> > reclaiming. This allows to minimize the footprint of a guest - memory
> > will only be taken out of the balloon when really needed.
> >
> > Especially, a drop_slab() will result in the whole balloon getting
> > deflated - undesired. While handling it via the OOM handler might not
> > be perfect, it keeps existing behavior. If we want a different
> > behavior, then we need a new feature bit and document it properly
> > (although, there should be a clear use case and the intended effects should
> be well described).
> >
> > Keep using the shrinker for VIRTIO_BALLOON_F_FREE_PAGE_HINT,
> because
> > this has no such side effects. Always register the shrinker with
> > VIRTIO_BALLOON_F_FREE_PAGE_HINT now. We are always allowed to
> reuse
> > free pages that are still to be processed by the guest. The hypervisor
> > takes care of identifying and resolving possible races between
> > processing a hinting request and the guest reusing a page.
> >
> > In contrast to pre commit 71994620bb25 ("virtio_balloon: replace oom
> > notifier with shrinker"), don't add a moodule parameter to configure
> > the number of pages to deflate on OOM. Can be re-added if really needed.
> > Also, pay attention that leak_balloon() returns the number of 4k pages
> > - convert it properly in virtio_balloon_oom_notify().
> >
> > Note1: using the OOM handler is frowned upon, but it really is what we
> >        need for this feature.
> >
> > Note2: without VIRTIO_BALLOON_F_MUST_TELL_HOST (iow, always with
> QEMU) we
> >        could actually skip sending deflation requests to our hypervisor,
> >        making the OOM path *very* simple. Besically freeing pages and
> >        updating the balloon. If the communication with the host ever
> >        becomes a problem on this call path.
> >
> 
> @Michael, how to proceed with this?
> 

I vote for not going back. When there are solid request and strong reasons in the future, we could reopen this discussion.

Best,
Wei

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v1 3/3] virtio-balloon: Switch back to OOM handler for VIRTIO_BALLOON_F_DEFLATE_ON_OOM
  2020-02-05 16:34 ` [PATCH v1 3/3] virtio-balloon: Switch back to OOM handler for VIRTIO_BALLOON_F_DEFLATE_ON_OOM David Hildenbrand
                     ` (5 preceding siblings ...)
  2020-02-14  9:51   ` David Hildenbrand
@ 2020-02-14 14:06   ` Michal Hocko
  2020-02-14 14:18     ` David Hildenbrand
  6 siblings, 1 reply; 27+ messages in thread
From: Michal Hocko @ 2020-02-14 14:06 UTC (permalink / raw)
  To: David Hildenbrand
  Cc: linux-kernel, linux-mm, virtualization, Tyler Sanderson,
	Michael S . Tsirkin, Wei Wang, Alexander Duyck, David Rientjes,
	Nadav Amit

On Wed 05-02-20 17:34:02, David Hildenbrand wrote:
> Commit 71994620bb25 ("virtio_balloon: replace oom notifier with shrinker")
> changed the behavior when deflation happens automatically. Instead of
> deflating when called by the OOM handler, the shrinker is used.
> 
> However, the balloon is not simply some slab cache that should be
> shrunk when under memory pressure. The shrinker does not have a concept of
> priorities, so this behavior cannot be configured.

Adding a priority to the shrinker doesn't sound like a big problem to
me. Shrinkers already get shrink_control data structure already and
priority could be added there.

> There was a report that this results in undesired side effects when
> inflating the balloon to shrink the page cache. [1]
> 	"When inflating the balloon against page cache (i.e. no free memory
> 	 remains) vmscan.c will both shrink page cache, but also invoke the
> 	 shrinkers -- including the balloon's shrinker. So the balloon
> 	 driver allocates memory which requires reclaim, vmscan gets this
> 	 memory by shrinking the balloon, and then the driver adds the
> 	 memory back to the balloon. Basically a busy no-op."
> 
> The name "deflate on OOM" makes it pretty clear when deflation should
> happen - after other approaches to reclaim memory failed, not while
> reclaiming. This allows to minimize the footprint of a guest - memory
> will only be taken out of the balloon when really needed.
> 
> Especially, a drop_slab() will result in the whole balloon getting
> deflated - undesired.

Could you explain why some more? drop_caches shouldn't be really used in
any production workloads and if somebody really wants all the cache to
be dropped then why is balloon any different?

-- 
Michal Hocko
SUSE Labs


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v1 3/3] virtio-balloon: Switch back to OOM handler for VIRTIO_BALLOON_F_DEFLATE_ON_OOM
  2020-02-14 14:06   ` Michal Hocko
@ 2020-02-14 14:18     ` David Hildenbrand
  2020-02-14 20:48       ` Tyler Sanderson
  0 siblings, 1 reply; 27+ messages in thread
From: David Hildenbrand @ 2020-02-14 14:18 UTC (permalink / raw)
  To: Michal Hocko
  Cc: linux-kernel, linux-mm, virtualization, Tyler Sanderson,
	Michael S . Tsirkin, Wei Wang, Alexander Duyck, David Rientjes,
	Nadav Amit

>> There was a report that this results in undesired side effects when
>> inflating the balloon to shrink the page cache. [1]
>> 	"When inflating the balloon against page cache (i.e. no free memory
>> 	 remains) vmscan.c will both shrink page cache, but also invoke the
>> 	 shrinkers -- including the balloon's shrinker. So the balloon
>> 	 driver allocates memory which requires reclaim, vmscan gets this
>> 	 memory by shrinking the balloon, and then the driver adds the
>> 	 memory back to the balloon. Basically a busy no-op."
>>
>> The name "deflate on OOM" makes it pretty clear when deflation should
>> happen - after other approaches to reclaim memory failed, not while
>> reclaiming. This allows to minimize the footprint of a guest - memory
>> will only be taken out of the balloon when really needed.
>>
>> Especially, a drop_slab() will result in the whole balloon getting
>> deflated - undesired.
> 
> Could you explain why some more? drop_caches shouldn't be really used in
> any production workloads and if somebody really wants all the cache to
> be dropped then why is balloon any different?
> 

Deflation should happen when the guest is out of memory, not when
somebody thinks it's time to reclaim some memory. That's what the
feature promised from the beginning: Only give the guest more memory in
case it *really* needs more memory.

Deflate on oom, not deflate on reclaim/memory pressure. (that's what the
report was all about)

A priority for shrinkers might be a step into the right direction.

-- 
Thanks,

David / dhildenb



^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v1 3/3] virtio-balloon: Switch back to OOM handler for VIRTIO_BALLOON_F_DEFLATE_ON_OOM
  2020-02-14 14:18     ` David Hildenbrand
@ 2020-02-14 20:48       ` Tyler Sanderson
  2020-02-14 21:17         ` David Hildenbrand
  2020-02-16  9:46         ` Michael S. Tsirkin
  0 siblings, 2 replies; 27+ messages in thread
From: Tyler Sanderson @ 2020-02-14 20:48 UTC (permalink / raw)
  To: David Hildenbrand
  Cc: Michal Hocko, linux-kernel, linux-mm, virtualization,
	Michael S . Tsirkin, Wei Wang, Alexander Duyck, David Rientjes,
	Nadav Amit

[-- Attachment #1: Type: text/plain, Size: 2706 bytes --]

Regarding Wei's patch that modifies the shrinker implementation, versus
this patch which reverts to OOM notifier:
I am in favor of both patches. But I do want to make sure a fix gets back
ported to 4.19 where the performance regression was first introduced.
My concern with reverting to the OOM notifier is, as mst@ put it (in the
other thread):
"when linux hits OOM all kind of error paths are being hit, latent bugs
start triggering, latency goes up drastically."
The guest could be in a lot of pain before the OOM notifier is invoked, and
it seems like the shrinker API might allow more fine grained control of
when we deflate.

On the other hand, I'm not totally convinced that Wei's patch is an
expected use of the shrinker/page-cache APIs, and maybe it is fragile.
Needs more testing and scrutiny.

It seems to me like the shrinker API is the right API in the long run,
perhaps with some fixes and modifications. But maybe reverting to OOM
notifier is the best patch to back port?

On Fri, Feb 14, 2020 at 6:19 AM David Hildenbrand <david@redhat.com> wrote:

> >> There was a report that this results in undesired side effects when
> >> inflating the balloon to shrink the page cache. [1]
> >>      "When inflating the balloon against page cache (i.e. no free memory
> >>       remains) vmscan.c will both shrink page cache, but also invoke the
> >>       shrinkers -- including the balloon's shrinker. So the balloon
> >>       driver allocates memory which requires reclaim, vmscan gets this
> >>       memory by shrinking the balloon, and then the driver adds the
> >>       memory back to the balloon. Basically a busy no-op."
> >>
> >> The name "deflate on OOM" makes it pretty clear when deflation should
> >> happen - after other approaches to reclaim memory failed, not while
> >> reclaiming. This allows to minimize the footprint of a guest - memory
> >> will only be taken out of the balloon when really needed.
> >>
> >> Especially, a drop_slab() will result in the whole balloon getting
> >> deflated - undesired.
> >
> > Could you explain why some more? drop_caches shouldn't be really used in
> > any production workloads and if somebody really wants all the cache to
> > be dropped then why is balloon any different?
> >
>
> Deflation should happen when the guest is out of memory, not when
> somebody thinks it's time to reclaim some memory. That's what the
> feature promised from the beginning: Only give the guest more memory in
> case it *really* needs more memory.
>
> Deflate on oom, not deflate on reclaim/memory pressure. (that's what the
> report was all about)
>
> A priority for shrinkers might be a step into the right direction.
>
> --
> Thanks,
>
> David / dhildenb
>
>

[-- Attachment #2: Type: text/html, Size: 3531 bytes --]

<div dir="ltr"><div>Regarding Wei&#39;s patch that modifies the shrinker implementation, versus this patch which reverts to OOM notifier:</div><div>I am in favor of both patches. But I do want to make sure a fix gets back ported to 4.19 where the performance regression was first introduced.</div><div>My concern with reverting to the OOM notifier is, as mst@ put it (in the other thread):<br><span style="color:rgb(80,0,80)">&quot;when linux hits OOM </span><span style="color:rgb(80,0,80)">all kind of error paths are being hit, latent bugs start triggering, </span><span style="color:rgb(80,0,80)">latency goes up drastically.&quot;</span><br></div><div>The guest could be in a lot of pain before the OOM notifier is invoked, and it seems like the shrinker API might allow more fine grained control of when we deflate.</div><div><br></div><div>On the other hand, I&#39;m not totally convinced that Wei&#39;s patch is an expected use of the shrinker/page-cache APIs, and maybe it is fragile. Needs more testing and scrutiny.</div><div><br></div><div>It seems to me like the shrinker API is the right API in the long run, perhaps with some fixes and modifications. But maybe reverting to OOM notifier is the best patch to back port?</div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Feb 14, 2020 at 6:19 AM David Hildenbrand &lt;<a href="mailto:david@redhat.com" target="_blank">david@redhat.com</a>&gt; wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">&gt;&gt; There was a report that this results in undesired side effects when<br>
&gt;&gt; inflating the balloon to shrink the page cache. [1]<br>
&gt;&gt;      &quot;When inflating the balloon against page cache (i.e. no free memory<br>
&gt;&gt;       remains) vmscan.c will both shrink page cache, but also invoke the<br>
&gt;&gt;       shrinkers -- including the balloon&#39;s shrinker. So the balloon<br>
&gt;&gt;       driver allocates memory which requires reclaim, vmscan gets this<br>
&gt;&gt;       memory by shrinking the balloon, and then the driver adds the<br>
&gt;&gt;       memory back to the balloon. Basically a busy no-op.&quot;<br>
&gt;&gt;<br>
&gt;&gt; The name &quot;deflate on OOM&quot; makes it pretty clear when deflation should<br>
&gt;&gt; happen - after other approaches to reclaim memory failed, not while<br>
&gt;&gt; reclaiming. This allows to minimize the footprint of a guest - memory<br>
&gt;&gt; will only be taken out of the balloon when really needed.<br>
&gt;&gt;<br>
&gt;&gt; Especially, a drop_slab() will result in the whole balloon getting<br>
&gt;&gt; deflated - undesired.<br>
&gt; <br>
&gt; Could you explain why some more? drop_caches shouldn&#39;t be really used in<br>
&gt; any production workloads and if somebody really wants all the cache to<br>
&gt; be dropped then why is balloon any different?<br>
&gt; <br>
<br>
Deflation should happen when the guest is out of memory, not when<br>
somebody thinks it&#39;s time to reclaim some memory. That&#39;s what the<br>
feature promised from the beginning: Only give the guest more memory in<br>
case it *really* needs more memory.<br>
<br>
Deflate on oom, not deflate on reclaim/memory pressure. (that&#39;s what the<br>
report was all about)<br>
<br>
A priority for shrinkers might be a step into the right direction.<br>
<br>
-- <br>
Thanks,<br>
<br>
David / dhildenb<br>
<br>
</blockquote></div></div>

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v1 3/3] virtio-balloon: Switch back to OOM handler for VIRTIO_BALLOON_F_DEFLATE_ON_OOM
  2020-02-14 20:48       ` Tyler Sanderson
@ 2020-02-14 21:17         ` David Hildenbrand
  2020-02-16  9:46         ` Michael S. Tsirkin
  1 sibling, 0 replies; 27+ messages in thread
From: David Hildenbrand @ 2020-02-14 21:17 UTC (permalink / raw)
  To: Tyler Sanderson
  Cc: David Hildenbrand, Michal Hocko, linux-kernel, linux-mm,
	virtualization, Michael S . Tsirkin, Wei Wang, Alexander Duyck,
	David Rientjes, Nadav Amit

[-- Attachment #1: Type: text/plain, Size: 1345 bytes --]



> Am 14.02.2020 um 21:49 schrieb Tyler Sanderson <tysand@google.com>:
> 
> 
> Regarding Wei's patch that modifies the shrinker implementation, versus this patch which reverts to OOM notifier:
> I am in favor of both patches. But I do want to make sure a fix gets back ported to 4.19 where the performance regression was first introduced.
> My concern with reverting to the OOM notifier is, as mst@ put it (in the other thread):
> "when linux hits OOM all kind of error paths are being hit, latent bugs start triggering, latency goes up drastically."

Yeah, and that was the default behavior for years, so it‘s not big news :)

> The guest could be in a lot of pain before the OOM notifier is invoked, and it seems like the shrinker API might allow more fine grained control of when we deflate.
> 
> On the other hand, I'm not totally convinced that Wei's patch is an expected use of the shrinker/page-cache APIs, and maybe it is fragile. Needs more testing and scrutiny.
> 
> It seems to me like the shrinker API is the right API in the long run, perhaps with some fixes and modifications. But maybe reverting to OOM notifier is the best patch to back

I think that‘s a good idea. Revert to the old state we had for years and then implement a proper, fully tested solution (e.g., shrinkers with priorities).

Cheers!

[-- Attachment #2: Type: text/html, Size: 1967 bytes --]

<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body dir="auto"><div dir="ltr"><br></div><div dir="ltr"><br><blockquote type="cite">Am 14.02.2020 um 21:49 schrieb Tyler Sanderson &lt;tysand@google.com&gt;:<br><br></blockquote></div><blockquote type="cite"><div dir="ltr"><div dir="ltr"><div>Regarding Wei's patch that modifies the shrinker implementation, versus this patch which reverts to OOM notifier:</div><div>I am in favor of both patches. But I do want to make sure a fix gets back ported to 4.19 where the performance regression was first introduced.</div><div>My concern with reverting to the OOM notifier is, as mst@ put it (in the other thread):<br><span style="color:rgb(80,0,80)">"when linux hits OOM&nbsp;</span><span style="color:rgb(80,0,80)">all kind of error paths are being hit, latent bugs start triggering,&nbsp;</span><span style="color:rgb(80,0,80)">latency goes up drastically."</span><br></div></div></div></blockquote><div><br></div><div>Yeah, and that was the default behavior for years, so it‘s not big news :)</div><br><blockquote type="cite"><div dir="ltr"><div dir="ltr"><div>The guest could be in a lot of pain before the OOM notifier is invoked, and it seems like the shrinker API might allow more fine grained control of when we deflate.</div><div><br></div><div>On the other hand, I'm not totally convinced that Wei's patch is an expected use of the shrinker/page-cache APIs, and maybe it is fragile. Needs more testing&nbsp;and scrutiny.</div><div><br></div><div>It seems to me like the shrinker API is the right API in the long run, perhaps with some fixes and modifications. But maybe reverting to OOM notifier is the best patch to back</div></div></div></blockquote><br><div>I think that‘s a good idea. Revert to the old state we had for years and then implement a proper, fully tested solution (e.g., shrinkers with priorities).</div><div><br></div><div>Cheers!</div></body></html>

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v1 3/3] virtio-balloon: Switch back to OOM handler for VIRTIO_BALLOON_F_DEFLATE_ON_OOM
  2020-02-14 20:48       ` Tyler Sanderson
  2020-02-14 21:17         ` David Hildenbrand
@ 2020-02-16  9:46         ` Michael S. Tsirkin
  1 sibling, 0 replies; 27+ messages in thread
From: Michael S. Tsirkin @ 2020-02-16  9:46 UTC (permalink / raw)
  To: Tyler Sanderson
  Cc: David Hildenbrand, Michal Hocko, linux-kernel, linux-mm,
	virtualization, Wei Wang, Alexander Duyck, David Rientjes,
	Nadav Amit

On Fri, Feb 14, 2020 at 12:48:42PM -0800, Tyler Sanderson wrote:
> Regarding Wei's patch that modifies the shrinker implementation, versus this
> patch which reverts to OOM notifier:
> I am in favor of both patches. But I do want to make sure a fix gets back
> ported to 4.19 where the performance regression was first introduced.
> My concern with reverting to the OOM notifier is, as mst@ put it (in the other
> thread):
> "when linux hits OOM all kind of error paths are being hit, latent bugs start
> triggering, latency goes up drastically."
> The guest could be in a lot of pain before the OOM notifier is invoked, and it
> seems like the shrinker API might allow more fine grained control of when we
> deflate.
> 
> On the other hand, I'm not totally convinced that Wei's patch is an expected
> use of the shrinker/page-cache APIs, and maybe it is fragile. Needs more
> testing and scrutiny.
> 
> It seems to me like the shrinker API is the right API in the long run, perhaps
> with some fixes and modifications. But maybe reverting to OOM notifier is the
> best patch to back port?

In that case can I see some Tested-by reports pls?


> On Fri, Feb 14, 2020 at 6:19 AM David Hildenbrand <david@redhat.com> wrote:
> 
>     >> There was a report that this results in undesired side effects when
>     >> inflating the balloon to shrink the page cache. [1]
>     >>      "When inflating the balloon against page cache (i.e. no free memory
>     >>       remains) vmscan.c will both shrink page cache, but also invoke the
>     >>       shrinkers -- including the balloon's shrinker. So the balloon
>     >>       driver allocates memory which requires reclaim, vmscan gets this
>     >>       memory by shrinking the balloon, and then the driver adds the
>     >>       memory back to the balloon. Basically a busy no-op."
>     >>
>     >> The name "deflate on OOM" makes it pretty clear when deflation should
>     >> happen - after other approaches to reclaim memory failed, not while
>     >> reclaiming. This allows to minimize the footprint of a guest - memory
>     >> will only be taken out of the balloon when really needed.
>     >>
>     >> Especially, a drop_slab() will result in the whole balloon getting
>     >> deflated - undesired.
>     >
>     > Could you explain why some more? drop_caches shouldn't be really used in
>     > any production workloads and if somebody really wants all the cache to
>     > be dropped then why is balloon any different?
>     >
> 
>     Deflation should happen when the guest is out of memory, not when
>     somebody thinks it's time to reclaim some memory. That's what the
>     feature promised from the beginning: Only give the guest more memory in
>     case it *really* needs more memory.
> 
>     Deflate on oom, not deflate on reclaim/memory pressure. (that's what the
>     report was all about)
> 
>     A priority for shrinkers might be a step into the right direction.
> 
>     --
>     Thanks,
> 
>     David / dhildenb
> 
> 



^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v1 3/3] virtio-balloon: Switch back to OOM handler for VIRTIO_BALLOON_F_DEFLATE_ON_OOM
  2020-02-14  9:51   ` David Hildenbrand
  2020-02-14 13:31     ` Wang, Wei W
@ 2020-02-16  9:47     ` Michael S. Tsirkin
  2020-02-21  3:29       ` Tyler Sanderson
  1 sibling, 1 reply; 27+ messages in thread
From: Michael S. Tsirkin @ 2020-02-16  9:47 UTC (permalink / raw)
  To: David Hildenbrand
  Cc: linux-kernel, linux-mm, virtualization, Tyler Sanderson,
	Wei Wang, Alexander Duyck, David Rientjes, Nadav Amit,
	Michal Hocko

On Fri, Feb 14, 2020 at 10:51:43AM +0100, David Hildenbrand wrote:
> On 05.02.20 17:34, David Hildenbrand wrote:
> > Commit 71994620bb25 ("virtio_balloon: replace oom notifier with shrinker")
> > changed the behavior when deflation happens automatically. Instead of
> > deflating when called by the OOM handler, the shrinker is used.
> > 
> > However, the balloon is not simply some slab cache that should be
> > shrunk when under memory pressure. The shrinker does not have a concept of
> > priorities, so this behavior cannot be configured.
> > 
> > There was a report that this results in undesired side effects when
> > inflating the balloon to shrink the page cache. [1]
> > 	"When inflating the balloon against page cache (i.e. no free memory
> > 	 remains) vmscan.c will both shrink page cache, but also invoke the
> > 	 shrinkers -- including the balloon's shrinker. So the balloon
> > 	 driver allocates memory which requires reclaim, vmscan gets this
> > 	 memory by shrinking the balloon, and then the driver adds the
> > 	 memory back to the balloon. Basically a busy no-op."
> > 
> > The name "deflate on OOM" makes it pretty clear when deflation should
> > happen - after other approaches to reclaim memory failed, not while
> > reclaiming. This allows to minimize the footprint of a guest - memory
> > will only be taken out of the balloon when really needed.
> > 
> > Especially, a drop_slab() will result in the whole balloon getting
> > deflated - undesired. While handling it via the OOM handler might not be
> > perfect, it keeps existing behavior. If we want a different behavior, then
> > we need a new feature bit and document it properly (although, there should
> > be a clear use case and the intended effects should be well described).
> > 
> > Keep using the shrinker for VIRTIO_BALLOON_F_FREE_PAGE_HINT, because
> > this has no such side effects. Always register the shrinker with
> > VIRTIO_BALLOON_F_FREE_PAGE_HINT now. We are always allowed to reuse free
> > pages that are still to be processed by the guest. The hypervisor takes
> > care of identifying and resolving possible races between processing a
> > hinting request and the guest reusing a page.
> > 
> > In contrast to pre commit 71994620bb25 ("virtio_balloon: replace oom
> > notifier with shrinker"), don't add a moodule parameter to configure the
> > number of pages to deflate on OOM. Can be re-added if really needed.
> > Also, pay attention that leak_balloon() returns the number of 4k pages -
> > convert it properly in virtio_balloon_oom_notify().
> > 
> > Note1: using the OOM handler is frowned upon, but it really is what we
> >        need for this feature.
> > 
> > Note2: without VIRTIO_BALLOON_F_MUST_TELL_HOST (iow, always with QEMU) we
> >        could actually skip sending deflation requests to our hypervisor,
> >        making the OOM path *very* simple. Besically freeing pages and
> >        updating the balloon. If the communication with the host ever
> >        becomes a problem on this call path.
> > 
> 
> @Michael, how to proceed with this?
> 

I'd like to see some reports that this helps people.
e.g. a tested-by tag.

> -- 
> Thanks,
> 
> David / dhildenb



^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v1 3/3] virtio-balloon: Switch back to OOM handler for VIRTIO_BALLOON_F_DEFLATE_ON_OOM
  2020-02-16  9:47     ` Michael S. Tsirkin
@ 2020-02-21  3:29       ` Tyler Sanderson
  0 siblings, 0 replies; 27+ messages in thread
From: Tyler Sanderson @ 2020-02-21  3:29 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: David Hildenbrand, linux-kernel, linux-mm, virtualization,
	Wei Wang, Alexander Duyck, David Rientjes, Nadav Amit,
	Michal Hocko

[-- Attachment #1: Type: text/plain, Size: 3842 bytes --]

Testing this patch is on my short-term TODO list, but I wasn't able to get
to it this week. It is prioritized.

In the meantime, I can anecdotally vouch that kernels before 4.19, the ones
using the OOM notifier callback, have roughly 10x faster balloon inflation
when pressuring the cache. So I anticipate this patch will return to that
state and help my use case.

I will try to post official measurements of this patch next week.

On Sun, Feb 16, 2020 at 1:47 AM Michael S. Tsirkin <mst@redhat.com> wrote:

> On Fri, Feb 14, 2020 at 10:51:43AM +0100, David Hildenbrand wrote:
> > On 05.02.20 17:34, David Hildenbrand wrote:
> > > Commit 71994620bb25 ("virtio_balloon: replace oom notifier with
> shrinker")
> > > changed the behavior when deflation happens automatically. Instead of
> > > deflating when called by the OOM handler, the shrinker is used.
> > >
> > > However, the balloon is not simply some slab cache that should be
> > > shrunk when under memory pressure. The shrinker does not have a
> concept of
> > > priorities, so this behavior cannot be configured.
> > >
> > > There was a report that this results in undesired side effects when
> > > inflating the balloon to shrink the page cache. [1]
> > >     "When inflating the balloon against page cache (i.e. no free memory
> > >      remains) vmscan.c will both shrink page cache, but also invoke the
> > >      shrinkers -- including the balloon's shrinker. So the balloon
> > >      driver allocates memory which requires reclaim, vmscan gets this
> > >      memory by shrinking the balloon, and then the driver adds the
> > >      memory back to the balloon. Basically a busy no-op."
> > >
> > > The name "deflate on OOM" makes it pretty clear when deflation should
> > > happen - after other approaches to reclaim memory failed, not while
> > > reclaiming. This allows to minimize the footprint of a guest - memory
> > > will only be taken out of the balloon when really needed.
> > >
> > > Especially, a drop_slab() will result in the whole balloon getting
> > > deflated - undesired. While handling it via the OOM handler might not
> be
> > > perfect, it keeps existing behavior. If we want a different behavior,
> then
> > > we need a new feature bit and document it properly (although, there
> should
> > > be a clear use case and the intended effects should be well described).
> > >
> > > Keep using the shrinker for VIRTIO_BALLOON_F_FREE_PAGE_HINT, because
> > > this has no such side effects. Always register the shrinker with
> > > VIRTIO_BALLOON_F_FREE_PAGE_HINT now. We are always allowed to reuse
> free
> > > pages that are still to be processed by the guest. The hypervisor takes
> > > care of identifying and resolving possible races between processing a
> > > hinting request and the guest reusing a page.
> > >
> > > In contrast to pre commit 71994620bb25 ("virtio_balloon: replace oom
> > > notifier with shrinker"), don't add a moodule parameter to configure
> the
> > > number of pages to deflate on OOM. Can be re-added if really needed.
> > > Also, pay attention that leak_balloon() returns the number of 4k pages
> -
> > > convert it properly in virtio_balloon_oom_notify().
> > >
> > > Note1: using the OOM handler is frowned upon, but it really is what we
> > >        need for this feature.
> > >
> > > Note2: without VIRTIO_BALLOON_F_MUST_TELL_HOST (iow, always with QEMU)
> we
> > >        could actually skip sending deflation requests to our
> hypervisor,
> > >        making the OOM path *very* simple. Besically freeing pages and
> > >        updating the balloon. If the communication with the host ever
> > >        becomes a problem on this call path.
> > >
> >
> > @Michael, how to proceed with this?
> >
>
> I'd like to see some reports that this helps people.
> e.g. a tested-by tag.
>
> > --
> > Thanks,
> >
> > David / dhildenb
>
>

[-- Attachment #2: Type: text/html, Size: 4768 bytes --]

<div dir="ltr">Testing this patch is on my short-term TODO list, but I wasn&#39;t able to get to it this week. It is prioritized.<div><br></div><div>In the meantime, I can anecdotally vouch that kernels before 4.19, the ones using the OOM notifier callback, have roughly 10x faster balloon inflation when pressuring the cache. So I anticipate this patch will return to that state and help my use case.</div><div><br></div><div>I will try to post official measurements of this patch next week.</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Sun, Feb 16, 2020 at 1:47 AM Michael S. Tsirkin &lt;<a href="mailto:mst@redhat.com">mst@redhat.com</a>&gt; wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On Fri, Feb 14, 2020 at 10:51:43AM +0100, David Hildenbrand wrote:<br>
&gt; On 05.02.20 17:34, David Hildenbrand wrote:<br>
&gt; &gt; Commit 71994620bb25 (&quot;virtio_balloon: replace oom notifier with shrinker&quot;)<br>
&gt; &gt; changed the behavior when deflation happens automatically. Instead of<br>
&gt; &gt; deflating when called by the OOM handler, the shrinker is used.<br>
&gt; &gt; <br>
&gt; &gt; However, the balloon is not simply some slab cache that should be<br>
&gt; &gt; shrunk when under memory pressure. The shrinker does not have a concept of<br>
&gt; &gt; priorities, so this behavior cannot be configured.<br>
&gt; &gt; <br>
&gt; &gt; There was a report that this results in undesired side effects when<br>
&gt; &gt; inflating the balloon to shrink the page cache. [1]<br>
&gt; &gt;     &quot;When inflating the balloon against page cache (i.e. no free memory<br>
&gt; &gt;      remains) vmscan.c will both shrink page cache, but also invoke the<br>
&gt; &gt;      shrinkers -- including the balloon&#39;s shrinker. So the balloon<br>
&gt; &gt;      driver allocates memory which requires reclaim, vmscan gets this<br>
&gt; &gt;      memory by shrinking the balloon, and then the driver adds the<br>
&gt; &gt;      memory back to the balloon. Basically a busy no-op.&quot;<br>
&gt; &gt; <br>
&gt; &gt; The name &quot;deflate on OOM&quot; makes it pretty clear when deflation should<br>
&gt; &gt; happen - after other approaches to reclaim memory failed, not while<br>
&gt; &gt; reclaiming. This allows to minimize the footprint of a guest - memory<br>
&gt; &gt; will only be taken out of the balloon when really needed.<br>
&gt; &gt; <br>
&gt; &gt; Especially, a drop_slab() will result in the whole balloon getting<br>
&gt; &gt; deflated - undesired. While handling it via the OOM handler might not be<br>
&gt; &gt; perfect, it keeps existing behavior. If we want a different behavior, then<br>
&gt; &gt; we need a new feature bit and document it properly (although, there should<br>
&gt; &gt; be a clear use case and the intended effects should be well described).<br>
&gt; &gt; <br>
&gt; &gt; Keep using the shrinker for VIRTIO_BALLOON_F_FREE_PAGE_HINT, because<br>
&gt; &gt; this has no such side effects. Always register the shrinker with<br>
&gt; &gt; VIRTIO_BALLOON_F_FREE_PAGE_HINT now. We are always allowed to reuse free<br>
&gt; &gt; pages that are still to be processed by the guest. The hypervisor takes<br>
&gt; &gt; care of identifying and resolving possible races between processing a<br>
&gt; &gt; hinting request and the guest reusing a page.<br>
&gt; &gt; <br>
&gt; &gt; In contrast to pre commit 71994620bb25 (&quot;virtio_balloon: replace oom<br>
&gt; &gt; notifier with shrinker&quot;), don&#39;t add a moodule parameter to configure the<br>
&gt; &gt; number of pages to deflate on OOM. Can be re-added if really needed.<br>
&gt; &gt; Also, pay attention that leak_balloon() returns the number of 4k pages -<br>
&gt; &gt; convert it properly in virtio_balloon_oom_notify().<br>
&gt; &gt; <br>
&gt; &gt; Note1: using the OOM handler is frowned upon, but it really is what we<br>
&gt; &gt;        need for this feature.<br>
&gt; &gt; <br>
&gt; &gt; Note2: without VIRTIO_BALLOON_F_MUST_TELL_HOST (iow, always with QEMU) we<br>
&gt; &gt;        could actually skip sending deflation requests to our hypervisor,<br>
&gt; &gt;        making the OOM path *very* simple. Besically freeing pages and<br>
&gt; &gt;        updating the balloon. If the communication with the host ever<br>
&gt; &gt;        becomes a problem on this call path.<br>
&gt; &gt; <br>
&gt; <br>
&gt; @Michael, how to proceed with this?<br>
&gt; <br>
<br>
I&#39;d like to see some reports that this helps people.<br>
e.g. a tested-by tag.<br>
<br>
&gt; -- <br>
&gt; Thanks,<br>
&gt; <br>
&gt; David / dhildenb<br>
<br>
</blockquote></div>

^ permalink raw reply	[flat|nested] 27+ messages in thread

end of thread, back to index

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-02-05 16:33 [PATCH v1 0/3] virtio-balloon: Fixes + switch back to OOM handler David Hildenbrand
2020-02-05 16:34 ` [PATCH v1 1/3] virtio-balloon: Fix memory leak when unloading while hinting is in progress David Hildenbrand
2020-02-06  8:36   ` Michael S. Tsirkin
2020-02-05 16:34 ` [PATCH v1 2/3] virtio_balloon: Fix memory leaks on errors in virtballoon_probe() David Hildenbrand
2020-02-06  8:36   ` Michael S. Tsirkin
2020-02-05 16:34 ` [PATCH v1 3/3] virtio-balloon: Switch back to OOM handler for VIRTIO_BALLOON_F_DEFLATE_ON_OOM David Hildenbrand
2020-02-05 22:37   ` Tyler Sanderson
2020-02-05 22:52     ` David Hildenbrand
2020-02-05 23:06       ` Tyler Sanderson
2020-02-06  7:40   ` Michael S. Tsirkin
2020-02-06  8:42     ` David Hildenbrand
2020-02-06  8:57       ` Michael S. Tsirkin
2020-02-06  9:05         ` David Hildenbrand
2020-02-06  9:09           ` Michael S. Tsirkin
2020-02-06  8:57   ` Wang, Wei W
2020-02-06  9:11   ` Michael S. Tsirkin
2020-02-06  9:12   ` Michael S. Tsirkin
2020-02-06  9:21     ` David Hildenbrand
2020-02-14  9:51   ` David Hildenbrand
2020-02-14 13:31     ` Wang, Wei W
2020-02-16  9:47     ` Michael S. Tsirkin
2020-02-21  3:29       ` Tyler Sanderson
2020-02-14 14:06   ` Michal Hocko
2020-02-14 14:18     ` David Hildenbrand
2020-02-14 20:48       ` Tyler Sanderson
2020-02-14 21:17         ` David Hildenbrand
2020-02-16  9:46         ` Michael S. Tsirkin

Linux-mm Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-mm/0 linux-mm/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-mm linux-mm/ https://lore.kernel.org/linux-mm \
		linux-mm@kvack.org
	public-inbox-index linux-mm

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kvack.linux-mm


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git