getting rid of bogus set_blocksize() uses, switching it

to struct file * and verifying that caller has device
 opened exclusively.
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYIAB0WIQQqUNBr3gm4hGXdBJlZ7Krx/gZQ6wUCZkwkfQAKCRBZ7Krx/gZQ
 62C3AQDW5vuXNx2+KDPma5YStjFpPLC0xtSyAS5D3YANjtyRFgD/TOcCarq7rvBt
 KubxHVFsfW+eu6ASeaoMRB83w5OIzwk=
 =Liix
 -----END PGP SIGNATURE-----

Merge tag 'pull-set_blocksize' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

Pull vfs blocksize updates from Al Viro:
 "This gets rid of bogus set_blocksize() uses, switches it over
  to be based on a 'struct file *' and verifies that the caller
  has the device opened exclusively"

* tag 'pull-set_blocksize' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  make set_blocksize() fail unless block device is opened exclusive
  set_blocksize(): switch to passing struct file *
  btrfs_get_bdev_and_sb(): call set_blocksize() only for exclusive opens
  swsusp: don't bother with setting block size
  zram: don't bother with reopening - just use O_EXCL for open
  swapon(2): open swap with O_EXCL
  swapon(2)/swapoff(2): don't bother with block size
  pktcdvd: sort set_blocksize() calls out
  bcache_register(): don't bother with set_blocksize()
This commit is contained in:
Linus Torvalds 2024-05-21 08:34:51 -07:00
commit 5ad8b6ad9a
16 changed files with 55 additions and 93 deletions

View file

@ -1134,3 +1134,10 @@ superblock of the main block device, i.e., the one stored in sb->s_bdev. Block
device freezing now works for any block device owned by a given superblock, not
just the main block device. The get_active_super() helper and bd_fsfreeze_sb
pointer are gone.
---
**mandatory**
set_blocksize() takes opened struct file instead of struct block_device now
and it *must* be opened exclusive.

View file

