Skip to content

Commit 22650a9

Browse files
committed
fs,block: yield devices early
Currently a device is only really released once the umount returns to userspace due to how file closing works. That ultimately could cause an old umount assumption to be violated that concurrent umount and mount don't fail. So an exclusively held device with a temporary holder should be yielded before the filesystem is gone. Add a helper that allows callers to do that. This also allows us to remove the two holder ops that Linus wasn't excited about. Link: https://lore.kernel.org/r/[email protected] Fixes: f3a6088 ("bdev: open block device as files") # mainline only Reviewed-by: Christoph Hellwig <[email protected]> Reviewed-by: Jan Kara <[email protected]> Suggested-by: Linus Torvalds <[email protected]> Signed-off-by: Christian Brauner <[email protected]>
1 parent 3ff56e2 commit 22650a9

File tree

13 files changed

+76
-55
lines changed

13 files changed

+76
-55
lines changed

block/bdev.c

Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -583,9 +583,6 @@ static void bd_finish_claiming(struct block_device *bdev, void *holder,
583583
mutex_unlock(&bdev->bd_holder_lock);
584584
bd_clear_claiming(whole, holder);
585585
mutex_unlock(&bdev_lock);
586-
587-
if (hops && hops->get_holder)
588-
hops->get_holder(holder);
589586
}
590587

