Re: [PATCH v5 4/4] iomap: add simple dio path for small direct I/O

From: changfengnan

Date: Tue Jun 30 2026 - 23:24:34 EST



> From: "Christoph Hellwig"<hch@xxxxxxxxxxxxx>
> Date:  Tue, Jun 30, 2026, 19:49
> Subject:  Re: [PATCH v5 4/4] iomap: add simple dio path for small direct I/O
> To: "Fengnan Chang"<changfengnan@xxxxxxxxxxxxx>
> Cc: <brauner@xxxxxxxxxx>, <djwong@xxxxxxxxxx>, <hch@xxxxxxxxxxxxx>, <ojaswin@xxxxxxxxxxxxx>, <dgc@xxxxxxxxxx>, <linux-xfs@xxxxxxxxxxxxxxx>, <linux-fsdevel@xxxxxxxxxxxxxxx>, <linux-ext4@xxxxxxxxxxxxxxx>, <linux-kernel@xxxxxxxxxxxxxxx>, <lidiangang@xxxxxxxxxxxxx>, <pankaj.raghav@xxxxxxxxx>
> On Mon, Jun 29, 2026 at 08:01:24PM +0800, Fengnan Chang wrote:
> > +#include <linux/kobject.h>
> > +#include <linux/sysfs.h>
> 
> I don't think these two headers are actually used by the new code.

Debug code, will delete in next version.

> 
> > +struct iomap_dio_simple {
> > +        struct kiocb                *iocb;
> > +        size_t                        size;
> > +        unsigned int                dio_flags;
> > +        struct work_struct        work;
> > +        /*
> > +         * Align @bio to a cacheline boundary so that, combined with the
> > +         * front_pad passed to bioset_init(), the bio sits at the start of
> > +         * a cacheline in memory returned by the (HWCACHE-aligned) bio
> > +         * slab.  This keeps the hot fields block layer touches on submit
> > +         * and completion (bi_iter, bi_status, ...) within a single line.
> > +         */
> > +        struct bio        bio ____cacheline_aligned_in_smp;
> 
> Add an extra tab here so it aligns with the fields above the comment?

All comments will fix in next version, thanks.

> 
> > +        int error = blk_status_to_errno(bio->bi_status);
> > +        ssize_t ret = error;
> > +
> > +        if (likely(!ret)) {
> > +                ret = sr->size;
> > +                iocb->ki_pos += ret;
> > +        } else if (should_report_dio_fserror(ret)) {
> > +                fserror_report_io(inode, FSERR_DIRECTIO_READ, iocb->ki_pos,
> > +                                  sr->size, ret, GFP_NOFS);
> > +        }
> > +
> > +        iomap_dio_bio_release_pages(bio, sr->dio_flags, ret < 0);
> > +        inode_dio_end(inode);
> > +        trace_iomap_dio_complete(iocb, error, ret);
> 
> I think some of this could be micro-optimized a bit more and
> cleaned up at the same time:
> 
>         ssize_t ret;
> 
>         if (unlikely(bio->bi_status) {
>                 ret = blk_status_to_errno(bio->bi_status);
>                 if (should_report_dio_fserror(ret)) {
>                         fserror_report_io(inode, FSERR_DIRECTIO_READ,
>                                         iocb->ki_pos, sr->size, ret,
>                                         GFP_NOFS);
>                 }
>         } else {
>                 ret = sr->size;
>                 iocb->ki_pos += ret;
>         }
> 
>         iomap_dio_bio_release_pages(bio, sr->dio_flags, ret < 0);
>         inode_dio_end(inode);
>         trace_iomap_dio_complete(iocb, ret < 0 ? ret : 0, ret);
> 
>         return ret;
> 
> > +
> > +static void iomap_dio_simple_complete_work(struct work_struct *work)
> > +{
> > +        struct iomap_dio_simple *sr =
> > +                        container_of(work, struct iomap_dio_simple, work);
> 
> A single tab indent is enough here. (and used in the next function)
> 
> > +        struct bio *bio;
> > +        bool wait_for_completion = is_sync_kiocb(iocb);
> > +        ssize_t ret;
> 
> Nitpick: keep variables initialized at declaration time above those
> that are not initalized.
> 
> > +        /*
> > +         * Fast path for small, block-aligned direct I/Os that map to a
> > +         * single contiguous on-disk extent.
> > +         *
> > +         * @dops must be NULL: a non-NULL @dops means the caller wants its
> > +         * ->end_io / ->submit_io hooks invoked, and in particular wants its
> > +         * bios to be allocated from the filesystem-private @dops->bio_set
> > +         * (whose front_pad sizes a filesystem-private wrapper around the
> > +         * bio).  The fast path instead allocates from the shared
> > +         * iomap_dio_simple_pool, whose front_pad matches
> > +         * struct iomap_dio_simple; the two wrappers are not
> > +         * interchangeable, so we must fall back to __iomap_dio_rw() in
> > +         * that case.
> > +         *
> > +         * @done_before must be zero: a non-zero caller-accumulated residual
> > +         * cannot be carried through a single-bio inline completion.
> > +         *
> > +         * -ENOTBLK is the private sentinel returned by iomap_dio_simple()
> > +         * when it decides the request does not fit the fast path.
> > +         * In that case we proceed to the generic __iomap_dio_rw() slow
> > +         * path.  Any other errno is a real result and is propagated as-is,
> > +         * in particular -EAGAIN for IOCB_NOWAIT must reach the caller.
> 
> I think this documentation belongs above iomap_dio_simple, not
> here.  And maye it should also mention that iomap_dio_simple_supported
> enforces these limitations.  Mostly anyway, and maybe the other two
> checks should go into that as well for completeness?
>