From: Heming Zhao <heming.zhao@suse.com>
To: Joseph Qi <joseph.qi@linux.alibaba.com>
Cc: mark@fasheh.com, jlbec@evilplan.org, hch@lst.de,
ocfs2-devel@lists.linux.dev, linux-kernel@vger.kernel.org
Subject: Re: [RFC PATCH v2 1/4] ocfs2: Add new ocfs2_map_blocks() to introduce iomap feature
Date: Sun, 2 Aug 2026 19:28:30 +0800 [thread overview]
Message-ID: <am8oSsQDQrynSXBf@p15> (raw)
In-Reply-To: <7624c381-8c33-4961-bb63-89e21dfcc352@linux.alibaba.com>
Looking at my thunderbird inbox, I noticed the previous mail was formatted
incorrectly. I must have hit the wrong shortcut in neomutt before sending it.
Resending again.
On Tue, Jul 28, 2026 at 01:41:31PM +0800, Joseph Qi wrote:
>
>
> On 7/27/26 2:17 PM, Heming Zhao wrote:
> > As part of migrating OCFS2 DIO read/write code paths towards the modern
> > and high-performant iomap framework, this patch introduces an iomap API
> > to replace old high-overhead VFS buffer_head structure paths.
> >
> > This patch establishes the foundational block mapping routines required by
> > subsequent iomap integration patches. The implementation draws
> > inspiration from ext4_map_blocks().
> >
> > Signed-off-by: Heming Zhao <heming.zhao@suse.com>
> > ---
> > fs/ocfs2/aops.c | 94 +++++++++++++++++++++++++++++++++++++++
> > fs/ocfs2/aops.h | 2 +
> > fs/ocfs2/buffer_head_io.c | 12 -----
> > fs/ocfs2/ocfs2.h | 45 ++++++++++++++++++-
> > 4 files changed, 140 insertions(+), 13 deletions(-)
> >
> > diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
> > index 4acdbb70882c..08df5e3b5196 100644
> > --- a/fs/ocfs2/aops.c
> > +++ b/fs/ocfs2/aops.c
> > @@ -126,6 +126,100 @@ static int ocfs2_lock_get_block(struct inode *inode, sector_t iblock,
> > return ret;
> > }
> >
> > +int ocfs2_map_blocks(struct inode *inode, struct ocfs2_map_block *map,
> > + int flags)
> > +{
> > + int err = 0;
> > + unsigned int ext_flags;
> > + u64 max_blocks = map->len;
> > + u64 p_blkno, count, past_eof;
> > + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
> > + int create = flags & OCFS2_GET_BLOCKS_CREATE;
> > +
> > + if (OCFS2_I(inode)->ip_flags & OCFS2_INODE_SYSTEM_FILE)
> > + mlog(ML_NOTICE, "map_block on system inode 0x%p (%llu)\n",
> > + inode, inode->i_ino);
> > +
> > + if (S_ISLNK(inode->i_mode)) {
> > + /*
> > + * TODO: refer ocfs2_get_block() to handle
> > + * ocfs2_read_folio in the future
> > + */
> > + mlog(ML_NOTICE, "map_block on S_ISLNK file, node 0x%p (%llu)\n",
> > + inode, inode->i_ino);
> > + dump_stack();
>
> Here mlog and dump_stack() for debug?
> Why not gate behind ML_DEBUG and WARN_ON_ONCE()?
>
I will follow this suggestion in the next version.
This function shouldn't handle symlink files in the current version.
However, since it derives from ocfs2_get_block() (which handles the S_ISLNK case)
and I eventually plan to replace ocfs2_get_block() with ocfs2_map_blocks(), I
left the WARN here to alert us during the migration. And also notify us when
we call this function on a symlink file.
> > + goto bail;
> > + }
> > +
> > + err = ocfs2_extent_map_get_blocks(inode, map->lblk, &p_blkno, &count,
> > + &ext_flags);
> > + if (err) {
> > + mlog(ML_ERROR, "get_blocks() failed, inode: 0x%p, "
> > + "block: %llu\n", inode, map->lblk);
> > + goto bail;
> > + }
> > +
> > + if (max_blocks < count)
> > + count = max_blocks;
> > +
> > + map->pblk = p_blkno;
> > + map->len = count;
> > +
> > + /*
> > + * ocfs2 never allocates in this function - the only time we
> > + * need to use MAP_NEW is when we're extending i_size on a file
> > + * system which doesn't support holes, in which case MAP_NEW
> > + * allows __block_write_begin() to zero.
> > + *
> > + * If we see this on a sparse file system, then a truncate has
> > + * raced us and removed the cluster. In this case, we clear
> > + * the buffers dirty and uptodate bits and let the buffer code
> > + * ignore it as a hole.
> > + */
> > + if (create && map->pblk == 0 && ocfs2_sparse_alloc(osb)) {
> > + map->flags &= ~(OCFS2_MAP_DIRTY | OCFS2_MAP_UPTODATE);
> > + goto bail;
> > + }
> > +
> > + if (p_blkno) {
> > + if (ext_flags & OCFS2_EXT_UNWRITTEN) {
> > + map->flags |= OCFS2_MAP_UNWRITTEN;
> > + } else if (!(ext_flags & OCFS2_EXT_UNWRITTEN)) {
> > + /* Treat the unwritten extent as a hole for zeroing purposes. */
> > + map->flags |= OCFS2_MAP_MAPPED;
> > + } else {
> > + /* nothing to do */
> > + }
> > + }
>
> It looks odd here. Can simplify to:
>
> if (ext_flags & OCFS2_EXT_UNWRITTEN)
> map->flags |= OCFS2_MAP_UNWRITTEN;
> else
> map->flags |= OCFS2_MAP_MAPPED;
>
I wrote this logic to set up a framework for future code. I added some macro
definitions in ocfs2.h (e.g., OCFS2_MAP_NEW, OCFS2_MAP_NEEDS_VALIDATE, etc.).
I would like to keep the current logic and add a comment like:
/* TODO: handling other OCFS2_MAP_XX in the future */
Do you agree?
> > +
> > + if (!ocfs2_sparse_alloc(osb)) {
> > + if (map->pblk == 0) {
> > + err = -EIO;
> > + mlog(ML_ERROR,
> > + "iblock = %llu p_blkno = %llu blkno=(%llu)\n",
> > + (unsigned long long)map->lblk,
> > + (unsigned long long)map->pblk,
> > + (unsigned long long)OCFS2_I(inode)->ip_blkno);
> > + mlog(ML_ERROR, "Size %llu, clusters %u\n",
> > + (unsigned long long)i_size_read(inode),
> > + OCFS2_I(inode)->ip_clusters);
> > + dump_stack();
> > + goto bail;
> > + }
> > + }
> > +
> > + past_eof = ocfs2_blocks_for_bytes(inode->i_sb, i_size_read(inode));
> > +
> > + if (create && (map->lblk >= past_eof))
> > + map->flags |= OCFS2_MAP_NEW;
> > +
> > +bail:
> > + if (err < 0)
> > + return -EIO;
>
> Why swallow the error code?
> I'd rather propagate the actual error.
>
I keep the legacy ocfs2_get_block() logic here.
I have tested the logic where it returns 'err' by xfstests, and the results look
fine.
Will update the return logic in the next version.
Thanks,
Heming
> > + else
> > + return map->len;
> > +}
> > +
> > int ocfs2_get_block(struct inode *inode, sector_t iblock,
> > struct buffer_head *bh_result, int create)
> > {
> > diff --git a/fs/ocfs2/aops.h b/fs/ocfs2/aops.h
> > index 114efc9111e4..8dd6edd7c1a1 100644
> > --- a/fs/ocfs2/aops.h
> > +++ b/fs/ocfs2/aops.h
> > @@ -42,6 +42,8 @@ int ocfs2_size_fits_inline_data(struct buffer_head *di_bh, u64 new_size);
> >
> > int ocfs2_get_block(struct inode *inode, sector_t iblock,
> > struct buffer_head *bh_result, int create);
> > +int ocfs2_map_blocks(struct inode *inode, struct ocfs2_map_block *map,
> > + int flags);
> > /* all ocfs2_dio_end_io()'s fault */
> > #define ocfs2_iocb_is_rw_locked(iocb) \
> > test_bit(0, (unsigned long *)&iocb->private)
> > diff --git a/fs/ocfs2/buffer_head_io.c b/fs/ocfs2/buffer_head_io.c
> > index 7bfe377af2df..493f2209cca5 100644
> > --- a/fs/ocfs2/buffer_head_io.c
> > +++ b/fs/ocfs2/buffer_head_io.c
> > @@ -23,18 +23,6 @@
> > #include "buffer_head_io.h"
> > #include "ocfs2_trace.h"
> >
> > -/*
> > - * Bits on bh->b_state used by ocfs2.
> > - *
> > - * These MUST be after the JBD2 bits. Hence, we use BH_JBDPrivateStart.
> > - */
> > -enum ocfs2_state_bits {
> > - BH_NeedsValidate = BH_JBDPrivateStart,
> > -};
> > -
> > -/* Expand the magic b_state functions */
> > -BUFFER_FNS(NeedsValidate, needs_validate);
> > -
> > int ocfs2_write_block(struct ocfs2_super *osb, struct buffer_head *bh,
> > struct ocfs2_caching_info *ci)
> > {
> > diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h
> > index 62cad6522c7a..095f7ae5dded 100644
> > --- a/fs/ocfs2/ocfs2.h
> > +++ b/fs/ocfs2/ocfs2.h
> > @@ -509,7 +509,50 @@ struct ocfs2_super
> > struct ocfs2_filecheck_sysfs_entry osb_fc_ent;
> > };
> >
> > -#define OCFS2_SB(sb) ((struct ocfs2_super *)(sb)->s_fs_info)
> > +/*
> > + * Bits on bh->b_state used by ocfs2.
> > + *
> > + * These MUST be after the JBD2 bits. Hence, we use BH_JBDPrivateStart.
> > + */
> > +enum ocfs2_state_bits {
> > + BH_NeedsValidate = BH_JBDPrivateStart,
> > +};
> > +
> > +/* Expand the magic b_state functions */
> > +BUFFER_FNS(NeedsValidate, needs_validate);
> > +
> > +/*
> > + * Logical to physical block mapping, used by ocfs2_map_blocks()
> > + *
> > + * This structure is used to pass requests into ocfs2_map_blocks() as
> > + * well as to store the information returned by ocfs2_map_blocks(). It
> > + * takes less room on the stack than a struct buffer_head.
> > + */
> > +#define OCFS2_MAP_NEW BIT(BH_New)
> > +#define OCFS2_MAP_MAPPED BIT(BH_Mapped)
> > +#define OCFS2_MAP_UNWRITTEN BIT(BH_Unwritten)
> > +/* useless? #define OCFS2_MAP_BOUNDARY BIT(BH_Boundary) */
> > +/* useless? #define OCFS2_MAP_DELAYED BIT(BH_Delay) */
> > +#define OCFS2_MAP_DIRTY BIT(BH_Dirty)
> > +#define OCFS2_MAP_UPTODATE BIT(BH_Uptodate)
> > +#define OCFS2_MAP_NEEDS_VALIDATE BIT(BH_NeedsValidate)
> > +#define OCFS2_MAP_DEFER_COMPLETION BIT(BH_Defer_Completion)
> > +#define OCFS2_MAP_FLAGS (OCFS2_MAP_NEW | OCFS2_MAP_MAPPED |\
> > + OCFS2_MAP_DIRTY | OCFS2_MAP_UPTODATE |\
> > + OCFS2_MAP_NEEDS_VALIDATE |\
> > + OCFS2_MAP_DEFER_COMPLETION)
> > +
> > +struct ocfs2_map_block {
> > + u64 pblk; /* physical block# */
> > + u64 lblk; /* logical block# */
> > + u64 len; /* number of block */
> > + unsigned int flags;
> > +};
> > +
> > +/* Flags used by ocfs2_map_blocks() */
> > +#define OCFS2_GET_BLOCKS_CREATE (0x0001)
> > +
> > +#define OCFS2_SB(sb) ((struct ocfs2_super *)(sb)->s_fs_info)
> >
> > /* Useful typedef for passing around journal access functions */
> > typedef int (*ocfs2_journal_access_func)(handle_t *handle,
>
next prev parent reply other threads:[~2026-08-02 11:28 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-27 6:17 [RFC PATCH v2 0/4] migrates ocfs2 DIO from buffer_head to iomap Heming Zhao
2026-07-27 6:17 ` [RFC PATCH v2 1/4] ocfs2: Add new ocfs2_map_blocks() to introduce iomap feature Heming Zhao
2026-07-28 5:41 ` Joseph Qi
2026-08-02 10:17 ` Heming Zhao
2026-08-02 11:28 ` Heming Zhao [this message]
2026-07-27 6:17 ` [RFC PATCH v2 2/4] ocfs2: switch dio read path from buffer_head to iomap Heming Zhao
2026-07-28 4:16 ` Christoph Hellwig
2026-08-02 10:30 ` Heming Zhao
2026-07-28 5:50 ` Joseph Qi
2026-08-02 10:36 ` Heming Zhao
2026-07-27 6:17 ` [RFC PATCH v2 3/4] ocfs2: switch dio write " Heming Zhao
2026-07-28 4:18 ` Christoph Hellwig
2026-07-28 6:07 ` Joseph Qi
2026-08-02 10:37 ` Heming Zhao
2026-07-27 6:18 ` [RFC PATCH v2 4/4] ocfs2: remove legacy blockdev direct-IO path APIs Heming Zhao
2026-07-28 4:19 ` Christoph Hellwig
2026-07-28 4:25 ` Heming Zhao
2026-07-28 6:11 ` Joseph Qi
2026-08-02 10:37 ` Heming Zhao
2026-07-28 4:11 ` [RFC PATCH v2 0/4] migrates ocfs2 DIO from buffer_head to iomap Christoph Hellwig
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=am8oSsQDQrynSXBf@p15 \
--to=heming.zhao@suse.com \
--cc=hch@lst.de \
--cc=jlbec@evilplan.org \
--cc=joseph.qi@linux.alibaba.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mark@fasheh.com \
--cc=ocfs2-devel@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.