[Devel] [PATCH RH9 v3 1/8] block/fops: add llseek_hole to blockdevops

Alexander Atanasov alexander.atanasov at virtuozzo.com
Thu Sep 7 20:14:48 MSK 2023


On 5.09.23 11:59, Andrey Zhadchenko wrote:
> Add new function for block_device_operations, which will be used
> for SEEK_HOLE and SEEK_DATA llseek calls
> 
> Feature: dm: implement SEEK_HOLE for dm-qcow2 and dm-ploop
> https://jira.vzint.dev/browse/PSBM-145746
> Signed-off-by: Andrey Zhadchenko <andrey.zhadchenko at virtuozzo.com>
> 
> ---
> v2: fix critical bug: do not (SEEK_HOLE | SEEK_DATA) as they are
> rather continious enums
> v3: add new helper to handle edge cases
> 
>   block/fops.c           | 38 ++++++++++++++++++++++++++++++++++++++
>   include/linux/blkdev.h |  1 +
>   2 files changed, 39 insertions(+)
> 
> diff --git a/block/fops.c b/block/fops.c
> index 0d07e6f6b284..edd97923a7f1 100644
> --- a/block/fops.c
> +++ b/block/fops.c
> @@ -424,6 +424,31 @@ const struct address_space_operations def_blk_aops = {
>   	.is_dirty_writeback = buffer_check_dirty_writeback,
>   };
>   
> +static loff_t blkdev_llseek_wrapper(struct block_device *bdev, loff_t offset, int whence)
> +{
> +	loff_t retval, bd_size;
> +
> +	bd_size = i_size_read(bdev->bd_inode);
> +	if (offset >= bd_size)
> +		return -ENXIO;
> +
> +	retval = bdev->bd_disk->fops->llseek_hole(bdev, offset, whence);
> +	if (retval < 0)
> +		return retval;
> +
> +	if (retval < offset)
> +		retval = offset;
> +
> +	if (retval >= bd_size) {
> +		if (whence & SEEK_DATA)
> +			retval = -ENXIO;
> +		if (whence & SEEK_HOLE)
> +			retval = bd_size;
> +	}
> +
> +	return retval;
> +}
> +
>   /*
>    * for a block special file file_inode(file)->i_size is zero
>    * so we compute the size by hand (just as in block_read/write above)
> @@ -431,11 +456,24 @@ const struct address_space_operations def_blk_aops = {
>   static loff_t blkdev_llseek(struct file *file, loff_t offset, int whence)
>   {
>   	struct inode *bd_inode = bdev_file_inode(file);
> +	struct block_device *bdev = I_BDEV(bd_inode);
> +	bool is_llseek_hole;
>   	loff_t retval;
>   
> +	is_llseek_hole = (whence == SEEK_HOLE || whence == SEEK_DATA);
> +	if (is_llseek_hole && bdev->bd_disk->fops->llseek_hole) {
> +		retval = blkdev_llseek_wrapper(bdev, offset, whence);
> +		if (retval < 0)
> +			return retval;
> +
> +		offset = retval;
> +		whence = SEEK_SET;
> +	}
> +
>   	inode_lock(bd_inode);
>   	retval = fixed_size_llseek(file, offset, whence, i_size_read(bd_inode));
>   	inode_unlock(bd_inode);
> +
>   	return retval;
>   }
>   
> diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
> index 8b82a63500fc..5c10935cb38e 100644
> --- a/include/linux/blkdev.h
> +++ b/include/linux/blkdev.h
> @@ -1482,6 +1482,7 @@ struct block_device_operations {
>   	int (*getgeo)(struct block_device *, struct hd_geometry *);
>   	int (*set_read_only)(struct block_device *bdev, bool ro);
>   	void (*free_disk)(struct gendisk *disk);
> +	loff_t (*llseek_hole)(struct block_device *bdev, loff_t offset, int whence);
>   	/* this callback is with swap_lock and sometimes page table lock held */
>   	void (*swap_slot_free_notify) (struct block_device *, unsigned long);
>   	int (*report_zones)(struct gendisk *, sector_t sector,


LGTM

-- 
Regards,
Alexander Atanasov



More information about the Devel mailing list