From: Sasha Levin <sashal@kernel.org>
To: linux-kernel@vger.kernel.org, stable@vger.kernel.org
Cc: David Hildenbrand <david@redhat.com>,
"Michael S . Tsirkin" <mst@redhat.com>,
Sasha Levin <sashal@kernel.org>,
jasowang@redhat.com, virtualization@lists.linux-foundation.org
Subject: [PATCH AUTOSEL 6.4 08/17] virtio-mem: keep retrying on offline_and_remove_memory() errors in Sub Block Mode (SBM)
Date: Tue, 29 Aug 2023 09:31:55 -0400 [thread overview]
Message-ID: <20230829133211.519957-8-sashal@kernel.org> (raw)
In-Reply-To: <20230829133211.519957-1-sashal@kernel.org>
From: David Hildenbrand <david@redhat.com>
[ Upstream commit a31648fd4f96fbe0a4d0aeb16b57a2405c6943c0 ]
In case offline_and_remove_memory() fails in SBM, we leave a completely
unplugged Linux memory block stick around until we try plugging memory
again. We won't try removing that memory block again.
offline_and_remove_memory() may, for example, fail if we're racing with
another alloc_contig_range() user, if allocating temporary memory fails,
or if some memory notifier rejected the offlining request.
Let's handle that case better, by simple retrying to offline and remove
such memory.
Tested using CONFIG_MEMORY_NOTIFIER_ERROR_INJECT.
Signed-off-by: David Hildenbrand <david@redhat.com>
Message-Id: <20230713145551.2824980-4-david@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/virtio/virtio_mem.c | 92 +++++++++++++++++++++++++++++--------
1 file changed, 73 insertions(+), 19 deletions(-)
diff --git a/drivers/virtio/virtio_mem.c b/drivers/virtio/virtio_mem.c
index 1a76ba2bc118c..a5cf92e3e5af2 100644
--- a/drivers/virtio/virtio_mem.c
+++ b/drivers/virtio/virtio_mem.c
@@ -168,6 +168,13 @@ struct virtio_mem {
/* The number of subblocks per Linux memory block. */
uint32_t sbs_per_mb;
+ /*
+ * Some of the Linux memory blocks tracked as "partially
+ * plugged" are completely unplugged and can be offlined
+ * and removed -- which previously failed.
+ */
+ bool have_unplugged_mb;
+
/* Summary of all memory block states. */
unsigned long mb_count[VIRTIO_MEM_SBM_MB_COUNT];
@@ -765,6 +772,34 @@ static int virtio_mem_sbm_offline_and_remove_mb(struct virtio_mem *vm,
return virtio_mem_offline_and_remove_memory(vm, addr, size);
}
+/*
+ * Try (offlining and) removing memory from Linux in case all subblocks are
+ * unplugged. Can be called on online and offline memory blocks.
+ *
+ * May modify the state of memory blocks in virtio-mem.
+ */
+static int virtio_mem_sbm_try_remove_unplugged_mb(struct virtio_mem *vm,
+ unsigned long mb_id)
+{
+ int rc;
+
+ /*
+ * Once all subblocks of a memory block were unplugged, offline and
+ * remove it.
+ */
+ if (!virtio_mem_sbm_test_sb_unplugged(vm, mb_id, 0, vm->sbm.sbs_per_mb))
+ return 0;
+
+ /* offline_and_remove_memory() works for online and offline memory. */
+ mutex_unlock(&vm->hotplug_mutex);
+ rc = virtio_mem_sbm_offline_and_remove_mb(vm, mb_id);
+ mutex_lock(&vm->hotplug_mutex);
+ if (!rc)
+ virtio_mem_sbm_set_mb_state(vm, mb_id,
+ VIRTIO_MEM_SBM_MB_UNUSED);
+ return rc;
+}
+
/*
* See virtio_mem_offline_and_remove_memory(): Try to offline and remove a
* all Linux memory blocks covered by the big block.
@@ -1988,20 +2023,10 @@ static int virtio_mem_sbm_unplug_any_sb_online(struct virtio_mem *vm,
}
unplugged:
- /*
- * Once all subblocks of a memory block were unplugged, offline and
- * remove it. This will usually not fail, as no memory is in use
- * anymore - however some other notifiers might NACK the request.
- */
- if (virtio_mem_sbm_test_sb_unplugged(vm, mb_id, 0, vm->sbm.sbs_per_mb)) {
- mutex_unlock(&vm->hotplug_mutex);
- rc = virtio_mem_sbm_offline_and_remove_mb(vm, mb_id);
- mutex_lock(&vm->hotplug_mutex);
- if (!rc)
- virtio_mem_sbm_set_mb_state(vm, mb_id,
- VIRTIO_MEM_SBM_MB_UNUSED);
- }
-
+ rc = virtio_mem_sbm_try_remove_unplugged_mb(vm, mb_id);
+ if (rc)
+ vm->sbm.have_unplugged_mb = 1;
+ /* Ignore errors, this is not critical. We'll retry later. */
return 0;
}
@@ -2253,12 +2278,13 @@ static int virtio_mem_unplug_request(struct virtio_mem *vm, uint64_t diff)
/*
* Try to unplug all blocks that couldn't be unplugged before, for example,
- * because the hypervisor was busy.
+ * because the hypervisor was busy. Further, offline and remove any memory
+ * blocks where we previously failed.
*/
-static int virtio_mem_unplug_pending_mb(struct virtio_mem *vm)
+static int virtio_mem_cleanup_pending_mb(struct virtio_mem *vm)
{
unsigned long id;
- int rc;
+ int rc = 0;
if (!vm->in_sbm) {
virtio_mem_bbm_for_each_bb(vm, id,
@@ -2280,6 +2306,27 @@ static int virtio_mem_unplug_pending_mb(struct virtio_mem *vm)
VIRTIO_MEM_SBM_MB_UNUSED);
}
+ if (!vm->sbm.have_unplugged_mb)
+ return 0;
+
+ /*
+ * Let's retry (offlining and) removing completely unplugged Linux
+ * memory blocks.
+ */
+ vm->sbm.have_unplugged_mb = false;
+
+ mutex_lock(&vm->hotplug_mutex);
+ virtio_mem_sbm_for_each_mb(vm, id, VIRTIO_MEM_SBM_MB_MOVABLE_PARTIAL)
+ rc |= virtio_mem_sbm_try_remove_unplugged_mb(vm, id);
+ virtio_mem_sbm_for_each_mb(vm, id, VIRTIO_MEM_SBM_MB_KERNEL_PARTIAL)
+ rc |= virtio_mem_sbm_try_remove_unplugged_mb(vm, id);
+ virtio_mem_sbm_for_each_mb(vm, id, VIRTIO_MEM_SBM_MB_OFFLINE_PARTIAL)
+ rc |= virtio_mem_sbm_try_remove_unplugged_mb(vm, id);
+ mutex_unlock(&vm->hotplug_mutex);
+
+ if (rc)
+ vm->sbm.have_unplugged_mb = true;
+ /* Ignore errors, this is not critical. We'll retry later. */
return 0;
}
@@ -2361,9 +2408,9 @@ static void virtio_mem_run_wq(struct work_struct *work)
virtio_mem_refresh_config(vm);
}
- /* Unplug any leftovers from previous runs */
+ /* Cleanup any leftovers from previous runs */
if (!rc)
- rc = virtio_mem_unplug_pending_mb(vm);
+ rc = virtio_mem_cleanup_pending_mb(vm);
if (!rc && vm->requested_size != vm->plugged_size) {
if (vm->requested_size > vm->plugged_size) {
@@ -2375,6 +2422,13 @@ static void virtio_mem_run_wq(struct work_struct *work)
}
}
+ /*
+ * Keep retrying to offline and remove completely unplugged Linux
+ * memory blocks.
+ */
+ if (!rc && vm->in_sbm && vm->sbm.have_unplugged_mb)
+ rc = -EBUSY;
+
switch (rc) {
case 0:
vm->retry_timer_ms = VIRTIO_MEM_RETRY_TIMER_MIN_MS;
--
2.40.1
next prev parent reply other threads:[~2023-08-29 13:35 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-08-29 13:31 [PATCH AUTOSEL 6.4 01/17] arm64: dts: rockchip: correct wifi interrupt flag in eaidk-610 Sasha Levin
2023-08-29 13:31 ` [PATCH AUTOSEL 6.4 02/17] arm64: dts: rockchip: correct wifi interrupt flag in Rock Pi 4B Sasha Levin
2023-08-29 13:31 ` [PATCH AUTOSEL 6.4 03/17] arm64: dts: rockchip: correct wifi interrupt flag in Box Demo Sasha Levin
2023-08-29 13:31 ` [PATCH AUTOSEL 6.4 04/17] vhost-scsi: Fix alignment handling with windows Sasha Levin
2023-08-29 13:31 ` [PATCH AUTOSEL 6.4 05/17] vdpa/mlx5: Correct default number of queues when MQ is on Sasha Levin
2023-08-29 13:31 ` [PATCH AUTOSEL 6.4 06/17] virtio-mem: remove unsafe unplug in Big Block Mode (BBM) Sasha Levin
2023-08-29 13:31 ` [PATCH AUTOSEL 6.4 07/17] virtio-mem: convert most offline_and_remove_memory() errors to -EBUSY Sasha Levin
2023-08-29 13:31 ` Sasha Levin [this message]
2023-08-29 13:31 ` [PATCH AUTOSEL 6.4 09/17] virtio-mem: check if the config changed before fake offlining memory Sasha Levin
2023-08-29 13:31 ` [PATCH AUTOSEL 6.4 10/17] ALSA: hda/cs8409: Support new Dell Dolphin Variants Sasha Levin
2023-08-29 13:31 ` [PATCH AUTOSEL 6.4 11/17] ARM: dts: integrator: fix PCI bus dtc warnings Sasha Levin
2023-08-29 13:31 ` [PATCH AUTOSEL 6.4 12/17] ASoC: rt1308-sdw: fix random louder sound Sasha Levin
2023-08-29 13:32 ` [PATCH AUTOSEL 6.4 13/17] i2c: imx-lpi2c: return -EINVAL when i2c peripheral clk doesn't work Sasha Levin
2023-08-29 13:32 ` [PATCH AUTOSEL 6.4 14/17] fbdev: goldfishfb: Do not check 0 for platform_get_irq() Sasha Levin
2023-08-29 13:32 ` [PATCH AUTOSEL 6.4 15/17] broadcom: b44: Use b44_writephy() return value Sasha Levin
2023-08-29 13:32 ` [PATCH AUTOSEL 6.4 16/17] gpiolib: fix reference leaks when removing GPIO chips still in use Sasha Levin
2023-08-29 13:32 ` [PATCH AUTOSEL 6.4 17/17] drm/amd/pm: Fix temperature unit of SMU v13.0.6 Sasha Levin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230829133211.519957-8-sashal@kernel.org \
--to=sashal@kernel.org \
--cc=david@redhat.com \
--cc=jasowang@redhat.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mst@redhat.com \
--cc=stable@vger.kernel.org \
--cc=virtualization@lists.linux-foundation.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox