From nobody Mon Apr 6 19:39:22 2026 Received: from mail-dy1-f178.google.com (mail-dy1-f178.google.com [74.125.82.178]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3BC3F33A704 for ; Wed, 18 Mar 2026 07:53:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.178 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773820384; cv=none; b=tHmqL7O/PPO1s9NWRu0sT2xnI5snLW3oOn/J8ck5VZf/1YRfMiAKTJ23cJSS65OY7J/XqTwZW0FH1B50pE/6gR0/CePpKbOILWnTB/eMjusouGYZm30t/GyajIchOuFqf41bCtIThyL/H1XgRf78H2WZLvGBejMDyo0VVM1q38U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773820384; c=relaxed/simple; bh=iUsNzNGlOUjgfwbj0hzM1wDqa3hF7+28cX07Ddu4Qjs=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:To:Cc; b=k/PM02OfBnNal2cCLA3hcbZcGhxMcRc50uRNqKlBFLrvsunXzIr1EXuI8si7NnYmohg9RPa317ckKKK/fPVVLJA+q09xMn7mpsLEUtf3S8DXmvTBOl2/eD0PBJ8godcjoh9Y95SQqLrVyd7Ouj9l7WAp+lsdkSrdwuJPPte59ao= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=D1lkGKIB; arc=none smtp.client-ip=74.125.82.178 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="D1lkGKIB" Received: by mail-dy1-f178.google.com with SMTP id 5a478bee46e88-2c0e38f3f60so340226eec.1 for ; Wed, 18 Mar 2026 00:53:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773820381; x=1774425181; darn=vger.kernel.org; h=cc:to:message-id:content-transfer-encoding:mime-version:subject :date:from:from:to:cc:subject:date:message-id:reply-to; bh=ScKc2Pflo1uvLlUk/jN8+wzFHf81p4mamY2h3zBpJ4g=; b=D1lkGKIBBqVDrRIajtPeurzr/0NWHU0iEEFHzR4n+oDJr7x198+OvGmLsZwKQbwnVc ZsmGIzq0foTHjuS+opYFsEJNZ9lr7ZjQXa7McLf/ZCJv2U7BIVMI41NyLFWNQOy3FtpT L2hwZjo91stZ1fuW+A3ypVQZ36yExPPmwHpeVH5yJq+7Zq8vnWaQ/rb9uL+TurUGg0+y Nb5nRaZTHQy85FvmXwhO5Et8aKYI1h2NvTrkSRRGIEqhywXT37WGSBuOF1o1IoKhUOV+ bGQ71JYhypCHmj+3BMPnVUEUvPRRwU01Q4q3b/mM6yG03WnAXvcrgmPVQuAZ+3JtgUxb k6Vg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773820381; x=1774425181; h=cc:to:message-id:content-transfer-encoding:mime-version:subject :date:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=ScKc2Pflo1uvLlUk/jN8+wzFHf81p4mamY2h3zBpJ4g=; b=Ik8/QuVLnPDZnYcUTpaA/T6JDGoe6d1YQg5Qj67RgRIhPqF4cCcQltSSDXeryO2fbo f9e4n9+v0Kr3PlgOMb/cgn1SVLqkJ/hjS5bp7IVne2JgKJUUNO0StSPXcealJGkTvpPe NOlAsoCm+FruvBPg1lnBjedMxCoRF+MkH/8wVG56360cNfTn2GGrtQ/BHLY3/eHRyazc zewYCRg6uSszq32qcSjw20NrMTGmnbh0ivL+UXEMrVGz+vpCVr0Lu0Ng2xhGXXsVxsxs vrzAq5FDVM0WMsFlooKFLjfkhQQbS/VuvSQnrG+Kz3Tmpx17jfOFx9PefNLvWQze945E c1WQ== X-Forwarded-Encrypted: i=1; AJvYcCU6sZHqWR//0QmMiBSk0rZEwMGjkK3jVjZ+7DmS7iyADGZqPUKTo+nOijTZd5XsfWlaErO2LK7MNYO2Tu4=@vger.kernel.org X-Gm-Message-State: AOJu0Yy0OiA20BzuwUsS1rpgZgozr6fFXEYiFjbEP8QWNdkCLhmj1n+8 hIyo5yYThdnOc0o9UcK9m6qmx/2sTOGR7aTidv414hPQf1zUtCZiKkn3U+seGg== X-Gm-Gg: ATEYQzxb6D1Hu0dkLT6JsIrZM9cdCZQLs+97P00mbx3ZFu+v8Z4ODvgAs5rL1FNH2pU eXlCf1CW9AyLqUseHvwyOcibI2B3UmSXpgWr8idoLkqfoitDPhbaXe5jtltpb5AkG3ejaPNmR7y Roe1DwpzdD5UuEY8narVCYxrDZlnDBfT5gamuVnqch6zswpbLt9Ww+nwPtwn2xta0YDJt3f6N5X W2ZoQst+x9aSWV5OGaq9NTvzHEj95lPjKbZOnedomFwhdJmKv6CRWDyq5/MWIabgZBLxKpvnFug RTGW+nYXLyEL3jikO9YCO0Y34x1q4DYsO9TV0QITOftyrngvIIIVOM7QGYea6x6dqkzIDxQcFym /DcGfohSfD6wVqzkCKdhubzieDYG4frJAE5GrfXXVlip/2GZup+aP1BiOXt0m1AnU15b4Vg66TD xnNJ5KYceLa1+VP2qC X-Received: by 2002:a05:7300:2214:b0:2be:17b1:e49f with SMTP id 5a478bee46e88-2c0d507c829mr2462388eec.4.1773820381066; Wed, 18 Mar 2026 00:53:01 -0700 (PDT) Received: from wujing. ([74.48.213.230]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-2c0e53b5fa1sm3487280eec.10.2026.03.18.00.52.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 18 Mar 2026 00:53:00 -0700 (PDT) From: Qiliang Yuan Date: Wed, 18 Mar 2026 15:52:46 +0800 Subject: [PATCH] bcache: convert bch_register_lock to rw_semaphore Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260318-wujing-bcache-v1-1-f0b9aaf3f81d@gmail.com> X-B4-Tracking: v=1; b=H4sIAM5ZumkC/6tWKk4tykwtVrJSqFYqSi3LLM7MzwNyDHUUlJIzE vPSU3UzU4B8JSMDIzMDY0ML3fLSrMy8dN2k5MTkjFTdVLOkZOOkFOO0NHNzJaCegqLUtMwKsHn RsbW1ABDZQJ5fAAAA To: Coly Li , Kent Overstreet Cc: linux-bcache@vger.kernel.org, linux-kernel@vger.kernel.org, Qiliang Yuan X-Mailer: b4 0.13.0 Refactor the global bch_register_lock from a mutex to an rw_semaphore to resolve severe lock contention and hung tasks (State D) during large-scale bcache device registration and concurrent sysfs access. Representative call trace from logs: [ 243.082130] INFO: task bcache_cache_se:3496 blocked for more than 121 se= conds. [ 243.130817] Call trace: [ 243.134161] __switch_to+0x7c/0xbc [ 243.138461] __schedule+0x338/0x6f0 [ 243.142847] schedule+0x50/0xe0 [ 243.146884] schedule_preempt_disabled+0x18/0x24 [ 243.152400] __mutex_lock.constprop.0+0x1d4/0x5ec [ 243.158002] __mutex_lock_slowpath+0x1c/0x30 [ 243.163170] mutex_lock+0x50/0x60 [ 243.167397] bch_cache_set_store+0x40/0x80 [bcache] [ 243.173175] sysfs_kf_write+0x4c/0x5c [ 243.177735] kernfs_fop_write_iter+0x130/0x1c0 [ 243.183077] new_sync_write+0xec/0x18c [ 243.187724] vfs_write+0x214/0x2ac [ 243.192022] ksys_write+0x70/0xfc [ 243.196234] __arm64_sys_write+0x24/0x30 [ 243.201057] invoke_syscall+0x50/0x11c [ 243.205705] el0_svc_common.constprop.0+0x158/0x164 [ 243.211483] do_el0_svc+0x2c/0x9c [ 243.215696] el0_svc+0x20/0x30 [ 243.219648] el0_sync_handler+0xb0/0xb4 [ 243.224384] el0_sync+0x160/0x180 This addresses the long-standing issue where a single slow bcache device initialization could block the entire system's bcache management path. Signed-off-by: Qiliang Yuan --- drivers/md/bcache/bcache.h | 2 +- drivers/md/bcache/request.c | 18 +++++----- drivers/md/bcache/super.c | 85 +++++++++++++++++++++++++----------------= ---- drivers/md/bcache/sysfs.c | 82 ++++++++++++++++++++++++++++++++++++++++-= -- drivers/md/bcache/sysfs.h | 8 ++--- 5 files changed, 139 insertions(+), 56 deletions(-) diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h index 8ccacba855475..7ab36987e945b 100644 --- a/drivers/md/bcache/bcache.h +++ b/drivers/md/bcache/bcache.h @@ -1003,7 +1003,7 @@ void bch_write_bdev_super(struct cached_dev *dc, stru= ct closure *parent); extern struct workqueue_struct *bcache_wq; extern struct workqueue_struct *bch_journal_wq; extern struct workqueue_struct *bch_flush_wq; -extern struct mutex bch_register_lock; +extern struct rw_semaphore bch_register_lock; extern struct list_head bch_cache_sets; =20 extern const struct kobj_type bch_cached_dev_ktype; diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c index 82fdea7dea7aa..3062ea2c6b312 100644 --- a/drivers/md/bcache/request.c +++ b/drivers/md/bcache/request.c @@ -1149,15 +1149,15 @@ static void quit_max_writeback_rate(struct cache_se= t *c, struct cached_dev *dc; =20 /* - * mutex bch_register_lock may compete with other parallel requesters, - * or attach/detach operations on other backing device. Waiting to - * the mutex lock may increase I/O request latency for seconds or more. - * To avoid such situation, if mutext_trylock() failed, only writeback - * rate of current cached device is set to 1, and __update_write_back() - * will decide writeback rate of other cached devices (remember now - * c->idle_counter is 0 already). + * rw_semaphore bch_register_lock may compete with other parallel + * requesters, or attach/detach operations on other backing device. + * Waiting to the semaphore lock may increase I/O request latency + * for seconds or more. To avoid such situation, if down_write_trylock() + * failed, only writeback rate of current cached device is set to 1, + * and __update_write_back() will decide writeback rate of other + * cached devices (remember now c->idle_counter is 0 already). */ - if (mutex_trylock(&bch_register_lock)) { + if (down_write_trylock(&bch_register_lock)) { for (i =3D 0; i < c->devices_max_used; i++) { if (!c->devices[i]) continue; @@ -1174,7 +1174,7 @@ static void quit_max_writeback_rate(struct cache_set = *c, */ atomic_long_set(&dc->writeback_rate.rate, 1); } - mutex_unlock(&bch_register_lock); + up_write(&bch_register_lock); } else atomic_long_set(&this_dc->writeback_rate.rate, 1); } diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index c17d4517af22c..187069a7262b9 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -40,7 +40,7 @@ static const char invalid_uuid[] =3D { }; =20 static struct kobject *bcache_kobj; -struct mutex bch_register_lock; +struct rw_semaphore bch_register_lock; bool bcache_is_reboot; LIST_HEAD(bch_cache_sets); static LIST_HEAD(uncached_devices); @@ -1147,7 +1147,7 @@ static void cached_dev_detach_finish(struct work_stru= ct *w) dc->writeback_thread =3D NULL; } =20 - mutex_lock(&bch_register_lock); + down_write(&bch_register_lock); =20 bcache_device_detach(&dc->disk); list_move(&dc->list, &uncached_devices); @@ -1156,7 +1156,7 @@ static void cached_dev_detach_finish(struct work_stru= ct *w) clear_bit(BCACHE_DEV_DETACHING, &dc->disk.flags); clear_bit(BCACHE_DEV_UNLINK_DONE, &dc->disk.flags); =20 - mutex_unlock(&bch_register_lock); + up_write(&bch_register_lock); =20 pr_info("Caching disabled for %pg\n", dc->bdev); =20 @@ -1354,7 +1354,7 @@ static CLOSURE_CALLBACK(cached_dev_free) if (!IS_ERR_OR_NULL(dc->status_update_thread)) kthread_stop(dc->status_update_thread); =20 - mutex_lock(&bch_register_lock); + down_write(&bch_register_lock); =20 if (atomic_read(&dc->running)) { bd_unlink_disk_holder(dc->bdev, dc->disk.disk); @@ -1363,7 +1363,7 @@ static CLOSURE_CALLBACK(cached_dev_free) bcache_device_free(&dc->disk); list_del(&dc->list); =20 - mutex_unlock(&bch_register_lock); + up_write(&bch_register_lock); =20 if (dc->sb_disk) folio_put(virt_to_folio(dc->sb_disk)); @@ -1381,9 +1381,9 @@ static CLOSURE_CALLBACK(cached_dev_flush) closure_type(dc, struct cached_dev, disk.cl); struct bcache_device *d =3D &dc->disk; =20 - mutex_lock(&bch_register_lock); + down_write(&bch_register_lock); bcache_device_unlink(d); - mutex_unlock(&bch_register_lock); + up_write(&bch_register_lock); =20 bch_cache_accounting_destroy(&dc->accounting); kobject_del(&d->kobj); @@ -1496,12 +1496,12 @@ static CLOSURE_CALLBACK(flash_dev_free) { closure_type(d, struct bcache_device, cl); =20 - mutex_lock(&bch_register_lock); + down_write(&bch_register_lock); atomic_long_sub(bcache_dev_sectors_dirty(d), &d->c->flash_dev_dirty_sectors); del_gendisk(d->disk); bcache_device_free(d); - mutex_unlock(&bch_register_lock); + up_write(&bch_register_lock); kobject_put(&d->kobj); } =20 @@ -1509,9 +1509,9 @@ static CLOSURE_CALLBACK(flash_dev_flush) { closure_type(d, struct bcache_device, cl); =20 - mutex_lock(&bch_register_lock); + down_write(&bch_register_lock); bcache_device_unlink(d); - mutex_unlock(&bch_register_lock); + up_write(&bch_register_lock); kobject_del(&d->kobj); continue_at(cl, flash_dev_free, system_percpu_wq); } @@ -1674,7 +1674,7 @@ static CLOSURE_CALLBACK(cache_set_free) bch_btree_cache_free(c); bch_journal_free(c); =20 - mutex_lock(&bch_register_lock); + down_write(&bch_register_lock); bch_bset_sort_state_free(&c->sort); free_pages((unsigned long) c->uuids, ilog2(meta_bucket_pages(&c->cache->s= b))); =20 @@ -1695,7 +1695,7 @@ static CLOSURE_CALLBACK(cache_set_free) kfree(c->devices); =20 list_del(&c->list); - mutex_unlock(&bch_register_lock); + up_write(&bch_register_lock); =20 pr_info("Cache set %pU unregistered\n", c->set_uuid); wake_up(&unregister_wait); @@ -1813,7 +1813,7 @@ static CLOSURE_CALLBACK(__cache_set_unregister) struct bcache_device *d; size_t i; =20 - mutex_lock(&bch_register_lock); + down_write(&bch_register_lock); =20 for (i =3D 0; i < c->devices_max_used; i++) { d =3D c->devices[i]; @@ -1831,7 +1831,7 @@ static CLOSURE_CALLBACK(__cache_set_unregister) } } =20 - mutex_unlock(&bch_register_lock); + up_write(&bch_register_lock); =20 continue_at(cl, cache_set_flush, system_percpu_wq); } @@ -2029,8 +2029,12 @@ static int run_cache_set(struct cache_set *c) goto err; =20 err =3D "error in recovery"; - if (bch_btree_check(c)) + downgrade_write(&bch_register_lock); + if (bch_btree_check(c)) { + up_read(&bch_register_lock); + down_write(&bch_register_lock); goto err; + } =20 bch_journal_mark(c, &journal); bch_initial_gc_finish(c); @@ -2044,8 +2048,11 @@ static int run_cache_set(struct cache_set *c) bch_journal_next(&c->journal); =20 err =3D "error starting allocator thread"; - if (bch_cache_allocator_start(ca)) + if (bch_cache_allocator_start(ca)) { + up_read(&bch_register_lock); + down_write(&bch_register_lock); goto err; + } =20 /* * First place it's safe to allocate: btree_check() and @@ -2061,8 +2068,14 @@ static int run_cache_set(struct cache_set *c) __uuid_write(c); =20 err =3D "bcache: replay journal failed"; - if (bch_journal_replay(c, &journal)) + if (bch_journal_replay(c, &journal)) { + up_read(&bch_register_lock); + down_write(&bch_register_lock); goto err; + } + + up_read(&bch_register_lock); + down_write(&bch_register_lock); } else { unsigned int j; =20 @@ -2409,9 +2422,9 @@ static int register_cache(struct cache_sb *sb, struct= cache_sb_disk *sb_disk, goto out; } =20 - mutex_lock(&bch_register_lock); + down_write(&bch_register_lock); err =3D register_cache_set(ca); - mutex_unlock(&bch_register_lock); + up_write(&bch_register_lock); =20 if (err) { ret =3D -ENODEV; @@ -2486,11 +2499,11 @@ static void register_bdev_worker(struct work_struct= *work) struct async_reg_args *args =3D container_of(work, struct async_reg_args, reg_work.work); =20 - mutex_lock(&bch_register_lock); + down_write(&bch_register_lock); if (register_bdev(args->sb, args->sb_disk, args->bdev_file, args->holder) < 0) fail =3D true; - mutex_unlock(&bch_register_lock); + up_write(&bch_register_lock); =20 if (fail) pr_info("error %s: fail to register backing device\n", @@ -2605,13 +2618,13 @@ static ssize_t register_bcache(struct kobject *k, s= truct kobj_attribute *attr, if (ret =3D=3D -EBUSY) { dev_t dev; =20 - mutex_lock(&bch_register_lock); + down_write(&bch_register_lock); if (lookup_bdev(strim(path), &dev) =3D=3D 0 && bch_is_open(dev)) err =3D "device already registered"; else err =3D "device busy"; - mutex_unlock(&bch_register_lock); + up_write(&bch_register_lock); if (attr =3D=3D &ksysfs_register_quiet) { quiet =3D true; ret =3D size; @@ -2644,9 +2657,9 @@ static ssize_t register_bcache(struct kobject *k, str= uct kobj_attribute *attr, } =20 if (SB_IS_BDEV(sb)) { - mutex_lock(&bch_register_lock); + down_write(&bch_register_lock); ret =3D register_bdev(sb, sb_disk, bdev_file, holder); - mutex_unlock(&bch_register_lock); + up_write(&bch_register_lock); /* blkdev_put() will be called in cached_dev_free() */ if (ret < 0) goto out_free_sb; @@ -2700,7 +2713,7 @@ static ssize_t bch_pending_bdevs_cleanup(struct kobje= ct *k, struct pdev *pdev, *tpdev; struct cache_set *c, *tc; =20 - mutex_lock(&bch_register_lock); + down_write(&bch_register_lock); list_for_each_entry_safe(dc, tdc, &uncached_devices, list) { pdev =3D kmalloc(sizeof(struct pdev), GFP_KERNEL); if (!pdev) @@ -2721,7 +2734,7 @@ static ssize_t bch_pending_bdevs_cleanup(struct kobje= ct *k, } } } - mutex_unlock(&bch_register_lock); + up_write(&bch_register_lock); =20 list_for_each_entry_safe(pdev, tpdev, &pending_devs, list) { pr_info("delete pdev %p\n", pdev); @@ -2748,7 +2761,7 @@ static int bcache_reboot(struct notifier_block *n, un= signed long code, void *x) struct cache_set *c, *tc; struct cached_dev *dc, *tdc; =20 - mutex_lock(&bch_register_lock); + down_write(&bch_register_lock); =20 if (bcache_is_reboot) goto out; @@ -2765,7 +2778,7 @@ static int bcache_reboot(struct notifier_block *n, un= signed long code, void *x) list_empty(&uncached_devices)) goto out; =20 - mutex_unlock(&bch_register_lock); + up_write(&bch_register_lock); =20 pr_info("Stopping all devices:\n"); =20 @@ -2800,7 +2813,7 @@ static int bcache_reboot(struct notifier_block *n, un= signed long code, void *x) while (1) { long timeout =3D start + 10 * HZ - jiffies; =20 - mutex_lock(&bch_register_lock); + down_write(&bch_register_lock); stopped =3D list_empty(&bch_cache_sets) && list_empty(&uncached_devices); =20 @@ -2810,7 +2823,7 @@ static int bcache_reboot(struct notifier_block *n, un= signed long code, void *x) prepare_to_wait(&unregister_wait, &wait, TASK_UNINTERRUPTIBLE); =20 - mutex_unlock(&bch_register_lock); + up_write(&bch_register_lock); schedule_timeout(timeout); } =20 @@ -2821,7 +2834,7 @@ static int bcache_reboot(struct notifier_block *n, un= signed long code, void *x) else pr_notice("Timeout waiting for devices to be closed\n"); out: - mutex_unlock(&bch_register_lock); + up_write(&bch_register_lock); } =20 return NOTIFY_DONE; @@ -2849,7 +2862,6 @@ static void bcache_exit(void) if (bcache_major) unregister_blkdev(bcache_major, "bcache"); unregister_reboot_notifier(&reboot); - mutex_destroy(&bch_register_lock); } =20 /* Check and fixup module parameters */ @@ -2889,15 +2901,14 @@ static int __init bcache_init(void) =20 check_module_parameters(); =20 - mutex_init(&bch_register_lock); + init_rwsem(&bch_register_lock); init_waitqueue_head(&unregister_wait); register_reboot_notifier(&reboot); =20 bcache_major =3D register_blkdev(0, "bcache"); if (bcache_major < 0) { unregister_reboot_notifier(&reboot); - mutex_destroy(&bch_register_lock); - return bcache_major; + return bcache_major; } =20 if (bch_btree_init()) diff --git a/drivers/md/bcache/sysfs.c b/drivers/md/bcache/sysfs.c index 72f38e5b6f5c7..29da507798cd5 100644 --- a/drivers/md/bcache/sysfs.c +++ b/drivers/md/bcache/sysfs.c @@ -285,7 +285,26 @@ SHOW(__bch_cached_dev) #undef var return 0; } -SHOW_LOCKED(bch_cached_dev) +SHOW(bch_cached_dev) +{ + struct cached_dev *dc =3D container_of(kobj, struct cached_dev, + disk.kobj); + ssize_t ret; + + /* + * Statistics attributes like dirty_data read atomic variables and + * can be shown without holding the global bch_register_lock. + */ + if (attr =3D=3D &sysfs_dirty_data || + attr =3D=3D &sysfs_writeback_rate_debug) + return __bch_cached_dev_show(kobj, attr, buf); + + down_read(&bch_register_lock); + ret =3D __bch_cached_dev_show(kobj, attr, buf); + up_read(&bch_register_lock); + + return ret; +} =20 STORE(__cached_dev) { @@ -457,12 +476,24 @@ STORE(bch_cached_dev) { struct cached_dev *dc =3D container_of(kobj, struct cached_dev, disk.kobj); + bool write =3D false; =20 /* no user space access if system is rebooting */ if (bcache_is_reboot) return -EBUSY; =20 - mutex_lock(&bch_register_lock); + if (attr =3D=3D &sysfs_attach || + attr =3D=3D &sysfs_detach || + attr =3D=3D &sysfs_stop || + attr =3D=3D &sysfs_label || + attr =3D=3D &sysfs_cache_mode) + write =3D true; + + if (write) + down_write(&bch_register_lock); + else + down_read(&bch_register_lock); + size =3D __cached_dev_store(kobj, attr, buf, size); =20 if (attr =3D=3D &sysfs_writeback_running) { @@ -495,7 +526,11 @@ STORE(bch_cached_dev) schedule_delayed_work(&dc->writeback_rate_update, dc->writeback_rate_update_seconds * HZ); =20 - mutex_unlock(&bch_register_lock); + if (write) + up_write(&bch_register_lock); + else + up_read(&bch_register_lock); + return size; } =20 @@ -806,7 +841,16 @@ SHOW(__bch_cache_set) =20 return 0; } -SHOW_LOCKED(bch_cache_set) +SHOW(bch_cache_set) +{ + ssize_t ret; + + down_read(&bch_register_lock); + ret =3D __bch_cache_set_show(kobj, attr, buf); + up_read(&bch_register_lock); + + return ret; +} =20 STORE(__bch_cache_set) { @@ -927,7 +971,35 @@ STORE(__bch_cache_set) =20 return size; } -STORE_LOCKED(bch_cache_set) +STORE(bch_cache_set) +{ + bool write =3D false; + ssize_t ret; + + /* no user space access if system is rebooting */ + if (bcache_is_reboot) + return -EBUSY; + + if (attr =3D=3D &sysfs_unregister || + attr =3D=3D &sysfs_stop || + attr =3D=3D &sysfs_flash_vol_create || + attr =3D=3D &sysfs_synchronous) + write =3D true; + + if (write) + down_write(&bch_register_lock); + else + down_read(&bch_register_lock); + + ret =3D __bch_cache_set_store(kobj, attr, buf, size); + + if (write) + up_write(&bch_register_lock); + else + up_read(&bch_register_lock); + + return ret; +} =20 SHOW(bch_cache_set_internal) { diff --git a/drivers/md/bcache/sysfs.h b/drivers/md/bcache/sysfs.h index 65b8bd975ab1e..d5beb997ac9af 100644 --- a/drivers/md/bcache/sysfs.h +++ b/drivers/md/bcache/sysfs.h @@ -24,9 +24,9 @@ static ssize_t fn ## _store(struct kobject *kobj, struct = attribute *attr,\ SHOW(fn) \ { \ ssize_t ret; \ - mutex_lock(&bch_register_lock); \ + down_read(&bch_register_lock); \ ret =3D __ ## fn ## _show(kobj, attr, buf); \ - mutex_unlock(&bch_register_lock); \ + up_read(&bch_register_lock); \ return ret; \ } =20 @@ -34,9 +34,9 @@ SHOW(fn) \ STORE(fn) \ { \ ssize_t ret; \ - mutex_lock(&bch_register_lock); \ + down_read(&bch_register_lock); \ ret =3D __ ## fn ## _store(kobj, attr, buf, size); \ - mutex_unlock(&bch_register_lock); \ + up_read(&bch_register_lock); \ return ret; \ } =20 --- base-commit: 0f61b1860cc3f52aef9036d7235ed1f017632193 change-id: 20260318-wujing-bcache-e6bc3bd3ff77 Best regards, --=20 Qiliang Yuan