Blame SOURCES/0014-daxctl-fail-reconfigure-device-based-on-kernel-onlin.patch

e0018b
From 99415dfc7c5167c49a5732f577836f68872645b2 Mon Sep 17 00:00:00 2001
e0018b
From: Vishal Verma <vishal.l.verma@intel.com>
e0018b
Date: Wed, 24 Mar 2021 12:09:29 -0700
e0018b
Subject: [PATCH 014/217] daxctl: fail reconfigure-device based on kernel
e0018b
 onlining policy
e0018b
e0018b
If the kernel has a policy set to auto-online any new memory blocks, we
e0018b
know that an attempt to reconfigure a device either in ZONE_MOVABLE, or
e0018b
with the --no-online is going to fail. While we detect this race after
e0018b
the fact, and print a warning, that is often insufficient as the user
e0018b
may be forced to reboot to get out of the situation, resulting in an
e0018b
unpleasant experience.
e0018b
e0018b
Detect whether the kernel policy is set to auto-online. If so, fail
e0018b
device reconfigure operations that we know can't be satisfied. Allow
e0018b
for overriding this safety check via the -f (--force) option. Update the
e0018b
man page to talk about this, and the unit test to test for an expected
e0018b
failure by enabling auto-onlining.
e0018b
e0018b
Cc: Dave Hansen <dave.hansen@intel.com>
e0018b
Reported-by: Chunye Xu <chunye.xu@intel.com>
e0018b
Reported-by: Dan Williams <dan.j.williams@intel.com>
e0018b
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
e0018b
---
e0018b
 .../daxctl/daxctl-reconfigure-device.txt      | 12 ++++++-
e0018b
 daxctl/device.c                               | 10 ++++++
e0018b
 daxctl/lib/libdaxctl-private.h                |  1 +
e0018b
 daxctl/lib/libdaxctl.c                        | 21 +++++++++++
e0018b
 daxctl/lib/libdaxctl.sym                      |  5 +++
e0018b
 daxctl/libdaxctl.h                            |  1 +
e0018b
 test/daxctl-devices.sh                        | 36 +++++++++++++++++++
e0018b
 7 files changed, 85 insertions(+), 1 deletion(-)
e0018b
e0018b
diff --git a/Documentation/daxctl/daxctl-reconfigure-device.txt b/Documentation/daxctl/daxctl-reconfigure-device.txt
e0018b
index ad33eda..f112b3c 100644
e0018b
--- a/Documentation/daxctl/daxctl-reconfigure-device.txt
e0018b
+++ b/Documentation/daxctl/daxctl-reconfigure-device.txt
e0018b
@@ -119,6 +119,10 @@ recommended to use the --no-online option described below. This will abridge
e0018b
 the device reconfiguration operation to just hotplugging the memory, and
e0018b
 refrain from then onlining it.
e0018b
 
e0018b
+In case daxctl detects that there is a kernel policy to auto-online blocks
e0018b
+(via /sys/devices/system/memory/auto_online_blocks), then reconfiguring to
e0018b
+system-ram will result in a failure. This can be overridden with '--force'.
e0018b
+
e0018b
 OPTIONS
e0018b
 -------
e0018b
 include::region-option.txt[]
e0018b
@@ -162,12 +166,18 @@ include::movable-options.txt[]
e0018b
 
e0018b
 -f::
e0018b
 --force::
e0018b
-	When converting from "system-ram" mode to "devdax", it is expected
e0018b
+	- When converting from "system-ram" mode to "devdax", it is expected
e0018b
 	that all the memory sections are first made offline. By default,
e0018b
 	daxctl won't touch online memory. However with this option, attempt
e0018b
 	to offline the memory on the NUMA node associated with the dax device
e0018b
 	before converting it back to "devdax" mode.
e0018b
 
e0018b
+	- Additionally, if a kernel policy to auto-online blocks is detected,
e0018b
+	reconfiguration to system-ram fails. With this option, the failure can
e0018b
+	be overridden to allow reconfiguration regardless of kernel policy.
e0018b
+	Doing this may result in a successful reconfiguration, but it may
e0018b
+	not be possible to subsequently offline the memory without a reboot.
e0018b
+
e0018b
 