591588
/**
@@ -608,7 +605,6 @@ EXPORT_SYMBOL(bd_abort_claiming);
608605
static void bd_end_claim(struct block_device *bdev, void *holder)
609606
{
610607
struct block_device *whole = bdev_whole(bdev);
611-
const struct blk_holder_ops *hops = bdev->bd_holder_ops;
612608
bool unblock = false;
613609

614610
/*
@@ -631,9 +627,6 @@ static void bd_end_claim(struct block_device *bdev, void *holder)
631627
whole->bd_holder = NULL;
632628
mutex_unlock(&bdev_lock);
633629

634-
if (hops && hops->put_holder)
635-
hops->put_holder(holder);
636-
637630
/*
638631
* If this was the last claim, remove holder link and unblock evpoll if
639632
* it was a write holder.
@@ -813,13 +806,21 @@ static void bdev_claim_write_access(struct block_device *bdev, blk_mode_t mode)
813806
bdev->bd_writers++;
814807
}
815808

809+
static inline bool bdev_unclaimed(const struct file *bdev_file)
810+
{
811+
return bdev_file->private_data == BDEV_I(bdev_file->f_mapping->host);
812+
}
813+
816814
static void bdev_yield_write_access(struct file *bdev_file)
817815
{
818816
struct block_device *bdev;
819817

820818
if (bdev_allow_write_mounted)
821819
return;
822820

821+
if (bdev_unclaimed(bdev_file))
822+
return;
823+
823824
bdev = file_bdev(bdev_file);
824825

825826
if (bdev_file->f_mode & FMODE_WRITE_RESTRICTED)
@@ -1012,6 +1013,20 @@ struct file *bdev_file_open_by_path(const char *path, blk_mode_t mode,
10121013
}
10131014
EXPORT_SYMBOL(bdev_file_open_by_path);
10141015

1016+
static inline void bd_yield_claim(struct file *bdev_file)
1017+
{
1018+
struct block_device *bdev = file_bdev(bdev_file);
1019+
void *holder = bdev_file->private_data;
1020+
1021+
lockdep_assert_held(&bdev->bd_disk->open_mutex);
1022+
1023+
if (WARN_ON_ONCE(IS_ERR_OR_NULL(holder)))
1024+
return;
1025+
1026+
if (!bdev_unclaimed(bdev_file))
1027+
bd_end_claim(bdev, holder);
1028+
}
1029+
10151030
void bdev_release(struct file *bdev_file)
10161031
{
10171032
struct block_device *bdev = file_bdev(bdev_file);
@@ -1036,7 +1051,7 @@ void bdev_release(struct file *bdev_file)
10361051
bdev_yield_write_access(bdev_file);
10371052

10381053
if (holder)
1039-
bd_end_claim(bdev, holder);
1054+
bd_yield_claim(bdev_file);
10401055

10411056
/*
10421057
* Trigger event checking and tell drivers to flush MEDIA_CHANGE
@@ -1056,6 +1071,39 @@ void bdev_release(struct file *bdev_file)
10561071
blkdev_put_no_open(bdev);
10571072
}
10581073

1074+
/**
1075+
* bdev_fput - yield claim to the block device and put the file
1076+
* @bdev_file: open block device
1077+
*
1078+
* Yield claim on the block device and put the file. Ensure that the
1079+
* block device can be reclaimed before the file is closed which is a
1080+
* deferred operation.
1081+
*/
1082+
void bdev_fput(struct file *bdev_file)
1083+
{
1084+
if (WARN_ON_ONCE(bdev_file->f_op != &def_blk_fops))
1085+
return;
1086+
1087+
if (bdev_file->private_data) {
1088+
struct block_device *bdev = file_bdev(bdev_file);
1089+
struct gendisk *disk = bdev->bd_disk;
1090+
1091+
mutex_lock(&disk->open_mutex);
1092+
bdev_yield_write_access(bdev_file);
1093+
bd_yield_claim(bdev_file);
1094+
/*
1095+
* Tell release we already gave up our hold on the
1096+
* device and if write restrictions are available that
1097+
* we already gave up write access to the device.
1098+
*/
1099+
bdev_file->private_data = BDEV_I(bdev_file->f_mapping->host);
1100+
mutex_unlock(&disk->open_mutex);
1101+
}
1102+
1103+
fput(bdev_file);
1104+
}
1105+
EXPORT_SYMBOL(bdev_fput);
1106+
10591107
/**
10601108
* lookup_bdev() - Look up a struct block_device by name.
10611109
* @pathname: Name of the block device in the filesystem.

drivers/mtd/devices/block2mtd.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ static void block2mtd_free_device(struct block2mtd_dev *dev)
209209

210210
if (dev->bdev_file) {
211211
invalidate_mapping_pages(dev->bdev_file->f_mapping, 0, -1);
212-
fput(dev->bdev_file);
212+
bdev_fput(dev->bdev_file);
213213
}
214214

215215
kfree(dev);

fs/bcachefs/super-io.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ void bch2_free_super(struct bch_sb_handle *sb)
143143
{
144144
kfree(sb->bio);
145145
if (!IS_ERR_OR_NULL(sb->s_bdev_file))
146-
fput(sb->s_bdev_file);
146+
bdev_fput(sb->s_bdev_file);
147147
kfree(sb->holder);
148148
kfree(sb->sb_name);
149149

fs/cramfs/inode.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,7 @@ static void cramfs_kill_sb(struct super_block *sb)
495495
sb->s_mtd = NULL;
496496
} else if (IS_ENABLED(CONFIG_CRAMFS_BLOCKDEV) && sb->s_bdev) {
497497
sync_blockdev(sb->s_bdev);
498-
fput(sb->s_bdev_file);
498+
bdev_fput(sb->s_bdev_file);
499499
}
500500
kfree(sbi);
501501
}

fs/ext4/super.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5668,7 +5668,7 @@ failed_mount9: __maybe_unused
56685668
brelse(sbi->s_sbh);
56695669
if (sbi->s_journal_bdev_file) {
56705670
invalidate_bdev(file_bdev(sbi->s_journal_bdev_file));
5671-
fput(sbi->s_journal_bdev_file);
5671+
bdev_fput(sbi->s_journal_bdev_file);
56725672
}
56735673
out_fail:
56745674
invalidate_bdev(sb->s_bdev);
@@ -5913,7 +5913,7 @@ static struct file *ext4_get_journal_blkdev(struct super_block *sb,
59135913
out_bh:
59145914
brelse(bh);
59155915
out_bdev:
5916-
fput(bdev_file);
5916+
bdev_fput(bdev_file);
59175917
return ERR_PTR(errno);
59185918
}
59195919

@@ -5952,7 +5952,7 @@ static journal_t *ext4_open_dev_journal(struct super_block *sb,
59525952
out_journal:
59535953
jbd2_journal_destroy(journal);
59545954
out_bdev:
5955-
fput(bdev_file);
5955+
bdev_fput(bdev_file);
59565956
return ERR_PTR(errno);
59575957
}
59585958

@@ -7327,7 +7327,7 @@ static void ext4_kill_sb(struct super_block *sb)
73277327
kill_block_super(sb);
73287328

73297329
if (bdev_file)
7330-
fput(bdev_file);
7330+
bdev_fput(bdev_file);
73317331
}
73327332

73337333
static struct file_system_type ext4_fs_type = {

fs/f2fs/super.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1558,7 +1558,7 @@ static void destroy_device_list(struct f2fs_sb_info *sbi)
15581558

15591559
for (i = 0; i < sbi->s_ndevs; i++) {
15601560
if (i > 0)
1561-
fput(FDEV(i).bdev_file);
1561+
bdev_fput(FDEV(i).bdev_file);
15621562
#ifdef CONFIG_BLK_DEV_ZONED
15631563
kvfree(FDEV(i).blkz_seq);
15641564
#endif

fs/jfs/jfs_logmgr.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1141,7 +1141,7 @@ int lmLogOpen(struct super_block *sb)
11411141
lbmLogShutdown(log);
11421142

11431143
close: /* close external log device */
1144-
fput(bdev_file);
1144+
bdev_fput(bdev_file);
11451145

