aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/xfs/libxfs/xfs_iext_tree.c20
-rw-r--r--fs/xfs/xfs_aops.c4
-rw-r--r--fs/xfs/xfs_iomap.c3
3 files changed, 21 insertions, 6 deletions
diff --git a/fs/xfs/libxfs/xfs_iext_tree.c b/fs/xfs/libxfs/xfs_iext_tree.c
index 8a7aea041ee1..771dd072015d 100644
--- a/fs/xfs/libxfs/xfs_iext_tree.c
+++ b/fs/xfs/libxfs/xfs_iext_tree.c
@@ -14,6 +14,7 @@
14#include "xfs_inode_fork.h" 14#include "xfs_inode_fork.h"
15#include "xfs_trans_resv.h" 15#include "xfs_trans_resv.h"
16#include "xfs_mount.h" 16#include "xfs_mount.h"
17#include "xfs_bmap.h"
17#include "xfs_trace.h" 18#include "xfs_trace.h"
18 19
19/* 20/*
@@ -612,6 +613,19 @@ xfs_iext_realloc_root(
612 cur->leaf = new; 613 cur->leaf = new;
613} 614}
614 615
616/*
617 * Increment the sequence counter if we are on a COW fork. This allows
618 * the writeback code to skip looking for a COW extent if the COW fork
619 * hasn't changed. We use WRITE_ONCE here to ensure the update to the
620 * sequence counter is seen before the modifications to the extent
621 * tree itself take effect.
622 */
623static inline void xfs_iext_inc_seq(struct xfs_ifork *ifp, int state)
624{
625 if (state & BMAP_COWFORK)
626 WRITE_ONCE(ifp->if_seq, READ_ONCE(ifp->if_seq) + 1);
627}
628
615void 629void
616xfs_iext_insert( 630xfs_iext_insert(
617 struct xfs_inode *ip, 631 struct xfs_inode *ip,
@@ -624,7 +638,7 @@ xfs_iext_insert(
624 struct xfs_iext_leaf *new = NULL; 638 struct xfs_iext_leaf *new = NULL;
625 int nr_entries, i; 639 int nr_entries, i;
626 640
627 ifp->if_seq++; 641 xfs_iext_inc_seq(ifp, state);
628 642
629 if (ifp->if_height == 0) 643 if (ifp->if_height == 0)
630 xfs_iext_alloc_root(ifp, cur); 644 xfs_iext_alloc_root(ifp, cur);
@@ -866,7 +880,7 @@ xfs_iext_remove(
866 ASSERT(ifp->if_u1.if_root != NULL); 880 ASSERT(ifp->if_u1.if_root != NULL);
867 ASSERT(xfs_iext_valid(ifp, cur)); 881 ASSERT(xfs_iext_valid(ifp, cur));
868 882
869 ifp->if_seq++; 883 xfs_iext_inc_seq(ifp, state);
870 884
871 nr_entries = xfs_iext_leaf_nr_entries(ifp, leaf, cur->pos) - 1; 885 nr_entries = xfs_iext_leaf_nr_entries(ifp, leaf, cur->pos) - 1;
872 for (i = cur->pos; i < nr_entries; i++) 886 for (i = cur->pos; i < nr_entries; i++)
@@ -974,7 +988,7 @@ xfs_iext_update_extent(
974{ 988{
975 struct xfs_ifork *ifp = xfs_iext_state_to_fork(ip, state); 989 struct xfs_ifork *ifp = xfs_iext_state_to_fork(ip, state);
976 990
977 ifp->if_seq++; 991 xfs_iext_inc_seq(ifp, state);
978 992
979 if (cur->pos == 0) { 993 if (cur->pos == 0) {
980 struct xfs_bmbt_irec old; 994 struct xfs_bmbt_irec old;
diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c
index 235b4ddcd324..49f5f5896a43 100644
--- a/fs/xfs/xfs_aops.c
+++ b/fs/xfs/xfs_aops.c
@@ -351,7 +351,7 @@ xfs_map_blocks(
351 if (imap_valid && 351 if (imap_valid &&
352 (!xfs_inode_has_cow_data(ip) || 352 (!xfs_inode_has_cow_data(ip) ||
353 wpc->io_type == XFS_IO_COW || 353 wpc->io_type == XFS_IO_COW ||
354 wpc->cow_seq == ip->i_cowfp->if_seq)) 354 wpc->cow_seq == READ_ONCE(ip->i_cowfp->if_seq)))
355 return 0; 355 return 0;
356 356
357 if (XFS_FORCED_SHUTDOWN(mp)) 357 if (XFS_FORCED_SHUTDOWN(mp))
@@ -380,7 +380,7 @@ xfs_map_blocks(
380 xfs_iext_lookup_extent(ip, ip->i_cowfp, offset_fsb, &icur, &imap)) 380 xfs_iext_lookup_extent(ip, ip->i_cowfp, offset_fsb, &icur, &imap))
381 cow_fsb = imap.br_startoff; 381 cow_fsb = imap.br_startoff;
382 if (cow_fsb != NULLFILEOFF && cow_fsb <= offset_fsb) { 382 if (cow_fsb != NULLFILEOFF && cow_fsb <= offset_fsb) {
383 wpc->cow_seq = ip->i_cowfp->if_seq; 383 wpc->cow_seq = READ_ONCE(ip->i_cowfp->if_seq);
384 xfs_iunlock(ip, XFS_ILOCK_SHARED); 384 xfs_iunlock(ip, XFS_ILOCK_SHARED);
385 /* 385 /*
386 * Truncate can race with writeback since writeback doesn't 386 * Truncate can race with writeback since writeback doesn't
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
index 3282575e2df4..6320aca39f39 100644
--- a/fs/xfs/xfs_iomap.c
+++ b/fs/xfs/xfs_iomap.c
@@ -655,6 +655,7 @@ xfs_iomap_write_allocate(
655 unsigned int *cow_seq) 655 unsigned int *cow_seq)
656{ 656{
657 xfs_mount_t *mp = ip->i_mount; 657 xfs_mount_t *mp = ip->i_mount;
658 struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork);
658 xfs_fileoff_t offset_fsb, last_block; 659 xfs_fileoff_t offset_fsb, last_block;
659 xfs_fileoff_t end_fsb, map_start_fsb; 660 xfs_fileoff_t end_fsb, map_start_fsb;
660 xfs_filblks_t count_fsb; 661 xfs_filblks_t count_fsb;
@@ -768,7 +769,7 @@ xfs_iomap_write_allocate(
768 goto error0; 769 goto error0;
769 770
770 if (whichfork == XFS_COW_FORK) 771 if (whichfork == XFS_COW_FORK)
771 *cow_seq = XFS_IFORK_PTR(ip, whichfork)->if_seq; 772 *cow_seq = READ_ONCE(ifp->if_seq);
772 xfs_iunlock(ip, XFS_ILOCK_EXCL); 773 xfs_iunlock(ip, XFS_ILOCK_EXCL);
773 } 774 }
774 775