aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_btree.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/xfs_btree.c')
-rw-r--r--fs/xfs/xfs_btree.c99
1 files changed, 99 insertions, 0 deletions
diff --git a/fs/xfs/xfs_btree.c b/fs/xfs/xfs_btree.c
index e9ab86b7990e..3d561f8f78d0 100644
--- a/fs/xfs/xfs_btree.c
+++ b/fs/xfs/xfs_btree.c
@@ -1171,3 +1171,102 @@ error0:
1171 XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); 1171 XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
1172 return error; 1172 return error;
1173} 1173}
1174
1175/*
1176 * Decrement cursor by one record at the level.
1177 * For nonzero levels the leaf-ward information is untouched.
1178 */
1179int /* error */
1180xfs_btree_decrement(
1181 struct xfs_btree_cur *cur,
1182 int level,
1183 int *stat) /* success/failure */
1184{
1185 struct xfs_btree_block *block;
1186 xfs_buf_t *bp;
1187 int error; /* error return value */
1188 int lev;
1189 union xfs_btree_ptr ptr;
1190
1191 XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
1192 XFS_BTREE_TRACE_ARGI(cur, level);
1193
1194 ASSERT(level < cur->bc_nlevels);
1195
1196 /* Read-ahead to the left at this level. */
1197 xfs_btree_readahead(cur, level, XFS_BTCUR_LEFTRA);
1198
1199 /* We're done if we remain in the block after the decrement. */
1200 if (--cur->bc_ptrs[level] > 0)
1201 goto out1;
1202
1203 /* Get a pointer to the btree block. */
1204 block = xfs_btree_get_block(cur, level, &bp);
1205
1206#ifdef DEBUG
1207 error = xfs_btree_check_block(cur, block, level, bp);
1208 if (error)
1209 goto error0;
1210#endif
1211
1212 /* Fail if we just went off the left edge of the tree. */
1213 xfs_btree_get_sibling(cur, block, &ptr, XFS_BB_LEFTSIB);
1214 if (xfs_btree_ptr_is_null(cur, &ptr))
1215 goto out0;
1216
1217 XFS_BTREE_STATS_INC(cur, decrement);
1218
1219 /*
1220 * March up the tree decrementing pointers.
1221 * Stop when we don't go off the left edge of a block.
1222 */
1223 for (lev = level + 1; lev < cur->bc_nlevels; lev++) {
1224 if (--cur->bc_ptrs[lev] > 0)
1225 break;
1226 /* Read-ahead the left block for the next loop. */
1227 xfs_btree_readahead(cur, lev, XFS_BTCUR_LEFTRA);
1228 }
1229
1230 /*
1231 * If we went off the root then we are seriously confused.
1232 * or the root of the tree is in an inode.
1233 */
1234 if (lev == cur->bc_nlevels) {
1235 if (cur->bc_flags & XFS_BTREE_ROOT_IN_INODE)
1236 goto out0;
1237 ASSERT(0);
1238 error = EFSCORRUPTED;
1239 goto error0;
1240 }
1241 ASSERT(lev < cur->bc_nlevels);
1242
1243 /*
1244 * Now walk back down the tree, fixing up the cursor's buffer
1245 * pointers and key numbers.
1246 */
1247 for (block = xfs_btree_get_block(cur, lev, &bp); lev > level; ) {
1248 union xfs_btree_ptr *ptrp;
1249
1250 ptrp = xfs_btree_ptr_addr(cur, cur->bc_ptrs[lev], block);
1251 error = xfs_btree_read_buf_block(cur, ptrp, --lev,
1252 0, &block, &bp);
1253 if (error)
1254 goto error0;
1255 xfs_btree_setbuf(cur, lev, bp);
1256 cur->bc_ptrs[lev] = xfs_btree_get_numrecs(block);
1257 }
1258out1:
1259 XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
1260 *stat = 1;
1261 return 0;
1262
1263out0:
1264 XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
1265 *stat = 0;
1266 return 0;
1267
1268error0:
1269 XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
1270 return error;
1271}
1272