diff options
Diffstat (limited to 'fs/xfs/xfs_btree.c')
-rw-r--r-- | fs/xfs/xfs_btree.c | 99 |
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 | */ | ||
1179 | int /* error */ | ||
1180 | xfs_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 | } | ||
1258 | out1: | ||
1259 | XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); | ||
1260 | *stat = 1; | ||
1261 | return 0; | ||
1262 | |||
1263 | out0: | ||
1264 | XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); | ||
1265 | *stat = 0; | ||
1266 | return 0; | ||
1267 | |||
1268 | error0: | ||
1269 | XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); | ||
1270 | return error; | ||
1271 | } | ||
1272 | |||