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.zhadche...@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, -- 2.39.3 _______________________________________________ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel