Skip to content

Commit 2c55559

Browse files
jankaraaxboe
authored andcommitted
bcache: Fix bcache device claiming
Commit 2736e8e ("block: use the holder as indication for exclusive opens") introduced a change that blkdev_put() has to get exclusive holder of the bdev as an argument. However it overlooked that register_bdev() and register_cache() overwrite the bdev->bd_holder field in the block device to point to the real owning object which was not available at the time we called blkdev_get_by_path(). Messing with bdev internals like this is a layering violation and it also causes blkdev_put() to issue warning about mismatching holders. Fix bcache to reopen the block device with appropriate holder once it is available which also restores the behavior that multiple bcache caches cannot claim the same device which was broken by commit 29499ab ("bcache: don't pass a stack address to blkdev_get_by_path"). Fixes: 2736e8e ("block: use the holder as indication for exclusive opens") Signed-off-by: Jan Kara <jack@suse.cz> Reviewed-by: Kent Overstreet <kent.overstreet@linux.dev> Acked-by: Coly Li <colyli@suse.de> Link: https://lore.kernel.org/r/20230622164658.12861-2-jack@suse.cz Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent abcc0cb commit 2c55559

1 file changed

Lines changed: 38 additions & 27 deletions

File tree

drivers/md/bcache/super.c

Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1369,7 +1369,7 @@ static void cached_dev_free(struct closure *cl)
13691369
put_page(virt_to_page(dc->sb_disk));
13701370

13711371
if (!IS_ERR_OR_NULL(dc->bdev))
1372-
blkdev_put(dc->bdev, bcache_kobj);
1372+
blkdev_put(dc->bdev, dc);
13731373

13741374
wake_up(&unregister_wait);
13751375

@@ -1453,7 +1453,6 @@ static int register_bdev(struct cache_sb *sb, struct cache_sb_disk *sb_disk,
14531453

14541454
memcpy(&dc->sb, sb, sizeof(struct cache_sb));
14551455
dc->bdev = bdev;
1456-
dc->bdev->bd_holder = dc;
14571456
dc->sb_disk = sb_disk;
14581457

14591458
if (cached_dev_init(dc, sb->block_size << 9))
@@ -2218,7 +2217,7 @@ void bch_cache_release(struct kobject *kobj)
22182217
put_page(virt_to_page(ca->sb_disk));
22192218

22202219
if (!IS_ERR_OR_NULL(ca->bdev))
2221-
blkdev_put(ca->bdev, bcache_kobj);
2220+
blkdev_put(ca->bdev, ca);
22222221

22232222
kfree(ca);
22242223
module_put(THIS_MODULE);
@@ -2345,7 +2344,6 @@ static int register_cache(struct cache_sb *sb, struct cache_sb_disk *sb_disk,
23452344

23462345
memcpy(&ca->sb, sb, sizeof(struct cache_sb));
23472346
ca->bdev = bdev;
2348-
ca->bdev->bd_holder = ca;
23492347
ca->sb_disk = sb_disk;
23502348

23512349
if (bdev_max_discard_sectors((bdev)))
@@ -2359,7 +2357,7 @@ static int register_cache(struct cache_sb *sb, struct cache_sb_disk *sb_disk,
23592357
* call blkdev_put() to bdev in bch_cache_release(). So we
23602358
* explicitly call blkdev_put() here.
23612359
*/
2362-
blkdev_put(bdev, bcache_kobj);
2360+
blkdev_put(bdev, ca);
23632361
if (ret == -ENOMEM)
23642362
err = "cache_alloc(): -ENOMEM";
23652363
else if (ret == -EPERM)
@@ -2516,10 +2514,11 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr,
25162514
char *path = NULL;
25172515
struct cache_sb *sb;
25182516
struct cache_sb_disk *sb_disk;
2519-
struct block_device *bdev;
2520-
void *holder;
2517+
struct block_device *bdev, *bdev2;
2518+
void *holder = NULL;
25212519
ssize_t ret;
25222520
bool async_registration = false;
2521+
bool quiet = false;
25232522

25242523
#ifdef CONFIG_BCACHE_ASYNC_REGISTRATION
25252524
async_registration = true;
@@ -2548,24 +2547,9 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr,
25482547

25492548
ret = -EINVAL;
25502549
err = "failed to open device";
2551-
bdev = blkdev_get_by_path(strim(path), BLK_OPEN_READ | BLK_OPEN_WRITE,
2552-
bcache_kobj, NULL);
2553-
if (IS_ERR(bdev)) {
2554-
if (bdev == ERR_PTR(-EBUSY)) {
2555-
dev_t dev;
2556-
2557-
mutex_lock(&bch_register_lock);
2558-
if (lookup_bdev(strim(path), &dev) == 0 &&
2559-
bch_is_open(dev))
2560-
err = "device already registered";
2561-
else
2562-
err = "device busy";
2563-
mutex_unlock(&bch_register_lock);
2564-
if (attr == &ksysfs_register_quiet)
2565-
goto done;
2566-
}
2550+
bdev = blkdev_get_by_path(strim(path), BLK_OPEN_READ, NULL, NULL);
2551+
if (IS_ERR(bdev))
25672552
goto out_free_sb;
2568-
}
25692553

25702554
err = "failed to set blocksize";
25712555
if (set_blocksize(bdev, 4096))
@@ -2582,6 +2566,32 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr,
25822566
goto out_put_sb_page;
25832567
}
25842568

2569+
/* Now reopen in exclusive mode with proper holder */
2570+
bdev2 = blkdev_get_by_dev(bdev->bd_dev, BLK_OPEN_READ | BLK_OPEN_WRITE,
2571+
holder, NULL);
2572+
blkdev_put(bdev, NULL);
2573+
bdev = bdev2;
2574+
if (IS_ERR(bdev)) {
2575+
ret = PTR_ERR(bdev);
2576+
bdev = NULL;
2577+
if (ret == -EBUSY) {
2578+
dev_t dev;
2579+
2580+
mutex_lock(&bch_register_lock);
2581+
if (lookup_bdev(strim(path), &dev) == 0 &&
2582+
bch_is_open(dev))
2583+
err = "device already registered";
2584+
else
2585+
err = "device busy";
2586+
mutex_unlock(&bch_register_lock);
2587+
if (attr == &ksysfs_register_quiet) {
2588+
quiet = true;
2589+
ret = size;
2590+
}
2591+
}
2592+
goto out_free_holder;
2593+
}
2594+
25852595
err = "failed to register device";
25862596

25872597
if (async_registration) {
@@ -2619,7 +2629,6 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr,
26192629
goto out_free_sb;
26202630
}
26212631

2622-
done:
26232632
kfree(sb);
26242633
kfree(path);
26252634
module_put(THIS_MODULE);
@@ -2631,7 +2640,8 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr,
26312640
out_put_sb_page:
26322641
put_page(virt_to_page(sb_disk));
26332642
out_blkdev_put:
2634-
blkdev_put(bdev, register_bcache);
2643+
if (bdev)
2644+
blkdev_put(bdev, holder);
26352645
out_free_sb:
26362646
kfree(sb);
26372647
out_free_path:
@@ -2640,7 +2650,8 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr,
26402650
out_module_put:
26412651
module_put(THIS_MODULE);
26422652
out:
2643-
pr_info("error %s: %s\n", path?path:"", err);
2653+
if (!quiet)
2654+
pr_info("error %s: %s\n", path?path:"", err);
26442655
return ret;
26452656
}
26462657

0 commit comments

Comments
 (0)