]> www.infradead.org Git - users/hch/xfs.git/commitdiff
iomap: refactor dio ->end_io handling i_rwsem-non_owner.2
authorChristoph Hellwig <hch@lst.de>
Mon, 17 Feb 2020 21:54:51 +0000 (13:54 -0800)
committerChristoph Hellwig <hch@lst.de>
Mon, 17 Feb 2020 22:13:53 +0000 (14:13 -0800)
Pass an (opaque) iomap_dio argument to the ->end_io handler an perform
the common end I/O action in a new helper that needs be called from
->end_io if implemented.  This will allow to move unlocking of i_rwsem
or other lock schemes like the proposed range locks from the ->end_io
handler.

Signed-off-by: Christoph Hellwig <hch@lst.de>
fs/ext4/file.c
fs/iomap/direct-io.c
fs/xfs/xfs_file.c
fs/zonefs/super.c
include/linux/iomap.h

index 5f225881176b93a3d50e3accc2ccaa07e46f605a..3dc210db33868e3801623753b0a62ee5287b1013 100644 (file)
@@ -361,20 +361,16 @@ truncate:
        return written;
 }
 
-static int ext4_dio_write_end_io(struct kiocb *iocb, ssize_t size,
-                                int error, unsigned int flags)
+static ssize_t ext4_dio_write_end_io(struct kiocb *iocb, struct iomap_dio *dio,
+               ssize_t size, int error, unsigned int flags)
 {
        loff_t offset = iocb->ki_pos;
        struct inode *inode = file_inode(iocb->ki_filp);
+       ssize_t ret = 0;
 
-       if (error)
-               return error;
-
-       if (size && flags & IOMAP_DIO_UNWRITTEN)
-               return ext4_convert_unwritten_extents(NULL, inode,
-                                                     offset, size);
-
-       return 0;
+       if (!error && size && (flags & IOMAP_DIO_UNWRITTEN))
+               ret = ext4_convert_unwritten_extents(NULL, inode, offset, size);
+       return iomap_dio_end_io(dio, ret);
 }
 
 static const struct iomap_dio_ops ext4_dio_write_ops = {
index 23837926c0c595eee7c8bb49867a7b4824b27409..945dc48e9bdf4eb2142d2c45f79e6ef25b1df8a4 100644 (file)
@@ -70,25 +70,20 @@ static void iomap_dio_submit_bio(struct iomap_dio *dio, struct iomap *iomap,
        dio->submit.cookie = submit_bio(bio);
 }
 
-static ssize_t iomap_dio_complete(struct iomap_dio *dio)
+ssize_t iomap_dio_end_io(struct iomap_dio *dio, int error)
 {
-       const struct iomap_dio_ops *dops = dio->dops;
        struct kiocb *iocb = dio->iocb;
        struct inode *inode = file_inode(iocb->ki_filp);
        loff_t offset = iocb->ki_pos;
-       ssize_t ret = dio->error;
+       ssize_t ret = dio->size;
 
-       if (dops && dops->end_io)
-               ret = dops->end_io(iocb, dio->size, ret, dio->flags);
-
-       if (likely(!ret)) {
-               ret = dio->size;
-               /* check for short read */
-               if (offset + ret > dio->i_size &&
-                   !(dio->flags & IOMAP_DIO_WRITE))
-                       ret = dio->i_size - offset;
-               iocb->ki_pos += ret;
-       }
+       if (unlikely(error))
+               return error;
+
+       /* check for short read */
+       if (!(dio->flags & IOMAP_DIO_WRITE) && offset + ret > dio->i_size)
+               ret = dio->i_size - offset;
+       iocb->ki_pos += ret;
 
        /*
         * Try again to invalidate clean pages which might have been cached by
@@ -102,13 +97,10 @@ static ssize_t iomap_dio_complete(struct iomap_dio *dio)
         * ->end_io() when necessary, otherwise a racing buffer read would cache
         * zeros from unwritten extents.
         */
-       if (!dio->error &&
-           (dio->flags & IOMAP_DIO_WRITE) && inode->i_mapping->nrpages) {
-               int err;
-               err = invalidate_inode_pages2_range(inode->i_mapping,
+       if ((dio->flags & IOMAP_DIO_WRITE) && inode->i_mapping->nrpages) {
+               if (invalidate_inode_pages2_range(inode->i_mapping,
                                offset >> PAGE_SHIFT,
-                               (offset + dio->size - 1) >> PAGE_SHIFT);
-               if (err)
+                               (offset + dio->size - 1) >> PAGE_SHIFT))
                        dio_warn_stale_pagecache(iocb->ki_filp);
        }
 
@@ -116,10 +108,23 @@ static ssize_t iomap_dio_complete(struct iomap_dio *dio)
         * If this is a DSYNC write, make sure we push it to stable storage now
         * that we've written data.
         */
-       if (ret > 0 && (dio->flags & IOMAP_DIO_NEED_SYNC))
-               ret = generic_write_sync(iocb, ret);
+       if ((dio->flags & IOMAP_DIO_NEED_SYNC) && ret > 0)
+               return generic_write_sync(iocb, ret);
+       return ret;
+}
+
+static ssize_t iomap_dio_complete(struct iomap_dio *dio)
+{
+       const struct iomap_dio_ops *dops = dio->dops;
+       ssize_t ret;
+
+       if (dops && dops->end_io)
+               ret = dops->end_io(dio->iocb, dio, dio->size, dio->error,
+                                  dio->flags);
+       else
+               ret = iomap_dio_end_io(dio, dio->error);
 
-       inode_dio_end(file_inode(iocb->ki_filp));
+       inode_dio_end(file_inode(dio->iocb->ki_filp));
        kfree(dio);
 
        return ret;
index b8a4a3f29b367dd35a46351991e5dd7c010f35a9..7e3b77e1aec53653fdecefebc10f8bdd8fb1f858 100644 (file)
@@ -372,9 +372,10 @@ restart:
        return file_modified(file);
 }
 
-static int
+static ssize_t
 xfs_dio_write_end_io(
        struct kiocb            *iocb,
+       struct iomap_dio        *dio,
        ssize_t                 size,
        int                     error,
        unsigned                flags)
@@ -392,7 +393,7 @@ xfs_dio_write_end_io(
        if (error)
                return error;
        if (!size)
-               return 0;
+               goto done;
 
        /*
         * Capture amount written on completion as we can't reliably account
@@ -410,7 +411,7 @@ xfs_dio_write_end_io(
        if (flags & IOMAP_DIO_COW) {
                error = xfs_reflink_end_cow(ip, offset, size);
                if (error)
-                       goto out;
+                       goto out_restore_nofs;
        }
 
        /*
@@ -421,7 +422,7 @@ xfs_dio_write_end_io(
         */
        if (flags & IOMAP_DIO_UNWRITTEN) {
                error = xfs_iomap_write_unwritten(ip, offset, size, true);
-               goto out;
+               goto out_restore_nofs;
        }
 
        /*
@@ -444,9 +445,10 @@ xfs_dio_write_end_io(
                spin_unlock(&ip->i_flags_lock);
        }
 
-out:
+out_restore_nofs:
        memalloc_nofs_restore(nofs_flag);
-       return error;
+done:
+       return iomap_dio_end_io(dio, error);
 }
 
 static const struct iomap_dio_ops xfs_dio_write_ops = {
index 8bc6ef82d693e06f0dc0da790db63cda8364f989..bd8341cab68473718ae178fc328d517452482c36 100644 (file)
@@ -548,8 +548,9 @@ static loff_t zonefs_file_llseek(struct file *file, loff_t offset, int whence)
        return generic_file_llseek_size(file, offset, whence, isize, isize);
 }
 
-static int zonefs_file_write_dio_end_io(struct kiocb *iocb, ssize_t size,
-                                       int error, unsigned int flags)
+static ssize_t zonefs_file_write_dio_end_io(struct kiocb *iocb,
+               struct iomap_dio *dio, ssize_t size, int error,
+               unsigned int flags)
 {
        struct inode *inode = file_inode(iocb->ki_filp);
        struct zonefs_inode_info *zi = ZONEFS_I(inode);
@@ -575,7 +576,7 @@ static int zonefs_file_write_dio_end_io(struct kiocb *iocb, ssize_t size,
                mutex_unlock(&zi->i_truncate_mutex);
        }
 
-       return 0;
+       return iomap_dio_end_io(dio, 0);
 }
 
 static const struct iomap_dio_ops zonefs_write_dio_ops = {
@@ -715,15 +716,16 @@ static ssize_t zonefs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
        return zonefs_file_buffered_write(iocb, from);
 }
 
-static int zonefs_file_read_dio_end_io(struct kiocb *iocb, ssize_t size,
-                                      int error, unsigned int flags)
+static ssize_t zonefs_file_read_dio_end_io(struct kiocb *iocb,
+               struct iomap_dio *dio, ssize_t size, int error,
+               unsigned int flags)
 {
        if (error) {
                zonefs_io_error(file_inode(iocb->ki_filp), false);
                return error;
        }
 
-       return 0;
+       return iomap_dio_end_io(dio, 0);
 }
 
 static const struct iomap_dio_ops zonefs_read_dio_ops = {
index 8b09463dae0dba2a4a60ce2372863ba0e8fd16b9..e7ace7a46c65e7b38992d1d1d999a85ff9b7dd41 100644 (file)
@@ -13,6 +13,7 @@
 struct address_space;
 struct fiemap_extent_info;
 struct inode;
+struct iomap_dio;
 struct iomap_writepage_ctx;
 struct iov_iter;
 struct kiocb;
@@ -250,14 +251,15 @@ int iomap_writepages(struct address_space *mapping,
 #define IOMAP_DIO_COW          (1 << 1)        /* covers COW extent(s) */
 
 struct iomap_dio_ops {
-       int (*end_io)(struct kiocb *iocb, ssize_t size, int error,
-                     unsigned flags);
+       ssize_t (*end_io)(struct kiocb *iocb, struct iomap_dio *dio, ssize_t size,
+                     int error, unsigned flags);
 };
 
 ssize_t iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
                const struct iomap_ops *ops, const struct iomap_dio_ops *dops,
                bool wait_for_completion);
 int iomap_dio_iopoll(struct kiocb *kiocb, bool spin);
+ssize_t iomap_dio_end_io(struct iomap_dio *dio, int error);
 
 #ifdef CONFIG_SWAP
 struct file;