]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
xfs: move the dio write relocking out of xfs_ilock_for_iomap
authorChristoph Hellwig <hch@lst.de>
Sun, 23 Jun 2024 05:44:26 +0000 (07:44 +0200)
committerChandan Babu R <chandanbabu@kernel.org>
Mon, 1 Jul 2024 04:02:29 +0000 (09:32 +0530)
About half of xfs_ilock_for_iomap deals with a special case for direct
I/O writes to COW files that need to take the ilock exclusively.  Move
this code into the one callers that cares and simplify
xfs_ilock_for_iomap.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Chandan Babu R <chandanbabu@kernel.org>
fs/xfs/xfs_iomap.c

index 414903885ab90571e18634b98d7551ecff270749..72c981e3dc9211c8dd1db0faffeb92239e7f07b5 100644 (file)
@@ -717,53 +717,30 @@ imap_needs_cow(
        return true;
 }
 
+/*
+ * Extents not yet cached requires exclusive access, don't block for
+ * IOMAP_NOWAIT.
+ *
+ * This is basically an opencoded xfs_ilock_data_map_shared() call, but with
+ * support for IOMAP_NOWAIT.
+ */
 static int
 xfs_ilock_for_iomap(
        struct xfs_inode        *ip,
        unsigned                flags,
        unsigned                *lockmode)
 {
-       unsigned int            mode = *lockmode;
-       bool                    is_write = flags & (IOMAP_WRITE | IOMAP_ZERO);
-
-       /*
-        * COW writes may allocate delalloc space or convert unwritten COW
-        * extents, so we need to make sure to take the lock exclusively here.
-        */
-       if (xfs_is_cow_inode(ip) && is_write)
-               mode = XFS_ILOCK_EXCL;
-
-       /*
-        * Extents not yet cached requires exclusive access, don't block.  This
-        * is an opencoded xfs_ilock_data_map_shared() call but with
-        * non-blocking behaviour.
-        */
-       if (xfs_need_iread_extents(&ip->i_df)) {
-               if (flags & IOMAP_NOWAIT)
-                       return -EAGAIN;
-               mode = XFS_ILOCK_EXCL;
-       }
-
-relock:
        if (flags & IOMAP_NOWAIT) {
-               if (!xfs_ilock_nowait(ip, mode))
+               if (xfs_need_iread_extents(&ip->i_df))
+                       return -EAGAIN;
+               if (!xfs_ilock_nowait(ip, *lockmode))
                        return -EAGAIN;
        } else {
-               xfs_ilock(ip, mode);
+               if (xfs_need_iread_extents(&ip->i_df))
+                       *lockmode = XFS_ILOCK_EXCL;
+               xfs_ilock(ip, *lockmode);
        }
 
-       /*
-        * The reflink iflag could have changed since the earlier unlocked
-        * check, so if we got ILOCK_SHARED for a write and but we're now a
-        * reflink inode we have to switch to ILOCK_EXCL and relock.
-        */
-       if (mode == XFS_ILOCK_SHARED && is_write && xfs_is_cow_inode(ip)) {
-               xfs_iunlock(ip, mode);
-               mode = XFS_ILOCK_EXCL;
-               goto relock;
-       }
-
-       *lockmode = mode;
        return 0;
 }
 
@@ -801,7 +778,7 @@ xfs_direct_write_iomap_begin(
        int                     nimaps = 1, error = 0;
        bool                    shared = false;
        u16                     iomap_flags = 0;
-       unsigned int            lockmode = XFS_ILOCK_SHARED;
+       unsigned int            lockmode;
        u64                     seq;
 
        ASSERT(flags & (IOMAP_WRITE | IOMAP_ZERO));
@@ -817,10 +794,30 @@ xfs_direct_write_iomap_begin(
        if (offset + length > i_size_read(inode))
                iomap_flags |= IOMAP_F_DIRTY;
 
+       /*
+        * COW writes may allocate delalloc space or convert unwritten COW
+        * extents, so we need to make sure to take the lock exclusively here.
+        */
+       if (xfs_is_cow_inode(ip))
+               lockmode = XFS_ILOCK_EXCL;
+       else
+               lockmode = XFS_ILOCK_SHARED;
+
+relock:
        error = xfs_ilock_for_iomap(ip, flags, &lockmode);
        if (error)
                return error;
 
+       /*
+        * The reflink iflag could have changed since the earlier unlocked
+        * check, check if it again and relock if needed.
+        */
+       if (xfs_is_cow_inode(ip) && lockmode == XFS_ILOCK_SHARED) {
+               xfs_iunlock(ip, lockmode);
+               lockmode = XFS_ILOCK_EXCL;
+               goto relock;
+       }
+
        error = xfs_bmapi_read(ip, offset_fsb, end_fsb - offset_fsb, &imap,
                               &nimaps, 0);
        if (error)