nilfs2: add iomap operations for direct I/O

The patch adds iomap.h with declaration of iomaps
operations and iomap.c with implementation of
nilfs_iomap_begin(). This method is based on calling
the nilfs_bmap_lookup_contig() method. It resolves
the file's block-mapping to find the sequence of
physically-contiguous blocks starting at starting
block. Offsets at or beyond i_size are reported
as a hole. For offsets within i_size, the requested
length is first clamped to the block-aligned end of the file.
Both the hole and mapped cases then report iomap->offset
aligned to the containing block (blkoff << i_blkbits)
rather than the raw request offset.

Co-developed-by: Linmao Li <lilinmao@kylinos.cn>
Signed-off-by: Linmao Li <lilinmao@kylinos.cn>
cc: Christoph Hellwig <hch@lst.de>
cc: Ryusuke Konishi <konishi.ryusuke@gmail.com>
cc: linux-nilfs@vger.kernel.org
cc: linux-fsdevel@vger.kernel.org
Acked-by: Ryusuke Konishi <konishi.ryusuke@gmail.com>
Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
This commit is contained in:
Viacheslav Dubeyko 2026-08-12 15:11:53 -07:00
parent 8393ce53a5
commit 89eebc9b5f
3 changed files with 86 additions and 1 deletions

View File

@ -3,4 +3,4 @@ obj-$(CONFIG_NILFS2_FS) += nilfs2.o
nilfs2-y := inode.o file.o dir.o super.o namei.o page.o mdt.o \
btnode.o bmap.o btree.o direct.o dat.o recovery.o \
the_nilfs.o segbuf.o segment.o cpfile.o sufile.o \
ifile.o alloc.o gcinode.o ioctl.o sysfs.o
ifile.o alloc.o gcinode.o ioctl.o sysfs.o iomap.o

72
fs/nilfs2/iomap.c Normal file
View File

@ -0,0 +1,72 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* NILFS iomap support implementation.
*
* Written by Viacheslav Dubeyko.
*/
#include <linux/iomap.h>
#include <linux/pagemap.h>
#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;
loff_t iomap_offset = (loff_t)blkoff << 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 = iomap_offset;
iomap->length = i_blocksize(inode);
return 0;
} else if (ret < 0)
return ret;
iomap->bdev = inode->i_sb->s_bdev;
iomap->offset = iomap_offset;
iomap->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,
};

13
fs/nilfs2/iomap.h Normal file
View File

@ -0,0 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* NILFS iomap support declarations.
*
* Written by Viacheslav Dubeyko.
*/
#ifndef _NILFS_IOMAP_H
#define _NILFS_IOMAP_H
extern const struct iomap_ops nilfs_iomap_ops;
#endif /* _NILFS_IOMAP_H */