e0018b
 include::human-option.txt[]
e0018b
 
e0018b
diff --git a/daxctl/device.c b/daxctl/device.c
e0018b
index 0721a57..a427b7d 100644
e0018b
--- a/daxctl/device.c
e0018b
+++ b/daxctl/device.c
e0018b
@@ -541,8 +541,18 @@ static int disable_devdax_device(struct daxctl_dev *dev)
e0018b
 
e0018b
 static int reconfig_mode_system_ram(struct daxctl_dev *dev)
e0018b
 {
e0018b
+	const char *devname = daxctl_dev_get_devname(dev);
e0018b
 	int rc, skip_enable = 0;
e0018b
 
e0018b
+	if (param.no_online || !param.no_movable) {
e0018b
+		if (!param.force && daxctl_dev_will_auto_online_memory(dev)) {
e0018b
+			fprintf(stderr,
e0018b
+				"%s: error: kernel policy will auto-online memory, aborting\n",
e0018b
+				devname);
e0018b
+			return -EBUSY;
e0018b
+		}
e0018b
+	}
e0018b
+
e0018b
 	if (daxctl_dev_is_enabled(dev)) {
e0018b
 		rc = disable_devdax_device(dev);
e0018b
 		if (rc < 0)
e0018b
diff --git a/daxctl/lib/libdaxctl-private.h b/daxctl/lib/libdaxctl-private.h
e0018b
index af257fd..ae45311 100644
e0018b
--- a/daxctl/lib/libdaxctl-private.h
e0018b
+++ b/daxctl/lib/libdaxctl-private.h
e0018b
@@ -111,6 +111,7 @@ struct daxctl_memory {
e0018b
 	char *node_path;
e0018b
 	unsigned long block_size;
e0018b
 	enum memory_zones zone;
e0018b
+	bool auto_online;
e0018b
 };
e0018b
 
e0018b
 
e0018b
diff --git a/daxctl/lib/libdaxctl.c b/daxctl/lib/libdaxctl.c
e0018b
index 479e8f6..879f7e6 100644
e0018b
--- a/daxctl/lib/libdaxctl.c
e0018b
+++ b/daxctl/lib/libdaxctl.c
e0018b
@@ -1644,3 +1644,24 @@ DAXCTL_EXPORT int daxctl_memory_is_movable(struct daxctl_memory *mem)
e0018b
 		return rc;
e0018b
 	return (mem->zone == MEM_ZONE_MOVABLE) ? 1 : 0;
e0018b
 }
e0018b
+
e0018b
+DAXCTL_EXPORT int daxctl_dev_will_auto_online_memory(struct daxctl_dev *dev)
e0018b
+{
e0018b
+	const char *auto_path = "/sys/devices/system/memory/auto_online_blocks";
e0018b
+	const char *devname = daxctl_dev_get_devname(dev);
e0018b
+	struct daxctl_ctx *ctx = daxctl_dev_get_ctx(dev);
e0018b
+	char buf[SYSFS_ATTR_SIZE];
e0018b
+
e0018b
+	/*
e0018b
+	 * If we can't read the policy for some reason, don't fail yet. Assume
e0018b
+	 * the auto-onlining policy is absent, and carry on. If onlining blocks
e0018b
+	 * does result in the memory being in an inconsistent state, we have a
e0018b
+	 * check and warning for it after the fact
e0018b
+	 */
e0018b
+	if (sysfs_read_attr(ctx, auto_path, buf) != 0)
e0018b
+		err(ctx, "%s: Unable to determine auto-online policy: %s\n",
e0018b
+				devname, strerror(errno));
e0018b
+
e0018b
+	/* match both "online" and "online_movable" */
e0018b
+	return !strncmp(buf, "online", 6);
e0018b
+}
e0018b
diff --git a/daxctl/lib/libdaxctl.sym b/daxctl/lib/libdaxctl.sym
e0018b
index a4e1684..892e393 100644
e0018b
--- a/daxctl/lib/libdaxctl.sym
e0018b
+++ b/daxctl/lib/libdaxctl.sym
e0018b
@@ -91,3 +91,8 @@ global:
e0018b
 	daxctl_mapping_get_size;
e0018b
 	daxctl_dev_set_mapping;
e0018b
 } LIBDAXCTL_7;
e0018b
+
e0018b
+LIBDAXCTL_9 {
e0018b
+global:
e0018b
+	daxctl_dev_will_auto_online_memory;
e0018b
+} LIBDAXCTL_8;
e0018b
diff --git a/daxctl/libdaxctl.h b/daxctl/libdaxctl.h
e0018b
index e82b274..30ab51a 100644
e0018b
--- a/daxctl/libdaxctl.h
e0018b
+++ b/daxctl/libdaxctl.h
e0018b
@@ -71,6 +71,7 @@ int daxctl_dev_disable(struct daxctl_dev *dev);
e0018b
 int daxctl_dev_enable_devdax(struct daxctl_dev *dev);
e0018b
 int daxctl_dev_enable_ram(struct daxctl_dev *dev);
e0018b
 int daxctl_dev_get_target_node(struct daxctl_dev *dev);
e0018b
+int daxctl_dev_will_auto_online_memory(struct daxctl_dev *dev);
e0018b
 
e0018b
 struct daxctl_memory;
e0018b
 struct daxctl_memory *daxctl_dev_get_memory(struct daxctl_dev *dev);
e0018b
diff --git a/test/daxctl-devices.sh b/test/daxctl-devices.sh
e0018b
index 496e4f2..eed5906 100755
e0018b
--- a/test/daxctl-devices.sh
e0018b
+++ b/test/daxctl-devices.sh
e0018b
@@ -64,6 +64,26 @@ daxctl_get_mode()
e0018b
 	"$DAXCTL" list -d "$1" | jq -er '.[].mode'
e0018b
 }
e0018b
 
e0018b
+set_online_policy()
e0018b
+{
e0018b
+	echo "online" > /sys/devices/system/memory/auto_online_blocks
e0018b
+}
e0018b
+
e0018b
+unset_online_policy()
e0018b
+{
e0018b
+	echo "offline" > /sys/devices/system/memory/auto_online_blocks
e0018b
+}
e0018b
+
e0018b
+save_online_policy()
e0018b
+{
e0018b
+	saved_policy="$(cat /sys/devices/system/memory/auto_online_blocks)"
e0018b
+}
e0018b
+
e0018b
+restore_online_policy()
e0018b
+{
e0018b
+	echo "$saved_policy" > /sys/devices/system/memory/auto_online_blocks
e0018b
+}
e0018b
+
e0018b
 daxctl_test()
e0018b
 {
e0018b
 	local daxdev
e0018b
@@ -71,6 +91,9 @@ daxctl_test()
e0018b
 	daxdev=$(daxctl_get_dev "$testdev")
e0018b
 	test -n "$daxdev"
e0018b
 
e0018b
+	# these tests need to run with kernel onlining policy turned off
e0018b
+	save_online_policy
e0018b
+	unset_online_policy
e0018b
 	"$DAXCTL" reconfigure-device -N -m system-ram "$daxdev"
e0018b
 	[[ $(daxctl_get_mode "$daxdev") == "system-ram" ]]
e0018b
 	"$DAXCTL" online-memory "$daxdev"
e0018b
@@ -81,6 +104,19 @@ daxctl_test()
e0018b
 	[[ $(daxctl_get_mode "$daxdev") == "system-ram" ]]
e0018b
 	"$DAXCTL" reconfigure-device -f -m devdax "$daxdev"
e0018b
 	[[ $(daxctl_get_mode "$daxdev") == "devdax" ]]
e0018b
+
e0018b
+	# this tests for reconfiguration failure if an online-policy is set
e0018b
+	set_online_policy
e0018b
+	: "This command is expected to fail:"
e0018b
+	if ! "$DAXCTL" reconfigure-device -N -m system-ram "$daxdev"; then
e0018b
+		echo "reconfigure failed as expected"
e0018b
+	else
e0018b
+		echo "reconfigure succeded, expected failure"
e0018b
+		restore_online_policy
e0018b
+		return 1
e0018b
+	fi
e0018b
+
e0018b
+	restore_online_policy
e0018b
 }
e0018b
 
e0018b
 find_testdev
e0018b
-- 
e0018b
2.27.0
e0018b