Skip to content

Commit ddd65e1

Browse files
committed
block: handle BLK_OPEN_RESTRICT_WRITES correctly
Last kernel release we introduce CONFIG_BLK_DEV_WRITE_MOUNTED. By default this option is set. When it is set the long-standing behavior of being able to write to mounted block devices is enabled. But in order to guard against unintended corruption by writing to the block device buffer cache CONFIG_BLK_DEV_WRITE_MOUNTED can be turned off. In that case it isn't possible to write to mounted block devices anymore. A filesystem may open its block devices with BLK_OPEN_RESTRICT_WRITES which disallows concurrent BLK_OPEN_WRITE access. When we still had the bdev handle around we could recognize BLK_OPEN_RESTRICT_WRITES because the mode was passed around. Since we managed to get rid of the bdev handle we changed that logic to recognize BLK_OPEN_RESTRICT_WRITES based on whether the file was opened writable and writes to that block device are blocked. That logic doesn't work because we do allow BLK_OPEN_RESTRICT_WRITES to be specified without BLK_OPEN_WRITE. Fix the detection logic and use an FMODE_* bit. We could've also abused O_EXCL as an indicator that BLK_OPEN_RESTRICT_WRITES has been requested. For userspace open paths O_EXCL will never be retained but for internal opens where we open files that are never installed into a file descriptor table this is fine. But it would be a gamble that this doesn't cause bugs. Note that BLK_OPEN_RESTRICT_WRITES is an internal only flag that cannot directly be raised by userspace. It is implicitly raised during mounting. Passes xftests and blktests with CONFIG_BLK_DEV_WRITE_MOUNTED set and unset. Link: https://lore.kernel.org/r/[email protected] Link: https://lore.kernel.org/r/20240323-zielbereich-mittragen-6fdf14876c3e@brauner Fixes: 321de65 ("block: don't rely on BLK_OPEN_RESTRICT_WRITES when yielding write access") Reviewed-by: Yu Kuai <[email protected]> Reviewed-by: Jan Kara <[email protected]> Reported-by: Matthew Wilcox <[email protected]> Signed-off-by: Christian Brauner <[email protected]>
1 parent 4cece76 commit ddd65e1

File tree

2 files changed

+9
-7
lines changed

2 files changed

+9
-7
lines changed

block/bdev.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -821,13 +821,11 @@ static void bdev_yield_write_access(struct file *bdev_file)
821821
return;
822822

823823
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-
}
824+
825+
if (bdev_file->f_mode & FMODE_WRITE_RESTRICTED)
826+
bdev_unblock_writes(bdev);
827+
else if (bdev_file->f_mode & FMODE_WRITE)
828+
bdev->bd_writers--;
831829
}
832830

833831
/**
@@ -907,6 +905,8 @@ int bdev_open(struct block_device *bdev, blk_mode_t mode, void *holder,
907905
bdev_file->f_mode |= FMODE_BUF_RASYNC | FMODE_CAN_ODIRECT;
908906
if (bdev_nowait(bdev))
909907
bdev_file->f_mode |= FMODE_NOWAIT;
908+
if (mode & BLK_OPEN_RESTRICT_WRITES)
909+
bdev_file->f_mode |= FMODE_WRITE_RESTRICTED;
910910
bdev_file->f_mapping = bdev->bd_inode->i_mapping;
911911
bdev_file->f_wb_err = filemap_sample_wb_err(bdev_file->f_mapping);
912912
bdev_file->private_data = holder;

include/linux/fs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
121121
#define FMODE_PWRITE ((__force fmode_t)0x10)
122122
/* File is opened for execution with sys_execve / sys_uselib */
123123
#define FMODE_EXEC ((__force fmode_t)0x20)
124+
/* File writes are restricted (block device specific) */
125+
#define FMODE_WRITE_RESTRICTED ((__force fmode_t)0x40)
124126
/* 32bit hashes as llseek() offset (for directories) */
125127
#define FMODE_32BITHASH ((__force fmode_t)0x200)
126128
/* 64bit hashes as llseek() offset (for directories) */

0 commit comments

Comments
 (0)