@ -144,8 +144,11 @@ static void set_init_blocksize(struct block_device *bdev)
bdev->bd_inode->i_blkbits = blksize_bits(bsize);
}
int set_blocksize(struct block_device *bdev, int size)
int set_blocksize(struct file *file, int size)
{
struct inode *inode = file->f_mapping->host;
struct block_device *bdev = I_BDEV(inode);
/* Size must be a power of two, and between 512 and PAGE_SIZE */
if (size > PAGE_SIZE || size < 512 || !is_power_of_2(size))
return -EINVAL;
@ -154,10 +157,13 @@ int set_blocksize(struct block_device *bdev, int size)
if (size < bdev_logical_block_size(bdev))
return -EINVAL;
if (!file->private_data)
return -EINVAL;
/* Don't change the size if it is same as current */
if (bdev->bd_inode->i_blkbits != blksize_bits(size)) {
if (inode->i_blkbits != blksize_bits(size)) {
sync_blockdev(bdev);
bdev->bd_inode->i_blkbits = blksize_bits(size);
inode->i_blkbits = blksize_bits(size);
kill_bdev(bdev);
}
return 0;
@ -167,7 +173,7 @@ EXPORT_SYMBOL(set_blocksize);
int sb_set_blocksize(struct super_block *sb, int size)
{
if (set_blocksize(sb->s_bdev, size))
if (set_blocksize(sb->s_bdev_file, size))
return 0;
/* If we get here, we know size is power of two
* and it's value is between 512 and PAGE_SIZE */

View file

@ -503,11 +503,14 @@ static int compat_hdio_getgeo(struct block_device *bdev,
#endif
/* set the logical block size */
static int blkdev_bszset(struct block_device *bdev, blk_mode_t mode,
static int blkdev_bszset(struct file *file, blk_mode_t mode,
int __user *argp)
{
// this one might be file_inode(file)->i_rdev - a rare valid
// use of file_inode() for those.
dev_t dev = I_BDEV(file->f_mapping->host)->bd_dev;
struct file *excl_file;
int ret, n;
struct file *file;
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
@ -517,13 +520,13 @@ static int blkdev_bszset(struct block_device *bdev, blk_mode_t mode,
return -EFAULT;
if (mode & BLK_OPEN_EXCL)
return set_blocksize(bdev, n);
return set_blocksize(file, n);
file = bdev_file_open_by_dev(bdev->bd_dev, mode, &bdev, NULL);
if (IS_ERR(file))
excl_file = bdev_file_open_by_dev(dev, mode, &dev, NULL);
if (IS_ERR(excl_file))
return -EBUSY;
ret = set_blocksize(bdev, n);
fput(file);
ret = set_blocksize(excl_file, n);
fput(excl_file);
return ret;
}
@ -652,7 +655,7 @@ long blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
case BLKBSZGET: /* get block device soft block size (cf. BLKSSZGET) */
return put_int(argp, block_size(bdev));
case BLKBSZSET:
return blkdev_bszset(bdev, mode, argp);
return blkdev_bszset(file, mode, argp);
case BLKGETSIZE64:
return put_u64(argp, bdev_nr_bytes(bdev));
@ -712,7 +715,7 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
case BLKBSZGET_32: /* get the logical block size (cf. BLKSSZGET) */
return put_int(argp, bdev_logical_block_size(bdev));
case BLKBSZSET_32:
return blkdev_bszset(bdev, mode, argp);
return blkdev_bszset(file, mode, argp);
case BLKGETSIZE64_32:
return put_u64(argp, bdev_nr_bytes(bdev));

View file

@ -2215,6 +2215,7 @@ static int pkt_open_dev(struct pktcdvd_device *pd, bool write)
}
dev_info(ddev, "%lukB available on disc\n", lba << 1);
}
set_blocksize(bdev_file, CD_FRAMESIZE);
return 0;
@ -2278,11 +2279,6 @@ static int pkt_open(struct gendisk *disk, blk_mode_t mode)
ret = pkt_open_dev(pd, mode & BLK_OPEN_WRITE);
if (ret)
goto out_dec;
/*
* needed here as well, since ext2 (among others) may change
* the blocksize at mount time
*/
set_blocksize(disk->part0, CD_FRAMESIZE);
}
mutex_unlock(&ctl_mutex);
mutex_unlock(&pktcdvd_mutex);
@ -2526,7 +2522,6 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev)
__module_get(THIS_MODULE);
pd->bdev_file = bdev_file;
set_blocksize(file_bdev(bdev_file), CD_FRAMESIZE);
atomic_set(&pd->cdrw.pending_bios, 0);
pd->cdrw.thread = kthread_run(kcdrwd, pd, "%s", pd->disk->disk_name);

View file

@ -426,11 +426,10 @@ static void reset_bdev(struct zram *zram)
if (!zram->backing_dev)
return;
fput(zram->bdev_file);
/* hope filp_close flush all of IO */
filp_close(zram->backing_dev, NULL);
zram->backing_dev = NULL;
zram->bdev_file = NULL;
zram->bdev = NULL;
zram->disk->fops = &zram_devops;
kvfree(zram->bitmap);
zram->bitmap = NULL;
@ -473,10 +472,8 @@ static ssize_t backing_dev_store(struct device *dev,
size_t sz;
struct file *backing_dev = NULL;
struct inode *inode;
struct address_space *mapping;
unsigned int bitmap_sz;
unsigned long nr_pages, *bitmap = NULL;
struct file *bdev_file = NULL;
int err;
struct zram *zram = dev_to_zram(dev);
@ -497,15 +494,14 @@ static ssize_t backing_dev_store(struct device *dev,
if (sz > 0 && file_name[sz - 1] == '\n')
file_name[sz - 1] = 0x00;
backing_dev = filp_open(file_name, O_RDWR|O_LARGEFILE, 0);
backing_dev = filp_open(file_name, O_RDWR | O_LARGEFILE | O_EXCL, 0);
if (IS_ERR(backing_dev)) {
err = PTR_ERR(backing_dev);
backing_dev = NULL;
goto out;
}
mapping = backing_dev->f_mapping;
inode = mapping->host;
inode = backing_dev->f_mapping->host;
/* Support only block device in this moment */
if (!S_ISBLK(inode->i_mode)) {
@ -513,14 +509,6 @@ static ssize_t backing_dev_store(struct device *dev,
goto out;
}
bdev_file = bdev_file_open_by_dev(inode->i_rdev,
BLK_OPEN_READ | BLK_OPEN_WRITE, zram, NULL);
if (IS_ERR(bdev_file)) {
err = PTR_ERR(bdev_file);
bdev_file = NULL;
goto out;
}
nr_pages = i_size_read(inode) >> PAGE_SHIFT;
bitmap_sz = BITS_TO_LONGS(nr_pages) * sizeof(long);
bitmap = kvzalloc(bitmap_sz, GFP_KERNEL);
@ -531,7 +519,7 @@ static ssize_t backing_dev_store(struct device *dev,
reset_bdev(zram);
zram->bdev_file = bdev_file;
zram->bdev = I_BDEV(inode);
zram->backing_dev = backing_dev;
zram->bitmap = bitmap;
zram->nr_pages = nr_pages;
@ -544,9 +532,6 @@ static ssize_t backing_dev_store(struct device *dev,
out:
kvfree(bitmap);
if (bdev_file)
fput(bdev_file);
if (backing_dev)
filp_close(backing_dev, NULL);
@ -587,7 +572,7 @@ static void read_from_bdev_async(struct zram *zram, struct page *page,
{
struct bio *bio;
bio = bio_alloc(file_bdev(zram->bdev_file), 1, parent->bi_opf, GFP_NOIO);
bio = bio_alloc(zram->bdev, 1, parent->bi_opf, GFP_NOIO);
bio->bi_iter.bi_sector = entry * (PAGE_SIZE >> 9);
__bio_add_page(bio, page, PAGE_SIZE, 0);
bio_chain(bio, parent);
@ -703,7 +688,7 @@ static ssize_t writeback_store(struct device *dev,
continue;
}
bio_init(&bio, file_bdev(zram->bdev_file), &bio_vec, 1,
bio_init(&bio, zram->bdev, &bio_vec, 1,
REQ_OP_WRITE | REQ_SYNC);
bio.bi_iter.bi_sector = blk_idx * (PAGE_SIZE >> 9);
__bio_add_page(&bio, page, PAGE_SIZE, 0);
@ -785,7 +770,7 @@ static void zram_sync_read(struct work_struct *work)
struct bio_vec bv;
struct bio bio;
bio_init(&bio, file_bdev(zw->zram->bdev_file), &bv, 1, REQ_OP_READ);
bio_init(&bio, zw->zram->bdev, &bv, 1, REQ_OP_READ);
bio.bi_iter.bi_sector = zw->entry * (PAGE_SIZE >> 9);
__bio_add_page(&bio, zw->page, PAGE_SIZE, 0);
zw->error = submit_bio_wait(&bio);

View file

@ -132,7 +132,7 @@ struct zram {
spinlock_t wb_limit_lock;
bool wb_limit_enable;
u64 bd_wb_limit;
struct file *bdev_file;
struct block_device *bdev;
unsigned long *bitmap;
unsigned long nr_pages;
#endif

View file

@ -2555,10 +2555,6 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr,
if (IS_ERR(bdev_file))
goto out_free_sb;
err = "failed to set blocksize";
if (set_blocksize(file_bdev(bdev_file), 4096))
goto out_blkdev_put;
err = read_super(sb, file_bdev(bdev_file), &sb_disk);
if (err)
goto out_blkdev_put;

View file

@ -316,7 +316,7 @@ static int btrfs_init_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
set_bit(BTRFS_DEV_STATE_IN_FS_METADATA, &device->dev_state);
set_bit(BTRFS_DEV_STATE_REPLACE_TGT, &device->dev_state);
device->dev_stats_valid = 1;
set_blocksize(device->bdev, BTRFS_BDEV_BLOCKSIZE);
set_blocksize(bdev_file, BTRFS_BDEV_BLOCKSIZE);
device->fs_devices = fs_devices;
ret = btrfs_get_dev_zone_info(device, false);

View file

@ -482,10 +482,12 @@ btrfs_get_bdev_and_sb(const char *device_path, blk_mode_t flags, void *holder,
if (flush)
sync_blockdev(bdev);
ret = set_blocksize(bdev, BTRFS_BDEV_BLOCKSIZE);
if (ret) {
fput(*bdev_file);
goto error;
if (holder) {
ret = set_blocksize(*bdev_file, BTRFS_BDEV_BLOCKSIZE);
if (ret) {
fput(*bdev_file);
goto error;
}
}
invalidate_bdev(bdev);
*disk_super = btrfs_read_dev_super(bdev);
@ -498,6 +500,7 @@ btrfs_get_bdev_and_sb(const char *device_path, blk_mode_t flags, void *holder,
return 0;
error:
*disk_super = NULL;
*bdev_file = NULL;
return ret;
}
@ -2714,7 +2717,7 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
set_bit(BTRFS_DEV_STATE_IN_FS_METADATA, &device->dev_state);
clear_bit(BTRFS_DEV_STATE_REPLACE_TGT, &device->dev_state);
device->dev_stats_valid = 1;
set_blocksize(device->bdev, BTRFS_BDEV_BLOCKSIZE);
set_blocksize(device->bdev_file, BTRFS_BDEV_BLOCKSIZE);
if (seeding_dev) {
btrfs_clear_sb_rdonly(sb);

View file

@ -5866,7 +5866,7 @@ static struct file *ext4_get_journal_blkdev(struct super_block *sb,
sb_block = EXT4_MIN_BLOCK_SIZE / blocksize;
offset = EXT4_MIN_BLOCK_SIZE % blocksize;
set_blocksize(bdev, blocksize);
set_blocksize(bdev_file, blocksize);
bh = __bread(bdev, sb_block, blocksize);
if (!bh) {
ext4_msg(sb, KERN_ERR, "couldn't read superblock of "

View file

@ -2626,8 +2626,7 @@ static int journal_init_dev(struct super_block *super,
MAJOR(jdev), MINOR(jdev), result);
return result;
} else if (jdev != super->s_dev)
set_blocksize(file_bdev(journal->j_bdev_file),
super->s_blocksize);
set_blocksize(journal->j_bdev_file, super->s_blocksize);
return 0;
}
@ -2643,7 +2642,7 @@ static int journal_init_dev(struct super_block *super,
return result;
}
set_blocksize(file_bdev(journal->j_bdev_file), super->s_blocksize);
set_blocksize(journal->j_bdev_file, super->s_blocksize);
reiserfs_info(super,
"journal_init_dev: journal device: %pg\n",
file_bdev(journal->j_bdev_file));

View file

@ -2046,7 +2046,7 @@ xfs_setsize_buftarg(
btp->bt_meta_sectorsize = sectorsize;
btp->bt_meta_sectormask = sectorsize - 1;
if (set_blocksize(btp->bt_bdev, sectorsize)) {
if (set_blocksize(btp->bt_bdev_file, sectorsize)) {
xfs_warn(btp->bt_mount,
"Cannot set_blocksize to %u on device %pg",
sectorsize, btp->bt_bdev);

View file

@ -1481,7 +1481,7 @@ static inline void bio_end_io_acct(struct bio *bio, unsigned long start_time)
}
int bdev_read_only(struct block_device *bdev);
int set_blocksize(struct block_device *bdev, int size);
int set_blocksize(struct file *file, int size);
int lookup_bdev(const char *pathname, dev_t *dev);

View file

@ -310,10 +310,8 @@ struct swap_info_struct {
unsigned int __percpu *cluster_next_cpu; /*percpu index for next allocation */
struct percpu_cluster __percpu *percpu_cluster; /* per cpu's swap location */
struct rb_root swap_extent_root;/* root of the swap extent rbtree */
struct file *bdev_file; /* open handle of the bdev */
struct block_device *bdev; /* swap device or bdev of swap file */
struct file *swap_file; /* seldom referenced */
unsigned int old_block_size; /* seldom referenced */
struct completion comp; /* seldom referenced */
spinlock_t lock; /*
* protect map scan related fields like

View file

@ -368,11 +368,7 @@ static int swsusp_swap_check(void)
if (IS_ERR(hib_resume_bdev_file))
return PTR_ERR(hib_resume_bdev_file);
res = set_blocksize(file_bdev(hib_resume_bdev_file), PAGE_SIZE);
if (res < 0)
fput(hib_resume_bdev_file);
return res;
return 0;
}
/**
@ -1574,7 +1570,6 @@ int swsusp_check(bool exclusive)
hib_resume_bdev_file = bdev_file_open_by_dev(swsusp_resume_device,
BLK_OPEN_READ, holder, NULL);
if (!IS_ERR(hib_resume_bdev_file)) {
set_blocksize(file_bdev(hib_resume_bdev_file), PAGE_SIZE);
clear_page(swsusp_header);
error = hib_submit_io(REQ_OP_READ, swsusp_resume_block,
swsusp_header, NULL);

View file

@ -2469,7 +2469,6 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
struct inode *inode;
struct filename *pathname;
int err, found = 0;
unsigned int old_block_size;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
@ -2582,7 +2581,6 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
}
swap_file = p->swap_file;
old_block_size = p->old_block_size;
p->swap_file = NULL;
p->max = 0;
swap_map = p->swap_map;
@ -2605,11 +2603,6 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
exit_swap_address_space(p->type);
inode = mapping->host;
if (p->bdev_file) {
set_blocksize(p->bdev, old_block_size);
fput(p->bdev_file);
p->bdev_file = NULL;
}
inode_lock(inode);
inode->i_flags &= ~S_SWAPFILE;
@ -2835,21 +2828,8 @@ static struct swap_info_struct *alloc_swap_info(void)
static int claim_swapfile(struct swap_info_struct *p, struct inode *inode)
{
int error;
if (S_ISBLK(inode->i_mode)) {
p->bdev_file = bdev_file_open_by_dev(inode->i_rdev,
BLK_OPEN_READ | BLK_OPEN_WRITE, p, NULL);
if (IS_ERR(p->bdev_file)) {
error = PTR_ERR(p->bdev_file);
p->bdev_file = NULL;
return error;
}
p->bdev = file_bdev(p->bdev_file);
p->old_block_size = block_size(p->bdev);
error = set_blocksize(p->bdev, PAGE_SIZE);
if (error < 0)
return error;
p->bdev = I_BDEV(inode);
/*
* Zoned block devices contain zones that have a sequential
* write only restriction. Hence zoned block devices are not
@ -3090,7 +3070,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
name = NULL;
goto bad_swap;
}
swap_file = file_open_name(name, O_RDWR|O_LARGEFILE, 0);
swap_file = file_open_name(name, O_RDWR | O_LARGEFILE | O_EXCL, 0);
if (IS_ERR(swap_file)) {
error = PTR_ERR(swap_file);
swap_file = NULL;
@ -3289,11 +3269,6 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
p->percpu_cluster = NULL;
free_percpu(p->cluster_next_cpu);
p->cluster_next_cpu = NULL;
if (p->bdev_file) {
set_blocksize(p->bdev, p->old_block_size);
fput(p->bdev_file);
p->bdev_file = NULL;
}
inode = NULL;
destroy_swap_extents(p);
swap_cgroup_swapoff(p->type);