diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/xfs/xfs_bmap.c | 13 | ||||
-rw-r--r-- | fs/xfs/xfs_bmap_btree.c | 38 |
2 files changed, 14 insertions, 37 deletions
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index c21e01a9b2dd..cf4dee01983a 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c | |||
@@ -1746,11 +1746,18 @@ xfs_bmap_add_extent_unwritten_real( | |||
1746 | if ((error = xfs_bmbt_insert(cur, &i))) | 1746 | if ((error = xfs_bmbt_insert(cur, &i))) |
1747 | goto done; | 1747 | goto done; |
1748 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); | 1748 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
1749 | if ((error = xfs_bmbt_increment(cur, 0, &i))) | 1749 | /* |
1750 | * Reset the cursor to the position of the new extent | ||
1751 | * we are about to insert as we can't trust it after | ||
1752 | * the previous insert. | ||
1753 | */ | ||
1754 | if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff, | ||
1755 | new->br_startblock, new->br_blockcount, | ||
1756 | &i))) | ||
1750 | goto done; | 1757 | goto done; |
1751 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); | 1758 | XFS_WANT_CORRUPTED_GOTO(i == 0, done); |
1752 | /* new middle extent - newext */ | 1759 | /* new middle extent - newext */ |
1753 | cur->bc_rec.b = *new; | 1760 | cur->bc_rec.b.br_state = new->br_state; |
1754 | if ((error = xfs_bmbt_insert(cur, &i))) | 1761 | if ((error = xfs_bmbt_insert(cur, &i))) |
1755 | goto done; | 1762 | goto done; |
1756 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); | 1763 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
diff --git a/fs/xfs/xfs_bmap_btree.c b/fs/xfs/xfs_bmap_btree.c index 4f0e849d973e..4aa2f11ba563 100644 --- a/fs/xfs/xfs_bmap_btree.c +++ b/fs/xfs/xfs_bmap_btree.c | |||
@@ -2029,22 +2029,8 @@ xfs_bmbt_increment( | |||
2029 | * Insert the current record at the point referenced by cur. | 2029 | * Insert the current record at the point referenced by cur. |
2030 | * | 2030 | * |
2031 | * A multi-level split of the tree on insert will invalidate the original | 2031 | * A multi-level split of the tree on insert will invalidate the original |
2032 | * cursor. It appears, however, that some callers assume that the cursor is | 2032 | * cursor. All callers of this function should assume that the cursor is |
2033 | * always valid. Hence if we do a multi-level split we need to revalidate the | 2033 | * no longer valid and revalidate it. |
2034 | * cursor. | ||
2035 | * | ||
2036 | * When a split occurs, we will see a new cursor returned. Use that as a | ||
2037 | * trigger to determine if we need to revalidate the original cursor. If we get | ||
2038 | * a split, then use the original irec to lookup up the path of the record we | ||
2039 | * just inserted. | ||
2040 | * | ||
2041 | * Note that the fact that the btree root is in the inode means that we can | ||
2042 | * have the level of the tree change without a "split" occurring at the root | ||
2043 | * level. What happens is that the root is migrated to an allocated block and | ||
2044 | * the inode root is pointed to it. This means a single split can change the | ||
2045 | * level of the tree (level 2 -> level 3) and invalidate the old cursor. Hence | ||
2046 | * the level change should be accounted as a split so as to correctly trigger a | ||
2047 | * revalidation of the old cursor. | ||
2048 | */ | 2034 | */ |
2049 | int /* error */ | 2035 | int /* error */ |
2050 | xfs_bmbt_insert( | 2036 | xfs_bmbt_insert( |
@@ -2057,14 +2043,11 @@ xfs_bmbt_insert( | |||
2057 | xfs_fsblock_t nbno; | 2043 | xfs_fsblock_t nbno; |
2058 | xfs_btree_cur_t *ncur; | 2044 | xfs_btree_cur_t *ncur; |
2059 | xfs_bmbt_rec_t nrec; | 2045 | xfs_bmbt_rec_t nrec; |
2060 | xfs_bmbt_irec_t oirec; /* original irec */ | ||
2061 | xfs_btree_cur_t *pcur; | 2046 | xfs_btree_cur_t *pcur; |
2062 | int splits = 0; | ||
2063 | 2047 | ||
2064 | XFS_BMBT_TRACE_CURSOR(cur, ENTRY); | 2048 | XFS_BMBT_TRACE_CURSOR(cur, ENTRY); |
2065 | level = 0; | 2049 | level = 0; |
2066 | nbno = NULLFSBLOCK; | 2050 | nbno = NULLFSBLOCK; |
2067 | oirec = cur->bc_rec.b; | ||
2068 | xfs_bmbt_disk_set_all(&nrec, &cur->bc_rec.b); | 2051 | xfs_bmbt_disk_set_all(&nrec, &cur->bc_rec.b); |
2069 | ncur = NULL; | 2052 | ncur = NULL; |
2070 | pcur = cur; | 2053 | pcur = cur; |
@@ -2073,13 +2056,11 @@ xfs_bmbt_insert( | |||
2073 | &i))) { | 2056 | &i))) { |
2074 | if (pcur != cur) | 2057 | if (pcur != cur) |
2075 | xfs_btree_del_cursor(pcur, XFS_BTREE_ERROR); | 2058 | xfs_btree_del_cursor(pcur, XFS_BTREE_ERROR); |
2076 | goto error0; | 2059 | XFS_BMBT_TRACE_CURSOR(cur, ERROR); |
2060 | return error; | ||
2077 | } | 2061 | } |
2078 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | 2062 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); |
2079 | if (pcur != cur && (ncur || nbno == NULLFSBLOCK)) { | 2063 | if (pcur != cur && (ncur || nbno == NULLFSBLOCK)) { |
2080 | /* allocating a new root is effectively a split */ | ||
2081 | if (cur->bc_nlevels != pcur->bc_nlevels) | ||
2082 | splits++; | ||
2083 | cur->bc_nlevels = pcur->bc_nlevels; | 2064 | cur->bc_nlevels = pcur->bc_nlevels; |
2084 | cur->bc_private.b.allocated += | 2065 | cur->bc_private.b.allocated += |
2085 | pcur->bc_private.b.allocated; | 2066 | pcur->bc_private.b.allocated; |
@@ -2093,21 +2074,10 @@ xfs_bmbt_insert( | |||
2093 | xfs_btree_del_cursor(pcur, XFS_BTREE_NOERROR); | 2074 | xfs_btree_del_cursor(pcur, XFS_BTREE_NOERROR); |
2094 | } | 2075 | } |
2095 | if (ncur) { | 2076 | if (ncur) { |
2096 | splits++; | ||
2097 | pcur = ncur; | 2077 | pcur = ncur; |
2098 | ncur = NULL; | 2078 | ncur = NULL; |
2099 | } | 2079 | } |
2100 | } while (nbno != NULLFSBLOCK); | 2080 | } while (nbno != NULLFSBLOCK); |
2101 | |||
2102 | if (splits > 1) { | ||
2103 | /* revalidate the old cursor as we had a multi-level split */ | ||
2104 | error = xfs_bmbt_lookup_eq(cur, oirec.br_startoff, | ||
2105 | oirec.br_startblock, oirec.br_blockcount, &i); | ||
2106 | if (error) | ||
2107 | goto error0; | ||
2108 | ASSERT(i == 1); | ||
2109 | } | ||
2110 | |||
2111 | XFS_BMBT_TRACE_CURSOR(cur, EXIT); | 2081 | XFS_BMBT_TRACE_CURSOR(cur, EXIT); |
2112 | *stat = i; | 2082 | *stat = i; |
2113 | return 0; | 2083 | return 0; |