Re: [PATCH 1/2] nilfs2: add iomap operations for direct I/O reads
Ryusuke Konishi <[email protected]> Sun, 26 Jul 2026 07:33:08 +0900
| Newsgroups | org.kernel.vger.linux-nilfs,org.kernel.vger.linux-fsdevel |
|---|---|
| Message-ID | <CAKFNMok2Op3dAAU8zGWLNPLeh8wj42MgQZbEdP1wSj8jnsO_+Q@mail.gmail.com> |
Hi Viacheslav, On Sat, Jul 25, 2026 at 7:28=E2=80=AFAM Viacheslav Dubeyko wrote: > > Add iomap.c and iomap.h with a read-only nilfs_iomap_ops, > wrapping the existing nilfs_bmap_lookup_contig() lookup > to report a mapped range, a real hole, or an EOF-clamped > range to iomap core. > > NILFS2 is a log-structured, copy-on-write filesystem: > newly allocated blocks are only given a real disk address > when the segment constructor writes them out as part of a log, > which walks buffer_head lists directly and is not integrated > with the generic address_space writeback path. Because of that, > only the read-only side of the mapping is added - buffered writes, > writeback, and mmap's ->page_mkwrite() will stay on the existing > buffer_head based path (nilfs_get_block(), nilfs_write_begin/end(), > nilfs_writepages(), nilfs_dirty_folio(), block_page_mkwrite()). > > Signed-off-by: Viacheslav Dubeyko <[email protected]> > cc: Christoph Hellwig <[email protected]> > cc: Ryusuke Konishi <[email protected]> > cc: [email protected] > cc: [email protected] > --- > fs/nilfs2/Makefile | 2 +- > fs/nilfs2/iomap.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++ > fs/nilfs2/iomap.h | 13 +++++++++ > 3 files changed, 85 insertions(+), 1 deletion(-) > create mode 100644 fs/nilfs2/iomap.c > create mode 100644 fs/nilfs2/iomap.h > > diff --git a/fs/nilfs2/Makefile b/fs/nilfs2/Makefile > index 43b60b8a4d07..516e6b85a03c 100644 > --- a/fs/nilfs2/Makefile > +++ b/fs/nilfs2/Makefile > @@ -3,4 +3,4 @@ obj-$(CONFIG_NILFS2_FS) +=3D nilfs2.o > nilfs2-y :=3D 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 > diff --git a/fs/nilfs2/iomap.c b/fs/nilfs2/iomap.c > new file mode 100644 > index 000000000000..3ae3bf6ed368 > --- /dev/null > +++ b/fs/nilfs2/iomap.c > @@ -0,0 +1,71 @@ > +// 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 =3D inode->i_sb->s_fs_info; > + struct nilfs_inode_info *ii =3D NILFS_I(inode); > + sector_t blkoff =3D offset >> inode->i_blkbits; > + unsigned int maxblocks; > + __u64 blknum =3D 0; > + int ret; > + > + /* Completely beyond EOF. Treat as hole */ > + if (i_size_read(inode) <=3D offset) { > + iomap->type =3D IOMAP_HOLE; > + iomap->addr =3D IOMAP_NULL_ADDR; > + iomap->offset =3D offset; > + iomap->length =3D length; > + return 0; > + } > + > + /* Clamp length if the requested range goes beyond i_size */ > + if (offset + length > i_size_read(inode)) { > + loff_t i_size =3D i_size_read(inode); > + unsigned int blocksize =3D i_blocksize(inode); > + > + length =3D round_up(i_size, blocksize) - offset; > + } > + > + maxblocks =3D min_t(loff_t, length >> inode->i_blkbits, INT_MAX); > + if (maxblocks =3D=3D 0) > + maxblocks =3D 1; > + > + down_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem); > + ret =3D nilfs_bmap_lookup_contig(ii->i_bmap, blkoff, &blknum, max= blocks); > + up_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem); > + > + if (ret =3D=3D -ENOENT) { > + iomap->type =3D IOMAP_HOLE; > + iomap->addr =3D IOMAP_NULL_ADDR; > + iomap->offset =3D offset; > + iomap->length =3D min_t(loff_t, length, i_blocksize(inode= )); After encountering a hole, I think we should use nilfs_bmap_seek_key() -- as nilfs_mdt_find_block() does for metadata files -- to efficiently determine its length. However, if you are short on time, I am fine with the current approach as w= ell. Acked-by: Ryusuke Konishi <[email protected]> Thanks, Ryusuke Konishi > + return 0; > + } else if (ret < 0) > + return ret; > + > + iomap->bdev =3D inode->i_sb->s_bdev; > + iomap->offset =3D offset; > + iomap->length =3D min_t(loff_t, length, (loff_t)ret << inode->i_b= lkbits); > + iomap->addr =3D (loff_t)blknum << inode->i_blkbits; > + iomap->type =3D IOMAP_MAPPED; > + iomap->flags =3D IOMAP_F_MERGED; > + > + return 0; > +} > + > +const struct iomap_ops nilfs_iomap_ops =3D { > + .iomap_begin =3D nilfs_iomap_begin, > +}; > diff --git a/fs/nilfs2/iomap.h b/fs/nilfs2/iomap.h > new file mode 100644 > index 000000000000..adef3e22346d > --- /dev/null > +++ b/fs/nilfs2/iomap.h > @@ -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 */ > -- > 2.43.0 >