diff options
Diffstat (limited to 'fs/xfs/xfs_bmap_btree.c')
-rw-r--r-- | fs/xfs/xfs_bmap_btree.c | 76 |
1 files changed, 39 insertions, 37 deletions
diff --git a/fs/xfs/xfs_bmap_btree.c b/fs/xfs/xfs_bmap_btree.c index 4f0e849d973e..23efad29a5cd 100644 --- a/fs/xfs/xfs_bmap_btree.c +++ b/fs/xfs/xfs_bmap_btree.c | |||
@@ -1493,12 +1493,27 @@ xfs_bmbt_split( | |||
1493 | left = XFS_BUF_TO_BMBT_BLOCK(lbp); | 1493 | left = XFS_BUF_TO_BMBT_BLOCK(lbp); |
1494 | args.fsbno = cur->bc_private.b.firstblock; | 1494 | args.fsbno = cur->bc_private.b.firstblock; |
1495 | args.firstblock = args.fsbno; | 1495 | args.firstblock = args.fsbno; |
1496 | args.minleft = 0; | ||
1496 | if (args.fsbno == NULLFSBLOCK) { | 1497 | if (args.fsbno == NULLFSBLOCK) { |
1497 | args.fsbno = lbno; | 1498 | args.fsbno = lbno; |
1498 | args.type = XFS_ALLOCTYPE_START_BNO; | 1499 | args.type = XFS_ALLOCTYPE_START_BNO; |
1499 | } else | 1500 | /* |
1501 | * Make sure there is sufficient room left in the AG to | ||
1502 | * complete a full tree split for an extent insert. If | ||
1503 | * we are converting the middle part of an extent then | ||
1504 | * we may need space for two tree splits. | ||
1505 | * | ||
1506 | * We are relying on the caller to make the correct block | ||
1507 | * reservation for this operation to succeed. If the | ||
1508 | * reservation amount is insufficient then we may fail a | ||
1509 | * block allocation here and corrupt the filesystem. | ||
1510 | */ | ||
1511 | args.minleft = xfs_trans_get_block_res(args.tp); | ||
1512 | } else if (cur->bc_private.b.flist->xbf_low) | ||
1513 | args.type = XFS_ALLOCTYPE_START_BNO; | ||
1514 | else | ||
1500 | args.type = XFS_ALLOCTYPE_NEAR_BNO; | 1515 | args.type = XFS_ALLOCTYPE_NEAR_BNO; |
1501 | args.mod = args.minleft = args.alignment = args.total = args.isfl = | 1516 | args.mod = args.alignment = args.total = args.isfl = |
1502 | args.userdata = args.minalignslop = 0; | 1517 | args.userdata = args.minalignslop = 0; |
1503 | args.minlen = args.maxlen = args.prod = 1; | 1518 | args.minlen = args.maxlen = args.prod = 1; |
1504 | args.wasdel = cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL; | 1519 | args.wasdel = cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL; |
@@ -1510,6 +1525,21 @@ xfs_bmbt_split( | |||
1510 | XFS_BMBT_TRACE_CURSOR(cur, ERROR); | 1525 | XFS_BMBT_TRACE_CURSOR(cur, ERROR); |
1511 | return error; | 1526 | return error; |
1512 | } | 1527 | } |
1528 | if (args.fsbno == NULLFSBLOCK && args.minleft) { | ||
1529 | /* | ||
1530 | * Could not find an AG with enough free space to satisfy | ||
1531 | * a full btree split. Try again without minleft and if | ||
1532 | * successful activate the lowspace algorithm. | ||
1533 | */ | ||
1534 | args.fsbno = 0; | ||
1535 | args.type = XFS_ALLOCTYPE_FIRST_AG; | ||
1536 | args.minleft = 0; | ||
1537 | if ((error = xfs_alloc_vextent(&args))) { | ||
1538 | XFS_BMBT_TRACE_CURSOR(cur, ERROR); | ||
1539 | return error; | ||
1540 | } | ||
1541 | cur->bc_private.b.flist->xbf_low = 1; | ||
1542 | } | ||
1513 | if (args.fsbno == NULLFSBLOCK) { | 1543 | if (args.fsbno == NULLFSBLOCK) { |
1514 | XFS_BMBT_TRACE_CURSOR(cur, EXIT); | 1544 | XFS_BMBT_TRACE_CURSOR(cur, EXIT); |
1515 | *stat = 0; | 1545 | *stat = 0; |
@@ -2029,22 +2059,8 @@ xfs_bmbt_increment( | |||
2029 | * Insert the current record at the point referenced by cur. | 2059 | * Insert the current record at the point referenced by cur. |
2030 | * | 2060 | * |
2031 | * A multi-level split of the tree on insert will invalidate the original | 2061 | * 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 | 2062 | * 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 | 2063 | * 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 | */ | 2064 | */ |
2049 | int /* error */ | 2065 | int /* error */ |
2050 | xfs_bmbt_insert( | 2066 | xfs_bmbt_insert( |
@@ -2057,14 +2073,11 @@ xfs_bmbt_insert( | |||
2057 | xfs_fsblock_t nbno; | 2073 | xfs_fsblock_t nbno; |
2058 | xfs_btree_cur_t *ncur; | 2074 | xfs_btree_cur_t *ncur; |
2059 | xfs_bmbt_rec_t nrec; | 2075 | xfs_bmbt_rec_t nrec; |
2060 | xfs_bmbt_irec_t oirec; /* original irec */ | ||
2061 | xfs_btree_cur_t *pcur; | 2076 | xfs_btree_cur_t *pcur; |
2062 | int splits = 0; | ||
2063 | 2077 | ||
2064 | XFS_BMBT_TRACE_CURSOR(cur, ENTRY); | 2078 | XFS_BMBT_TRACE_CURSOR(cur, ENTRY); |
2065 | level = 0; | 2079 | level = 0; |
2066 | nbno = NULLFSBLOCK; | 2080 | nbno = NULLFSBLOCK; |
2067 | oirec = cur->bc_rec.b; | ||
2068 | xfs_bmbt_disk_set_all(&nrec, &cur->bc_rec.b); | 2081 | xfs_bmbt_disk_set_all(&nrec, &cur->bc_rec.b); |
2069 | ncur = NULL; | 2082 | ncur = NULL; |
2070 | pcur = cur; | 2083 | pcur = cur; |
@@ -2073,13 +2086,11 @@ xfs_bmbt_insert( | |||
2073 | &i))) { | 2086 | &i))) { |
2074 | if (pcur != cur) | 2087 | if (pcur != cur) |
2075 | xfs_btree_del_cursor(pcur, XFS_BTREE_ERROR); | 2088 | xfs_btree_del_cursor(pcur, XFS_BTREE_ERROR); |
2076 | goto error0; | 2089 | XFS_BMBT_TRACE_CURSOR(cur, ERROR); |
2090 | return error; | ||
2077 | } | 2091 | } |
2078 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | 2092 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); |
2079 | if (pcur != cur && (ncur || nbno == NULLFSBLOCK)) { | 2093 | 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; | 2094 | cur->bc_nlevels = pcur->bc_nlevels; |
2084 | cur->bc_private.b.allocated += | 2095 | cur->bc_private.b.allocated += |
2085 | pcur->bc_private.b.allocated; | 2096 | pcur->bc_private.b.allocated; |
@@ -2093,21 +2104,10 @@ xfs_bmbt_insert( | |||
2093 | xfs_btree_del_cursor(pcur, XFS_BTREE_NOERROR); | 2104 | xfs_btree_del_cursor(pcur, XFS_BTREE_NOERROR); |
2094 | } | 2105 | } |
2095 | if (ncur) { | 2106 | if (ncur) { |
2096 | splits++; | ||
2097 | pcur = ncur; | 2107 | pcur = ncur; |
2098 | ncur = NULL; | 2108 | ncur = NULL; |
2099 | } | 2109 | } |
2100 | } while (nbno != NULLFSBLOCK); | 2110 | } 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); | 2111 | XFS_BMBT_TRACE_CURSOR(cur, EXIT); |
2112 | *stat = i; | 2112 | *stat = i; |
2113 | return 0; | 2113 | return 0; |
@@ -2254,7 +2254,9 @@ xfs_bmbt_newroot( | |||
2254 | #endif | 2254 | #endif |
2255 | args.fsbno = be64_to_cpu(*pp); | 2255 | args.fsbno = be64_to_cpu(*pp); |
2256 | args.type = XFS_ALLOCTYPE_START_BNO; | 2256 | args.type = XFS_ALLOCTYPE_START_BNO; |
2257 | } else | 2257 | } else if (cur->bc_private.b.flist->xbf_low) |
2258 | args.type = XFS_ALLOCTYPE_START_BNO; | ||
2259 | else | ||
2258 | args.type = XFS_ALLOCTYPE_NEAR_BNO; | 2260 | args.type = XFS_ALLOCTYPE_NEAR_BNO; |
2259 | if ((error = xfs_alloc_vextent(&args))) { | 2261 | if ((error = xfs_alloc_vextent(&args))) { |
2260 | XFS_BMBT_TRACE_CURSOR(cur, ERROR); | 2262 | XFS_BMBT_TRACE_CURSOR(cur, ERROR); |