Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cd9323fd authored by Nicholas Bellinger's avatar Nicholas Bellinger
Browse files

target: Fix bug in handling of FILEIO + block_device resize ops



This patch fixes a bug in the handling of FILEIO w/ underlying block_device
resize operations where the original fd_dev->fd_dev_size was incorrectly being
used in fd_get_blocks() for READ_CAPACITY response payloads.

This patch avoids using fd_dev->fd_dev_size for FILEIO devices with
an underlying block_device, and instead changes fd_get_blocks() to
get the sector count directly from i_size_read() as recommended by hch.

Reported-by: default avatarChristoph Hellwig <hch@lst.de>
Cc: <stable@vger.kernel.org>
Signed-off-by: default avatarNicholas Bellinger <nab@linux-iscsi.org>
parent edc318d9
Loading
Loading
Loading
Loading
+16 −6
Original line number Diff line number Diff line
@@ -169,6 +169,7 @@ static struct se_device *fd_create_virtdevice(
	inode = file->f_mapping->host;
	if (S_ISBLK(inode->i_mode)) {
		struct request_queue *q;
		unsigned long long dev_size;
		/*
		 * Setup the local scope queue_limits from struct request_queue->limits
		 * to pass into transport_add_device_to_core_hba() as struct se_dev_limits.
@@ -183,13 +184,12 @@ static struct se_device *fd_create_virtdevice(
		 * one (1) logical sector from underlying struct block_device
		 */
		fd_dev->fd_block_size = bdev_logical_block_size(inode->i_bdev);
		fd_dev->fd_dev_size = (i_size_read(file->f_mapping->host) -
		dev_size = (i_size_read(file->f_mapping->host) -
				       fd_dev->fd_block_size);

		pr_debug("FILEIO: Using size: %llu bytes from struct"
			" block_device blocks: %llu logical_block_size: %d\n",
			fd_dev->fd_dev_size,
			div_u64(fd_dev->fd_dev_size, fd_dev->fd_block_size),
			dev_size, div_u64(dev_size, fd_dev->fd_block_size),
			fd_dev->fd_block_size);
	} else {
		if (!(fd_dev->fbd_flags & FBDF_HAS_SIZE)) {
@@ -605,10 +605,20 @@ static u32 fd_get_device_type(struct se_device *dev)
static sector_t fd_get_blocks(struct se_device *dev)
{
	struct fd_dev *fd_dev = dev->dev_ptr;
	unsigned long long blocks_long = div_u64(fd_dev->fd_dev_size,
			dev->se_sub_dev->se_dev_attrib.block_size);
	struct file *f = fd_dev->fd_file;
	struct inode *i = f->f_mapping->host;
	unsigned long long dev_size;
	/*
	 * When using a file that references an underlying struct block_device,
	 * ensure dev_size is always based on the current inode size in order
	 * to handle underlying block_device resize operations.
	 */
	if (S_ISBLK(i->i_mode))
		dev_size = (i_size_read(i) - fd_dev->fd_block_size);
	else
		dev_size = fd_dev->fd_dev_size;

	return blocks_long;
	return div_u64(dev_size, dev->se_sub_dev->se_dev_attrib.block_size);
}

static struct se_subsystem_api fileio_template = {