Commit d0d7f181 authored by Carlos Maiolino's avatar Carlos Maiolino
Browse files

Merge remote-tracking branch 'linux-block/block-6.15' into xfs tree



We need two patches inside linux-block tree as dependencies of the patch
which will follow this merge.

Specifically, we need:

block: fix race between set_blocksize and read paths
block: hoist block size validation code to a separate function

Signed-off-by: default avatarCarlos Maiolino <cem@kernel.org>
parents f0447f80 f40139fd
Loading
Loading
Loading
Loading
+51 −16
Original line number Diff line number Diff line
@@ -152,27 +152,65 @@ static void set_init_blocksize(struct block_device *bdev)
				    get_order(bsize));
}

int set_blocksize(struct file *file, int size)
/**
 * bdev_validate_blocksize - check that this block size is acceptable
 * @bdev:	blockdevice to check
 * @block_size:	block size to check
 *
 * For block device users that do not use buffer heads or the block device
 * page cache, make sure that this block size can be used with the device.
 *
 * Return: On success zero is returned, negative error code on failure.
 */
int bdev_validate_blocksize(struct block_device *bdev, int block_size)
{
	struct inode *inode = file->f_mapping->host;
	struct block_device *bdev = I_BDEV(inode);

	if (blk_validate_block_size(size))
	if (blk_validate_block_size(block_size))
		return -EINVAL;

	/* Size cannot be smaller than the size supported by the device */
	if (size < bdev_logical_block_size(bdev))
	if (block_size < bdev_logical_block_size(bdev))
		return -EINVAL;

	return 0;
}
EXPORT_SYMBOL_GPL(bdev_validate_blocksize);

int set_blocksize(struct file *file, int size)
{
	struct inode *inode = file->f_mapping->host;
	struct block_device *bdev = I_BDEV(inode);
	int ret;

	ret = bdev_validate_blocksize(bdev, size);
	if (ret)
		return ret;

	if (!file->private_data)
		return -EINVAL;

	/* Don't change the size if it is same as current */
	if (inode->i_blkbits != blksize_bits(size)) {
		/*
		 * Flush and truncate the pagecache before we reconfigure the
		 * mapping geometry because folio sizes are variable now.  If a
		 * reader has already allocated a folio whose size is smaller
		 * than the new min_order but invokes readahead after the new
		 * min_order becomes visible, readahead will think there are
		 * "zero" blocks per folio and crash.  Take the inode and
		 * invalidation locks to avoid racing with
		 * read/write/fallocate.
		 */
		inode_lock(inode);
		filemap_invalidate_lock(inode->i_mapping);

		sync_blockdev(bdev);
		kill_bdev(bdev);

		inode->i_blkbits = blksize_bits(size);
		mapping_set_folio_min_order(inode->i_mapping, get_order(size));
		kill_bdev(bdev);
		filemap_invalidate_unlock(inode->i_mapping);
		inode_unlock(inode);
	}
	return 0;
}
@@ -777,13 +815,13 @@ static void blkdev_put_part(struct block_device *part)
	blkdev_put_whole(whole);
}

struct block_device *blkdev_get_no_open(dev_t dev)
struct block_device *blkdev_get_no_open(dev_t dev, bool autoload)
{
	struct block_device *bdev;
	struct inode *inode;

