On Tue, Apr 18, 2023 at 10:05:12PM +0800, Jason Yan wrote: > On 2023/4/18 20:28, Kanchan Joshi wrote: > > On Tue, Apr 18, 2023 at 11:00:12AM +0100, David Howells wrote: > > > Hi Christoph, > > > > > > It seems that my use of i_size_read(file_inode(in)) in > > > filemap_splice_read() > > > to get the size of the file to be spliced from doesn't work in the > > > case of > > > blockdevs and it always returns 0. > > > > > > What would be the best way to get the blockdev size? Look at > > > file->f_mapping->i_size maybe? > > > > bdev_nr_bytes(I_BDEV(file->f_mapping->host)) > > should work I suppose. > > > > This needs the caller to check if the file is a blockdev. Can we fill the > upper inode size which belongs to devtmpfs so that the generic code do not > need to aware the low level inode type? We do: static inline loff_t bdev_nr_bytes(struct block_device *bdev) { return (loff_t)bdev_nr_sectors(bdev) << SECTOR_SHIFT; } static inline sector_t bdev_nr_sectors(struct block_device *bdev) { return bdev->bd_nr_sectors; } $ git grep -n -w bd_nr_sectors block/genhd.c:64: bdev->bd_nr_sectors = sectors; block/partitions/core.c:92: bdev->bd_nr_sectors = sectors; include/linux/blk_types.h:42: sector_t bd_nr_sectors; include/linux/blkdev.h:785: return bdev->bd_nr_sectors; and if you look into the functions with those assignments you'll see void set_capacity(struct gendisk *disk, sector_t sectors) { struct block_device *bdev = disk->part0; spin_lock(&bdev->bd_size_lock); i_size_write(bdev->bd_inode, (loff_t)sectors << SECTOR_SHIFT); bdev->bd_nr_sectors = sectors; spin_unlock(&bdev->bd_size_lock); } and static void bdev_set_nr_sectors(struct block_device *bdev, sector_t sectors) { spin_lock(&bdev->bd_size_lock); i_size_write(bdev->bd_inode, (loff_t)sectors << SECTOR_SHIFT); bdev->bd_nr_sectors = sectors; spin_unlock(&bdev->bd_size_lock); } As you can see, both do i_size_write() on bdev->bd_inode with the value equal to what bdev_nr_bytes() will return after the store to ->bd_nr_sectors. Now, bdev->bd_inode always points to inode coallocated with bdev (see bdev_alloc() for details) and that's what we have ->f_mapping->host pointing to for opened file after blkdev_open() - see filp->f_mapping = bdev->bd_inode->i_mapping; in there combined with inode->i_mapping.host set to inode by inode_init_always()<-alloc_inode()<-new_inode_pseudo()<-new_inode()<-bdev_alloc(). IOW, i_size_read(file->f_mapping->host) is correct answer for any kind of file.