From: Zizhi Wo <wozizhi@huaweicloud.com>
To: Niklas Cassel <cassel@kernel.org>, Jens Axboe <axboe@kernel.dk>,
Shaohua Li <shli@fb.com>, Kyungchan Koh <kkc6196@fb.com>
Cc: Damien Le Moal <dlemoal@kernel.org>,
syzbot+643a6dd130546afdf1fb@syzkaller.appspotmail.com,
linux-block@vger.kernel.org
Subject: Re: [PATCH] null_blk: serialize configfs attribute updates with device setup
Date: Sat, 15 Aug 2026 10:07:08 +0800 [thread overview]
Message-ID: <4591d9cc-3dcb-46b8-833e-4a98a0bbdc8e@huaweicloud.com> (raw)
In-Reply-To: <20260813141456.1625857-2-cassel@kernel.org>
Hi Niklas,
在 2026/8/13 22:14, Niklas Cassel 写道:
> The attribute store methods generated with NULLB_DEVICE_ATTR() refuse to
> change the configuration of a live device by testing
> NULLB_DEV_FL_CONFIGURED, but that flag is only set by
> nullb_device_power_store() after null_add_dev() has returned, and the
> store methods take no lock at all. configfs only serializes writes to
> the same open file (buffer->mutex), so a write to any attribute can run
> concurrently with null_add_dev() and change the device configuration
> while it is being used.
>
> null_add_dev() reads the configuration several times, e.g. dev->zoned is
> read once to set up the queue limits and once to initialize the zone
> resources:
>
> CPU0: echo 1 > nullb0/power CPU1: echo 1 > nullb0/zoned
> nullb_device_power_store()
> mutex_lock(&lock)
> null_add_dev()
> if (dev->zoned) -> false
> /* no BLK_FEAT_ZONED */ nullb_device_zoned_store()
> test_bit(FL_CONFIGURED) -> 0
> dev->zoned = true
> blk_mq_alloc_disk()
> /* queue is not zoned */
> if (nullb->dev->zoned) -> true
> null_register_zoned_dev()
> blk_revalidate_disk_zones()
>
> blk_revalidate_disk_zones() is then called for a queue that does not
> have BLK_FEAT_ZONED set, which triggers its WARN_ON_ONCE() and fails the
> device setup with -EIO:
>
> WARNING: CPU: 2 PID: 322 at block/blk-zoned.c:2357 blk_revalidate_disk_zones+0x4c/0x560
>
> Clearing dev->zoned in the same window is worse: the queue is created
> with BLK_FEAT_ZONED but the zone resources are never initialized, so
> add_disk() succeeds for a zoned disk that has no zones. And a store that
> lands after the last dev->zoned test leaves dev->zoned set while
> dev->zones is still NULL, which null_process_zoned_cmd() dereferences on
> the first write.
>
> Fix this by taking the global lock, which nullb_device_power_store()
> already holds across null_add_dev() and null_del_dev(), around both the
> NULLB_DEV_FL_CONFIGURED test and the update of the device configuration.
> The submit_queues and poll_queues apply callbacks are now called with
> that lock held, so remove the locking they did themselves.
>
> Since the store methods can run as soon as configfs_register_subsystem()
> returns, that is, before null_init() gets to mutex_init(&lock), also
> initialize the lock statically with DEFINE_MUTEX().
>
> Fixes: 3bf2bd20734e ("nullb: add configfs interface")
> Reported-by: syzbot+643a6dd130546afdf1fb@syzkaller.appspotmail.com
> Closes: https://lore.kernel.org/linux-block/6a7d0b3f.ac361c09.22ff0a.004c.GAE@google.com/
> Signed-off-by: Niklas Cassel <cassel@kernel.org>
> ---
> drivers/block/null_blk/main.c | 39 ++++++++++++++++-------------------
> 1 file changed, 18 insertions(+), 21 deletions(-)
>
> diff --git a/drivers/block/null_blk/main.c b/drivers/block/null_blk/main.c
> index f8c0fd57e041..2e8f99873956 100644
> --- a/drivers/block/null_blk/main.c
> +++ b/drivers/block/null_blk/main.c
> @@ -66,7 +66,7 @@ struct nullb_page {
> #define NULLB_PAGE_FREE (MAP_SZ - 2)
>
> static LIST_HEAD(nullb_list);
> -static struct mutex lock;
> +static DEFINE_MUTEX(lock);
> static int null_major;
> static DEFINE_IDA(nullb_indexes);
> static struct blk_mq_tag_set tag_set;
> @@ -340,7 +340,15 @@ static ssize_t nullb_device_bool_attr_store(bool *val, const char *page,
> return count;
> }
>
> -/* The following macro should only be used with TYPE = {uint, ulong, bool}. */
> +/*
> + * The following macro should only be used with TYPE = {uint, ulong, bool}.
> + *
> + * The device configuration is modified under the global lock to serialize
> + * attribute changes against null_add_dev() and null_del_dev(): without this,
> + * an attribute could be changed while null_add_dev() is running, that is,
> + * before NULLB_DEV_FL_CONFIGURED is set, which would let null_add_dev()
> + * observe inconsistent values for the device configuration.
> + */
> #define NULLB_DEVICE_ATTR(NAME, TYPE, APPLY) \
> static ssize_t \
> nullb_device_##NAME##_show(struct config_item *item, char *page) \
> @@ -360,13 +368,16 @@ nullb_device_##NAME##_store(struct config_item *item, const char *page, \
> ret = nullb_device_##TYPE##_attr_store(&new_value, page, count);\
> if (ret < 0) \
> return ret; \
> + mutex_lock(&lock); \
> if (apply_fn) \
> ret = apply_fn(dev, new_value); \
> else if (test_bit(NULLB_DEV_FL_CONFIGURED, &dev->flags)) \
> ret = -EBUSY; \
> + if (ret >= 0) \
> + dev->NAME = new_value; \
> + mutex_unlock(&lock); \
> if (ret < 0) \
> return ret; \
> - dev->NAME = new_value; \
> return count; \
> } \
> CONFIGFS_ATTR(nullb_device_, NAME);
> @@ -379,6 +390,8 @@ static int nullb_update_nr_hw_queues(struct nullb_device *dev,
> struct blk_mq_tag_set *set;
> int ret, nr_hw_queues;
>
> + lockdep_assert_held(&lock);
> +
> if (!dev->nullb)
> return 0;
>
> @@ -421,25 +434,13 @@ static int nullb_update_nr_hw_queues(struct nullb_device *dev,
> static int nullb_apply_submit_queues(struct nullb_device *dev,
> unsigned int submit_queues)
> {
> - int ret;
> -
> - mutex_lock(&lock);
> - ret = nullb_update_nr_hw_queues(dev, submit_queues, dev->poll_queues);
> - mutex_unlock(&lock);
> -
> - return ret;
> + return nullb_update_nr_hw_queues(dev, submit_queues, dev->poll_queues);
> }
>
> static int nullb_apply_poll_queues(struct nullb_device *dev,
> unsigned int poll_queues)
> {
> - int ret;
> -
> - mutex_lock(&lock);
> - ret = nullb_update_nr_hw_queues(dev, dev->submit_queues, poll_queues);
> - mutex_unlock(&lock);
> -
> - return ret;
> + return nullb_update_nr_hw_queues(dev, dev->submit_queues, poll_queues);
> }
>
> NULLB_DEVICE_ATTR(size, ulong, NULL);
> @@ -2166,8 +2167,6 @@ static int __init null_init(void)
> if (ret)
> return ret;
>
> - mutex_init(&lock);
> -
> null_major = register_blkdev(0, "nullb");
> if (null_major < 0) {
> ret = null_major;
> @@ -2211,8 +2210,6 @@ static void __exit null_exit(void)
>
> if (tag_set.ops)
> blk_mq_free_tag_set(&tag_set);
> -
> - mutex_destroy(&lock);
> }
>
> module_init(null_init);
Thanks for the patch. This issue has already been addressed in my
null_blk series posted back in July:
https://lore.kernel.org/all/20260725022509.714271-1-
wozizhi@huaweicloud.com/
This includes DEFINE_MUTEX and the serialization, but this series hasn't
been merged yet. It has already collected some Reviewed-by tags, and I'm
hoping it can be picked up for mainline soon.
Thanks,
Zizhi Wo
next prev parent reply other threads:[~2026-08-15 2:07 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-13 14:14 [PATCH] null_blk: serialize configfs attribute updates with device setup Niklas Cassel
2026-08-13 15:22 ` Niklas Cassel
2026-08-14 5:25 ` Damien Le Moal
2026-08-15 2:07 ` Zizhi Wo [this message]
2026-08-16 0:01 ` Jens Axboe
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=4591d9cc-3dcb-46b8-833e-4a98a0bbdc8e@huaweicloud.com \
--to=wozizhi@huaweicloud.com \
--cc=axboe@kernel.dk \
--cc=cassel@kernel.org \
--cc=dlemoal@kernel.org \
--cc=kkc6196@fb.com \
--cc=linux-block@vger.kernel.org \
--cc=shli@fb.com \
--cc=syzbot+643a6dd130546afdf1fb@syzkaller.appspotmail.com \
/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