]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
iomap: factor out a iomap_dio_done helper
authorChristoph Hellwig <hch@lst.de>
Thu, 6 Feb 2025 06:40:04 +0000 (07:40 +0100)
committerChristian Brauner <brauner@kernel.org>
Thu, 6 Feb 2025 12:02:14 +0000 (13:02 +0100)
Split out the struct iomap-dio level final completion from
iomap_dio_bio_end_io into a helper to clean up the code and make it
reusable.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Link: https://lore.kernel.org/r/20250206064035.2323428-7-hch@lst.de
Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/iomap/direct-io.c

index 641649a04614e48fc6fa24e52d00f866ada2c43c..277ece243770747b41243b965b8a1abbbe6debf8 100644 (file)
@@ -165,43 +165,31 @@ static inline void iomap_dio_set_error(struct iomap_dio *dio, int ret)
        cmpxchg(&dio->error, 0, ret);
 }
 
-void iomap_dio_bio_end_io(struct bio *bio)
+/*
+ * Called when dio->ref reaches zero from an I/O completion.
+ */
+static void iomap_dio_done(struct iomap_dio *dio)
 {
-       struct iomap_dio *dio = bio->bi_private;
-       bool should_dirty = (dio->flags & IOMAP_DIO_DIRTY);
        struct kiocb *iocb = dio->iocb;
 
-       if (bio->bi_status)
-               iomap_dio_set_error(dio, blk_status_to_errno(bio->bi_status));
-       if (!atomic_dec_and_test(&dio->ref))
-               goto release_bio;
-
-       /*
-        * Synchronous dio, task itself will handle any completion work
-        * that needs after IO. All we need to do is wake the task.
-        */
        if (dio->wait_for_completion) {
+               /*
+                * Synchronous I/O, task itself will handle any completion work
+                * that needs after IO. All we need to do is wake the task.
+                */
                struct task_struct *waiter = dio->submit.waiter;
 
                WRITE_ONCE(dio->submit.waiter, NULL);
                blk_wake_io_task(waiter);
-               goto release_bio;
-       }
-
-       /*
-        * Flagged with IOMAP_DIO_INLINE_COMP, we can complete it inline
-        */
-       if (dio->flags & IOMAP_DIO_INLINE_COMP) {
+       } else if (dio->flags & IOMAP_DIO_INLINE_COMP) {
                WRITE_ONCE(iocb->private, NULL);
                iomap_dio_complete_work(&dio->aio.work);
-               goto release_bio;
-       }
-
-       /*
-        * If this dio is flagged with IOMAP_DIO_CALLER_COMP, then schedule
-        * our completion that way to avoid an async punt to a workqueue.
-        */
-       if (dio->flags & IOMAP_DIO_CALLER_COMP) {
+       } else if (dio->flags & IOMAP_DIO_CALLER_COMP) {
+               /*
+                * If this dio is flagged with IOMAP_DIO_CALLER_COMP, then
+                * schedule our completion that way to avoid an async punt to a
+                * workqueue.
+                */
                /* only polled IO cares about private cleared */
                iocb->private = dio;
                iocb->dio_complete = iomap_dio_deferred_complete;
@@ -219,19 +207,31 @@ void iomap_dio_bio_end_io(struct bio *bio)
                 * issuer.
                 */
                iocb->ki_complete(iocb, 0);
-               goto release_bio;
+       } else {
+               struct inode *inode = file_inode(iocb->ki_filp);
+
+               /*
+                * Async DIO completion that requires filesystem level
+                * completion work gets punted to a work queue to complete as
+                * the operation may require more IO to be issued to finalise
+                * filesystem metadata changes or guarantee data integrity.
+                */
+               INIT_WORK(&dio->aio.work, iomap_dio_complete_work);
+               queue_work(inode->i_sb->s_dio_done_wq, &dio->aio.work);
        }
+}
+
+void iomap_dio_bio_end_io(struct bio *bio)
+{
+       struct iomap_dio *dio = bio->bi_private;
+       bool should_dirty = (dio->flags & IOMAP_DIO_DIRTY);
+
+       if (bio->bi_status)
+               iomap_dio_set_error(dio, blk_status_to_errno(bio->bi_status));
+
+       if (atomic_dec_and_test(&dio->ref))
+               iomap_dio_done(dio);
 
-       /*
-        * Async DIO completion that requires filesystem level completion work
-        * gets punted to a work queue to complete as the operation may require
-        * more IO to be issued to finalise filesystem metadata changes or
-        * guarantee data integrity.
-        */
-       INIT_WORK(&dio->aio.work, iomap_dio_complete_work);
-       queue_work(file_inode(iocb->ki_filp)->i_sb->s_dio_done_wq,
-                       &dio->aio.work);
-release_bio:
        if (should_dirty) {
                bio_check_pages_dirty(bio);
        } else {