Skip to content

Commit fae0268

Browse files
committed
Merge tag 'vfs-6.9-rc3.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
Pull vfs fixes from Christian Brauner: "This contains a few small fixes. This comes with some delay because I wanted to wait on people running their reproducers and the Easter Holidays meant that those replies came in a little later than usual: - Fix handling of preventing writes to mounted block devices. Since last kernel we allow to prevent writing to mounted block devices provided CONFIG_BLK_DEV_WRITE_MOUNTED isn't set and the block device is opened with restricted writes. When we switched to opening block devices as files we altered the mechanism by which we recognize when a block device has been opened with write restrictions. The detection logic assumed that only read-write mounted filesystems would apply write restrictions to their block devices from other openers. That of course is not true since it also makes sense to apply write restrictions for filesystems that are read-only. Fix the detection logic using an FMODE_* bit. We still have a few left since we freed up a couple a while ago. I also picked up a patch to free up four additional FMODE_* bits scheduled for the next merge window. - Fix counting the number of writers to a block device. This just changes the logic to be consistent. - Fix a bug in aio causing a NULL pointer derefernce after we implemented batched processing in aio. - Finally, add the changes we discussed that allows to yield block devices early even though file closing itself is deferred. This also allows us to remove two holder operations to get and release the holder to align lifetime of file and holder of the block device" * tag 'vfs-6.9-rc3.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: aio: Fix null ptr deref in aio_complete() wakeup fs,block: yield devices early block: count BLK_OPEN_RESTRICT_WRITES openers block: handle BLK_OPEN_RESTRICT_WRITES correctly
2 parents 8cb4a9a + caeb4b0 commit fae0268

File tree

15 files changed

+89
-66
lines changed

15 files changed

+89
-66
lines changed

block/bdev.c

Lines changed: 66 additions & 18 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.
@@ -776,17 +769,17 @@ void blkdev_put_no_open(struct block_device *bdev)
776769

777770
static bool bdev_writes_blocked(struct block_device *bdev)
778771
{
779-
return bdev->bd_writers == -1;
772+
return bdev->bd_writers < 0;
780773
}
781774

782775
static void bdev_block_writes(struct block_device *bdev)
783776
{
784-
bdev->bd_writers = -1;
777+
bdev->bd_writers--;
785778
}
786779

787780
static void bdev_unblock_writes(struct block_device *bdev)
788781
{
789-
bdev->bd_writers = 0;
782+
bdev->bd_writers++;
790783
}
791784

792785
static bool bdev_may_open(struct block_device *bdev, blk_mode_t mode)
@@ -813,21 +806,27 @@ 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);
824-
/* Yield exclusive or shared write access. */
825-
if (bdev_file->f_mode & FMODE_WRITE) {
826-
if (bdev_writes_blocked(bdev))
827-
bdev_unblock_writes(bdev);
828-
else
829-
bdev->bd_writers--;
830-
}
825+
826+
if (bdev_file->f_mode & FMODE_WRITE_RESTRICTED)
827+
bdev_unblock_writes(bdev);
828+
else if (bdev_file->f_mode & FMODE_WRITE)
829+
bdev->bd_writers--;
831830
}
832831

833832
/**
@@ -907,6 +906,8 @@ int bdev_open(struct block_device *bdev, blk_mode_t mode, void *holder,
907906
bdev_file->f_mode |= FMODE_BUF_RASYNC | FMODE_CAN_ODIRECT;
908907
if (bdev_nowait(bdev))
909908
bdev_file->f_mode |= FMODE_NOWAIT;
909+
if (mode & BLK_OPEN_RESTRICT_WRITES)
910+
bdev_file->f_mode |= FMODE_WRITE_RESTRICTED;
910911
bdev_file->f_mapping = bdev->bd_inode->i_mapping;
911912
bdev_file->f_wb_err = filemap_sample_wb_err(bdev_file->f_mapping);
912913
bdev_file->private_data = holder;
@@ -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/aio.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1202,8 +1202,8 @@ static void aio_complete(struct aio_kiocb *iocb)
12021202
spin_lock_irqsave(&ctx->wait.lock, flags);
12031203
list_for_each_entry_safe(curr, next, &ctx->wait.head, w.entry)
12041204
if (avail >= curr->min_nr) {
1205-
list_del_init_careful(&curr->w.entry);
12061205
wake_up_process(curr->w.private);
1206+
list_del_init_careful(&curr->w.entry);
12071207
}
12081208
spin_unlock_irqrestore(&ctx->wait.lock, flags);
12091209
}

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
}

0 commit comments

Comments
 (0)