	inode = ilookup(blockdev_superblock, dev);
	if (!inode && IS_ENABLED(CONFIG_BLOCK_LEGACY_AUTOLOAD)) {
	if (!inode && autoload && IS_ENABLED(CONFIG_BLOCK_LEGACY_AUTOLOAD)) {
		blk_request_module(dev);
		inode = ilookup(blockdev_superblock, dev);
		if (inode)
@@ -1005,7 +1043,7 @@ struct file *bdev_file_open_by_dev(dev_t dev, blk_mode_t mode, void *holder,
	if (ret)
		return ERR_PTR(ret);

	bdev = blkdev_get_no_open(dev);
	bdev = blkdev_get_no_open(dev, true);
	if (!bdev)
		return ERR_PTR(-ENXIO);

@@ -1275,18 +1313,15 @@ void sync_bdevs(bool wait)
void bdev_statx(struct path *path, struct kstat *stat,
		u32 request_mask)
{
	struct inode *backing_inode;
	struct block_device *bdev;

	backing_inode = d_backing_inode(path->dentry);

	/*
	 * Note that backing_inode is the inode of a block device node file,
	 * not the block device's internal inode.  Therefore it is *not* valid
	 * to use I_BDEV() here; the block device has to be looked up by i_rdev
	 * Note that d_backing_inode() returns the block device node inode, not
	 * the block device's internal inode.  Therefore it is *not* valid to
	 * use I_BDEV() here; the block device has to be looked up by i_rdev
	 * instead.
	 */
	bdev = blkdev_get_no_open(backing_inode->i_rdev);
	bdev = blkdev_get_no_open(d_backing_inode(path->dentry)->i_rdev, false);
	if (!bdev)
		return;

+6 −11
Original line number Diff line number Diff line
@@ -66,17 +66,13 @@ struct bio_integrity_payload *bio_integrity_alloc(struct bio *bio,
}
EXPORT_SYMBOL(bio_integrity_alloc);

static void bio_integrity_unpin_bvec(struct bio_vec *bv, int nr_vecs,
				     bool dirty)
static void bio_integrity_unpin_bvec(struct bio_vec *bv, int nr_vecs)
{
	int i;

	for (i = 0; i < nr_vecs; i++) {
		if (dirty && !PageCompound(bv[i].bv_page))
			set_page_dirty_lock(bv[i].bv_page);
	for (i = 0; i < nr_vecs; i++)
		unpin_user_page(bv[i].bv_page);
}
}

static void bio_integrity_uncopy_user(struct bio_integrity_payload *bip)
{
@@ -91,7 +87,7 @@ static void bio_integrity_uncopy_user(struct bio_integrity_payload *bip)
	ret = copy_to_iter(bvec_virt(bounce_bvec), bytes, &orig_iter);
	WARN_ON_ONCE(ret != bytes);

	bio_integrity_unpin_bvec(orig_bvecs, orig_nr_vecs, true);
	bio_integrity_unpin_bvec(orig_bvecs, orig_nr_vecs);
}

/**
@@ -111,8 +107,7 @@ void bio_integrity_unmap_user(struct bio *bio)
		return;
	}

	bio_integrity_unpin_bvec(bip->bip_vec, bip->bip_max_vcnt,
			bio_data_dir(bio) == READ);
	bio_integrity_unpin_bvec(bip->bip_vec, bip->bip_max_vcnt);
}

/**
@@ -198,7 +193,7 @@ static int bio_integrity_copy_user(struct bio *bio, struct bio_vec *bvec,
	}

	if (write)
		bio_integrity_unpin_bvec(bvec, nr_vecs, false);
		bio_integrity_unpin_bvec(bvec, nr_vecs);
	else
		memcpy(&bip->bip_vec[1], bvec, nr_vecs * sizeof(*bvec));

@@ -319,7 +314,7 @@ int bio_integrity_map_user(struct bio *bio, struct iov_iter *iter)
	return 0;

release_pages:
	bio_integrity_unpin_bvec(bvec, nr_bvecs, false);
	bio_integrity_unpin_bvec(bvec, nr_bvecs);
free_bvec:
	if (bvec != stack_vec)
		kfree(bvec);
+1 −1
Original line number Diff line number Diff line
@@ -797,7 +797,7 @@ int blkg_conf_open_bdev(struct blkg_conf_ctx *ctx)
		return -EINVAL;
	input = skip_spaces(input);

	bdev = blkdev_get_no_open(MKDEV(major, minor));
	bdev = blkdev_get_no_open(MKDEV(major, minor), false);
	if (!bdev)
		return -ENODEV;
	if (bdev_is_partition(bdev)) {
+7 −1
Original line number Diff line number Diff line
@@ -61,8 +61,14 @@ void blk_apply_bdi_limits(struct backing_dev_info *bdi,
	/*
	 * For read-ahead of large files to be effective, we need to read ahead
	 * at least twice the optimal I/O size.
	 *
	 * There is no hardware limitation for the read-ahead size and the user
	 * might have increased the read-ahead size through sysfs, so don't ever
	 * decrease it.
	 */
	bdi->ra_pages = max(lim->io_opt * 2 / PAGE_SIZE, VM_READAHEAD_PAGES);
	bdi->ra_pages = max3(bdi->ra_pages,
				lim->io_opt * 2 / PAGE_SIZE,
				VM_READAHEAD_PAGES);
	bdi->io_pages = lim->max_sectors >> PAGE_SECTORS_SHIFT;
}

+2 −0
Original line number Diff line number Diff line
@@ -909,6 +909,8 @@ int blk_register_queue(struct gendisk *disk)
out_debugfs_remove:
	blk_debugfs_remove(disk);
	mutex_unlock(&q->sysfs_lock);
	if (queue_is_mq(q))
		blk_mq_sysfs_unregister(disk);
out_put_queue_kobj:
	kobject_put(&disk->queue_kobj);
	return ret;
Loading