11461146
free: /* free log descriptor */
11471147
mutex_unlock(&jfs_log_mutex);
@@ -1485,7 +1485,7 @@ int lmLogClose(struct super_block *sb)
14851485
bdev_file = log->bdev_file;
14861486
rc = lmLogShutdown(log);
14871487

1488-
fput(bdev_file);
1488+
bdev_fput(bdev_file);
14891489

14901490
kfree(log);
14911491

fs/reiserfs/journal.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2589,7 +2589,7 @@ static void journal_list_init(struct super_block *sb)
25892589
static void release_journal_dev(struct reiserfs_journal *journal)
25902590
{
25912591
if (journal->j_bdev_file) {
2592-
fput(journal->j_bdev_file);
2592+
bdev_fput(journal->j_bdev_file);
25932593
journal->j_bdev_file = NULL;
25942594
}
25952595
}

fs/romfs/super.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -594,7 +594,7 @@ static void romfs_kill_sb(struct super_block *sb)
594594
#ifdef CONFIG_ROMFS_ON_BLOCK
595595
if (sb->s_bdev) {
596596
sync_blockdev(sb->s_bdev);
597-
fput(sb->s_bdev_file);
597+
bdev_fput(sb->s_bdev_file);
598598
}
599599
#endif
600600
}

fs/super.c

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1515,29 +1515,11 @@ static int fs_bdev_thaw(struct block_device *bdev)
15151515
return error;
15161516
}
15171517

1518-
static void fs_bdev_super_get(void *data)
1519-
{
1520-
struct super_block *sb = data;
1521-
1522-
spin_lock(&sb_lock);
1523-
sb->s_count++;
1524-
spin_unlock(&sb_lock);
1525-
}
1526-
1527-
static void fs_bdev_super_put(void *data)
1528-
{
1529-
struct super_block *sb = data;
1530-
1531-
put_super(sb);
1532-
}
1533-
15341518
const struct blk_holder_ops fs_holder_ops = {
15351519
.mark_dead = fs_bdev_mark_dead,
15361520
.sync = fs_bdev_sync,
15371521
.freeze = fs_bdev_freeze,
15381522
.thaw = fs_bdev_thaw,
1539-
.get_holder = fs_bdev_super_get,
1540-
.put_holder = fs_bdev_super_put,
15411523
};
15421524
EXPORT_SYMBOL_GPL(fs_holder_ops);
15431525

@@ -1562,7 +1544,7 @@ int setup_bdev_super(struct super_block *sb, int sb_flags,
15621544
* writable from userspace even for a read-only block device.
15631545
*/
15641546
if ((mode & BLK_OPEN_WRITE) && bdev_read_only(bdev)) {
1565-
fput(bdev_file);
1547+
bdev_fput(bdev_file);
15661548
return -EACCES;
15671549
}
15681550

@@ -1573,7 +1555,7 @@ int setup_bdev_super(struct super_block *sb, int sb_flags,
15731555
if (atomic_read(&bdev->bd_fsfreeze_count) > 0) {
15741556
if (fc)
15751557
warnf(fc, "%pg: Can't mount, blockdev is frozen", bdev);
1576-
fput(bdev_file);
1558+
bdev_fput(bdev_file);
15771559
return -EBUSY;
15781560
}
15791561
spin_lock(&sb_lock);
@@ -1693,7 +1675,7 @@ void kill_block_super(struct super_block *sb)
16931675
generic_shutdown_super(sb);
16941676
if (bdev) {
16951677
sync_blockdev(bdev);
1696-
fput(sb->s_bdev_file);
1678+
bdev_fput(sb->s_bdev_file);
16971679
}
16981680
}
16991681

0 commit comments

Comments
 (0)