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.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,


LGTM

--
Regards,
Alexander Atanasov

_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to