From: Mauricio Faria de Oliveira <mfo@canonical.com>
To: Jens Axboe <axboe@kernel.dk>, linux-block@vger.kernel.org
Cc: "Isaac J. Manjarres" <isaacmanjarres@google.com>,
linux-kernel@vger.kernel.org
Subject: [PATCH 2/2] loop: do not enforce max_loop hard limit by (new) default
Date: Thu, 29 Jun 2023 18:22:56 -0300 [thread overview]
Message-ID: <20230629212256.918239-3-mfo@canonical.com> (raw)
In-Reply-To: <20230629212256.918239-1-mfo@canonical.com>
Problem:
The max_loop parameter is used for 2 different purposes:
1) initial number of loop devices to pre-create on init
2) maximum number of loop devices to add on access/open()
Historically, its default value (zero) caused 1) to create
non-zero number of devices (CONFIG_BLK_DEV_LOOP_MIN_COUNT),
and no hard limit on 2) to add devices with autoloading.
However, the default value changed in commit 85c50197716c
("loop: Fix the max_loop commandline argument treatment
when it is set to 0") to CONFIG_BLK_DEV_LOOP_MIN_COUNT,
for max_loop=0 not to pre-create devices.
That does improve 1), but unfortunately it breaks 2), as
the default behavior changed from no-limit to hard-limit.
Example:
For example, this userspace code broke for N >= CONFIG,
if the user relied on the default value 0 for max_loop:
mknod("/dev/loopN");
open("/dev/loopN"); // now fails with ENXIO
Though affected users may "fix" it with (loop.)max_loop=0,
this means to require a kernel parameter change on stable
kernel update (that commit Fixes: an old commit in stable).
Solution:
The original semantics for the default value in 2) can be
applied if the parameter is not set (ie, default behavior).
This still keeps the intended function in 1) and 2) if set,
and that commit's intended improvement in 1) if max_loop=0.
Before 85c50197716c:
- default: 1) CONFIG devices 2) no limit
- max_loop=0: 1) CONFIG devices 2) no limit
- max_loop=X: 1) X devices 2) X limit
After 85c50197716c:
- default: 1) CONFIG devices 2) CONFIG limit (*)
- max_loop=0: 1) 0 devices (*) 2) no limit
- max_loop=X: 1) X devices 2) X limit
This commit:
- default: 1) CONFIG devices 2) no limit (*)
- max_loop=0: 1) 0 devices 2) no limit
- max_loop=X: 1) X devices 2) X limit
Future:
The issue/regression from that commit only affects code
under the CONFIG_BLOCK_LEGACY_AUTOLOAD deprecation guard,
thus the fix too is contained under it.
Once that deprecated functionality/code is removed, the
purpose 2) of max_loop (hard limit) is no longer in use,
so the module parameter description can be changed then.
Tests:
Linux 6.4-rc7
CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
CONFIG_BLOCK_LEGACY_AUTOLOAD=y
- default (original)
# ls -1 /dev/loop*
/dev/loop-control
/dev/loop0
...
/dev/loop7
# ./test-loop
open: /dev/loop8: No such device or address
- default (patched)
# ls -1 /dev/loop*
/dev/loop-control
/dev/loop0
...
/dev/loop7
# ./test-loop
#
- max_loop=0 (original & patched):
# ls -1 /dev/loop*
/dev/loop-control
# ./test-loop
#
- max_loop=8 (original & patched):
# ls -1 /dev/loop*
/dev/loop-control
/dev/loop0
...
/dev/loop7
# ./test-loop
open: /dev/loop8: No such device or address
- max_loop=0 (patched; CONFIG_BLOCK_LEGACY_AUTOLOAD is not set)
# ls -1 /dev/loop*
/dev/loop-control
# ./test-loop
open: /dev/loop8: No such device or address
Fixes: 85c50197716c ("loop: Fix the max_loop commandline argument treatment when it is set to 0")
Signed-off-by: Mauricio Faria de Oliveira <mfo@canonical.com>
---
drivers/block/loop.c | 36 ++++++++++++++++++++++++++++++++++--
1 file changed, 34 insertions(+), 2 deletions(-)
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 21bcd6ffe241..86060be853bc 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -1777,14 +1777,43 @@ static const struct block_device_operations lo_fops = {
/*
* If max_loop is specified, create that many devices upfront.
* This also becomes a hard limit. If max_loop is not specified,
+ * the default isn't a hard limit (as before commit 85c50197716c
+ * changed the default value from 0 for max_loop=0 reasons), just
* create CONFIG_BLK_DEV_LOOP_MIN_COUNT loop devices at module
* init time. Loop devices can be requested on-demand with the
* /dev/loop-control interface, or be instantiated by accessing
* a 'dead' device node.
*/
static int max_loop = CONFIG_BLK_DEV_LOOP_MIN_COUNT;
-module_param(max_loop, int, 0444);
+
+#ifdef CONFIG_BLOCK_LEGACY_AUTOLOAD
+static bool max_loop_specified;
+
+static int max_loop_param_set_int(const char *val,
+ const struct kernel_param *kp)
+{
+ int ret;
+
+ ret = param_set_int(val, kp);
+ if (ret < 0)
+ return ret;
+
+ max_loop_specified = true;
+ return 0;
+}
+
+static const struct kernel_param_ops max_loop_param_ops = {
+ .set = max_loop_param_set_int,
+ .get = param_get_int,
+};
+
+module_param_cb(max_loop, &max_loop_param_ops, &max_loop, 0444);
MODULE_PARM_DESC(max_loop, "Maximum number of loop devices");
+#else
+module_param(max_loop, int, 0444);
+MODULE_PARM_DESC(max_loop, "Initial number of loop devices");
+#endif
+
module_param(max_part, int, 0444);
MODULE_PARM_DESC(max_part, "Maximum number of partitions per loop device");
@@ -2100,7 +2129,7 @@ static void loop_probe(dev_t dev)
{
int idx = MINOR(dev) >> part_shift;
- if (max_loop && idx >= max_loop)
+ if (max_loop_specified && max_loop && idx >= max_loop)
return;
loop_add(idx);
}
@@ -2288,6 +2317,9 @@ module_exit(loop_exit);
static int __init max_loop_setup(char *str)
{
max_loop = simple_strtol(str, NULL, 0);
+#ifdef CONFIG_BLOCK_LEGACY_AUTOLOAD
+ max_loop_specified = true;
+#endif
return 1;
}
--
2.39.2
prev parent reply other threads:[~2023-06-29 21:24 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-06-29 21:22 [PATCH 0/2] loop: fix regression from max_loop default value change Mauricio Faria de Oliveira
2023-06-29 21:22 ` [PATCH 1/2] loop: deprecate autoloading callback loop_probe() Mauricio Faria de Oliveira
2023-06-29 21:22 ` Mauricio Faria de Oliveira [this message]
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=20230629212256.918239-3-mfo@canonical.com \
--to=mfo@canonical.com \
--cc=axboe@kernel.dk \
--cc=isaacmanjarres@google.com \
--cc=linux-block@vger.kernel.org \
--cc=linux-kernel@vger.kernel.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
all inboxes | Powered by JetHome®