// SPDX-License-Identifier: GPL-2.0+ /* * NILFS iomap support implementation. * * Written by Viacheslav Dubeyko. */ #include #include #include "nilfs.h" #include "mdt.h" #include "iomap.h" static int nilfs_iomap_begin(struct inode *inode, loff_t offset, loff_t length, unsigned int flags, struct iomap *iomap, struct iomap *srcmap) { struct the_nilfs *nilfs = inode->i_sb->s_fs_info; struct nilfs_inode_info *ii = NILFS_I(inode); sector_t blkoff = offset >> inode->i_blkbits; unsigned int maxblocks; __u64 blknum = 0; int ret; /* Completely beyond EOF. Treat as hole */ if (i_size_read(inode) <= offset) { iomap->type = IOMAP_HOLE; iomap->addr = IOMAP_NULL_ADDR; iomap->offset = offset; iomap->length = length; return 0; } /* Clamp length if the requested range goes beyond i_size */ if (offset + length > i_size_read(inode)) { loff_t i_size = i_size_read(inode); unsigned int blocksize = i_blocksize(inode); length = round_up(i_size, blocksize) - offset; } maxblocks = min_t(loff_t, length >> inode->i_blkbits, INT_MAX); if (maxblocks == 0) maxblocks = 1; down_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem); ret = nilfs_bmap_lookup_contig(ii->i_bmap, blkoff, &blknum, maxblocks); up_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem); if (ret == -ENOENT) { iomap->type = IOMAP_HOLE; iomap->addr = IOMAP_NULL_ADDR; iomap->offset = offset; iomap->length = min_t(loff_t, length, i_blocksize(inode)); return 0; } else if (ret < 0) return ret; iomap->bdev = inode->i_sb->s_bdev; iomap->offset = offset; iomap->length = min_t(loff_t, length, (loff_t)ret << inode->i_blkbits); iomap->addr = (loff_t)blknum << inode->i_blkbits; iomap->type = IOMAP_MAPPED; iomap->flags = IOMAP_F_MERGED; return 0; } const struct iomap_ops nilfs_iomap_ops = { .iomap_begin = nilfs_iomap_begin, };