Re: How best to get the size of a blockdev from a file?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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.



[Index of Archives]     [Linux RAID]     [Linux SCSI]     [Linux ATA RAID]     [IDE]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Device Mapper]

  Powered by Linux