aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_ialloc_btree.c
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@infradead.org>2008-10-30 01:57:03 -0400
committerLachlan McIlroy <lachlan@sgi.com>2008-10-30 01:57:03 -0400
commitf5eb8e7ca58bc1e92436614444006120d21668ba (patch)
tree94825b885653224f74c6087956cb4e1930380467 /fs/xfs/xfs_ialloc_btree.c
parent687b890a184fef263ebb773926e1f4aa69240d01 (diff)
[XFS] implement generic xfs_btree_split
Make the btree split code generic. Based on a patch from David Chinner with lots of changes to follow the original btree implementations more closely. While this loses some of the generic helper routines for inserting/moving/removing records it also solves some of the one off bugs in the original code and makes it easier to verify. SGI-PV: 985583 SGI-Modid: xfs-linux-melb:xfs-kern:32198a Signed-off-by: Christoph Hellwig <hch@infradead.org> Signed-off-by: Lachlan McIlroy <lachlan@sgi.com> Signed-off-by: Bill O'Donnell <billodo@sgi.com> Signed-off-by: David Chinner <david@fromorbit.com>
Diffstat (limited to 'fs/xfs/xfs_ialloc_btree.c')
-rw-r--r--fs/xfs/xfs_ialloc_btree.c212
1 files changed, 49 insertions, 163 deletions
diff --git a/fs/xfs/xfs_ialloc_btree.c b/fs/xfs/xfs_ialloc_btree.c
index 60f5db5d6dfa..c76190a83e4e 100644
--- a/fs/xfs/xfs_ialloc_btree.c
+++ b/fs/xfs/xfs_ialloc_btree.c
@@ -35,6 +35,7 @@
35#include "xfs_dinode.h" 35#include "xfs_dinode.h"
36#include "xfs_inode.h" 36#include "xfs_inode.h"
37#include "xfs_btree.h" 37#include "xfs_btree.h"
38#include "xfs_btree_trace.h"
38#include "xfs_ialloc.h" 39#include "xfs_ialloc.h"
39#include "xfs_alloc.h" 40#include "xfs_alloc.h"
40#include "xfs_error.h" 41#include "xfs_error.h"
@@ -44,8 +45,6 @@ STATIC void xfs_inobt_log_keys(xfs_btree_cur_t *, xfs_buf_t *, int, int);
44STATIC void xfs_inobt_log_ptrs(xfs_btree_cur_t *, xfs_buf_t *, int, int); 45STATIC void xfs_inobt_log_ptrs(xfs_btree_cur_t *, xfs_buf_t *, int, int);
45STATIC void xfs_inobt_log_recs(xfs_btree_cur_t *, xfs_buf_t *, int, int); 46STATIC void xfs_inobt_log_recs(xfs_btree_cur_t *, xfs_buf_t *, int, int);
46STATIC int xfs_inobt_newroot(xfs_btree_cur_t *, int *); 47STATIC int xfs_inobt_newroot(xfs_btree_cur_t *, int *);
47STATIC int xfs_inobt_split(xfs_btree_cur_t *, int, xfs_agblock_t *,
48 xfs_inobt_key_t *, xfs_btree_cur_t **, int *);
49 48
50/* 49/*
51 * Single level of the xfs_inobt_delete record deletion routine. 50 * Single level of the xfs_inobt_delete record deletion routine.
@@ -620,15 +619,18 @@ xfs_inobt_insrec(
620 if (i) { 619 if (i) {
621 optr = ptr = cur->bc_ptrs[level]; 620 optr = ptr = cur->bc_ptrs[level];
622 } else { 621 } else {
622 union xfs_btree_ptr bno = { .s = cpu_to_be32(nbno) };
623 /* 623 /*
624 * Next, try splitting the current block 624 * Next, try splitting the current block
625 * in half. If this works we have to 625 * in half. If this works we have to
626 * re-set our variables because 626 * re-set our variables because
627 * we could be in a different block now. 627 * we could be in a different block now.
628 */ 628 */
629 if ((error = xfs_inobt_split(cur, level, &nbno, 629 if ((error = xfs_btree_split(cur, level, &bno,
630 &nkey, &ncur, &i))) 630 (union xfs_btree_key *)&nkey,
631 &ncur, &i)))
631 return error; 632 return error;
633 nbno = be32_to_cpu(bno.s);
632 if (i) { 634 if (i) {
633 bp = cur->bc_bufs[level]; 635 bp = cur->bc_bufs[level];
634 block = XFS_BUF_TO_INOBT_BLOCK(bp); 636 block = XFS_BUF_TO_INOBT_BLOCK(bp);
@@ -973,165 +975,6 @@ xfs_inobt_newroot(
973} 975}
974 976
975/* 977/*
976 * Split cur/level block in half.
977 * Return new block number and its first record (to be inserted into parent).
978 */
979STATIC int /* error */
980xfs_inobt_split(
981 xfs_btree_cur_t *cur, /* btree cursor */
982 int level, /* level to split */
983 xfs_agblock_t *bnop, /* output: block number allocated */
984 xfs_inobt_key_t *keyp, /* output: first key of new block */
985 xfs_btree_cur_t **curp, /* output: new cursor */
986 int *stat) /* success/failure */
987{
988 xfs_alloc_arg_t args; /* allocation argument structure */
989 int error; /* error return value */
990 int i; /* loop index/record number */
991 xfs_agblock_t lbno; /* left (current) block number */
992 xfs_buf_t *lbp; /* buffer for left block */
993 xfs_inobt_block_t *left; /* left (current) btree block */
994 xfs_inobt_key_t *lkp; /* left btree key pointer */
995 xfs_inobt_ptr_t *lpp; /* left btree address pointer */
996 xfs_inobt_rec_t *lrp; /* left btree record pointer */
997 xfs_buf_t *rbp; /* buffer for right block */
998 xfs_inobt_block_t *right; /* right (new) btree block */
999 xfs_inobt_key_t *rkp; /* right btree key pointer */
1000 xfs_inobt_ptr_t *rpp; /* right btree address pointer */
1001 xfs_inobt_rec_t *rrp; /* right btree record pointer */
1002
1003 /*
1004 * Set up left block (current one).
1005 */
1006 lbp = cur->bc_bufs[level];
1007 args.tp = cur->bc_tp;
1008 args.mp = cur->bc_mp;
1009 lbno = XFS_DADDR_TO_AGBNO(args.mp, XFS_BUF_ADDR(lbp));
1010 /*
1011 * Allocate the new block.
1012 * If we can't do it, we're toast. Give up.
1013 */
1014 args.fsbno = XFS_AGB_TO_FSB(args.mp, cur->bc_private.a.agno, lbno);
1015 args.mod = args.minleft = args.alignment = args.total = args.wasdel =
1016 args.isfl = args.userdata = args.minalignslop = 0;
1017 args.minlen = args.maxlen = args.prod = 1;
1018 args.type = XFS_ALLOCTYPE_NEAR_BNO;
1019 if ((error = xfs_alloc_vextent(&args)))
1020 return error;
1021 if (args.fsbno == NULLFSBLOCK) {
1022 *stat = 0;
1023 return 0;
1024 }
1025 ASSERT(args.len == 1);
1026 rbp = xfs_btree_get_bufs(args.mp, args.tp, args.agno, args.agbno, 0);
1027 /*
1028 * Set up the new block as "right".
1029 */
1030 right = XFS_BUF_TO_INOBT_BLOCK(rbp);
1031 /*
1032 * "Left" is the current (according to the cursor) block.
1033 */
1034 left = XFS_BUF_TO_INOBT_BLOCK(lbp);
1035#ifdef DEBUG
1036 if ((error = xfs_btree_check_sblock(cur, left, level, lbp)))
1037 return error;
1038#endif
1039 /*
1040 * Fill in the btree header for the new block.
1041 */
1042 right->bb_magic = cpu_to_be32(xfs_magics[cur->bc_btnum]);
1043 right->bb_level = left->bb_level;
1044 right->bb_numrecs = cpu_to_be16(be16_to_cpu(left->bb_numrecs) / 2);
1045 /*
1046 * Make sure that if there's an odd number of entries now, that
1047 * each new block will have the same number of entries.
1048 */
1049 if ((be16_to_cpu(left->bb_numrecs) & 1) &&
1050 cur->bc_ptrs[level] <= be16_to_cpu(right->bb_numrecs) + 1)
1051 be16_add_cpu(&right->bb_numrecs, 1);
1052 i = be16_to_cpu(left->bb_numrecs) - be16_to_cpu(right->bb_numrecs) + 1;
1053 /*
1054 * For non-leaf blocks, copy keys and addresses over to the new block.
1055 */
1056 if (level > 0) {
1057 lkp = XFS_INOBT_KEY_ADDR(left, i, cur);
1058 lpp = XFS_INOBT_PTR_ADDR(left, i, cur);
1059 rkp = XFS_INOBT_KEY_ADDR(right, 1, cur);
1060 rpp = XFS_INOBT_PTR_ADDR(right, 1, cur);
1061#ifdef DEBUG
1062 for (i = 0; i < be16_to_cpu(right->bb_numrecs); i++) {
1063 if ((error = xfs_btree_check_sptr(cur, be32_to_cpu(lpp[i]), level)))
1064 return error;
1065 }
1066#endif
1067 memcpy(rkp, lkp, be16_to_cpu(right->bb_numrecs) * sizeof(*rkp));
1068 memcpy(rpp, lpp, be16_to_cpu(right->bb_numrecs) * sizeof(*rpp));
1069 xfs_inobt_log_keys(cur, rbp, 1, be16_to_cpu(right->bb_numrecs));
1070 xfs_inobt_log_ptrs(cur, rbp, 1, be16_to_cpu(right->bb_numrecs));
1071 *keyp = *rkp;
1072 }
1073 /*
1074 * For leaf blocks, copy records over to the new block.
1075 */
1076 else {
1077 lrp = XFS_INOBT_REC_ADDR(left, i, cur);
1078 rrp = XFS_INOBT_REC_ADDR(right, 1, cur);
1079 memcpy(rrp, lrp, be16_to_cpu(right->bb_numrecs) * sizeof(*rrp));
1080 xfs_inobt_log_recs(cur, rbp, 1, be16_to_cpu(right->bb_numrecs));
1081 keyp->ir_startino = rrp->ir_startino;
1082 }
1083 /*
1084 * Find the left block number by looking in the buffer.
1085 * Adjust numrecs, sibling pointers.
1086 */
1087 be16_add_cpu(&left->bb_numrecs, -(be16_to_cpu(right->bb_numrecs)));
1088 right->bb_rightsib = left->bb_rightsib;
1089 left->bb_rightsib = cpu_to_be32(args.agbno);
1090 right->bb_leftsib = cpu_to_be32(lbno);
1091 xfs_inobt_log_block(args.tp, rbp, XFS_BB_ALL_BITS);
1092 xfs_inobt_log_block(args.tp, lbp, XFS_BB_NUMRECS | XFS_BB_RIGHTSIB);
1093 /*
1094 * If there's a block to the new block's right, make that block
1095 * point back to right instead of to left.
1096 */
1097 if (be32_to_cpu(right->bb_rightsib) != NULLAGBLOCK) {
1098 xfs_inobt_block_t *rrblock; /* rr btree block */
1099 xfs_buf_t *rrbp; /* buffer for rrblock */
1100
1101 if ((error = xfs_btree_read_bufs(args.mp, args.tp, args.agno,
1102 be32_to_cpu(right->bb_rightsib), 0, &rrbp,
1103 XFS_INO_BTREE_REF)))
1104 return error;
1105 rrblock = XFS_BUF_TO_INOBT_BLOCK(rrbp);
1106 if ((error = xfs_btree_check_sblock(cur, rrblock, level, rrbp)))
1107 return error;
1108 rrblock->bb_leftsib = cpu_to_be32(args.agbno);
1109 xfs_inobt_log_block(args.tp, rrbp, XFS_BB_LEFTSIB);
1110 }
1111 /*
1112 * If the cursor is really in the right block, move it there.
1113 * If it's just pointing past the last entry in left, then we'll
1114 * insert there, so don't change anything in that case.
1115 */
1116 if (cur->bc_ptrs[level] > be16_to_cpu(left->bb_numrecs) + 1) {
1117 xfs_btree_setbuf(cur, level, rbp);
1118 cur->bc_ptrs[level] -= be16_to_cpu(left->bb_numrecs);
1119 }
1120 /*
1121 * If there are more levels, we'll need another cursor which refers
1122 * the right block, no matter where this cursor was.
1123 */
1124 if (level + 1 < cur->bc_nlevels) {
1125 if ((error = xfs_btree_dup_cursor(cur, curp)))
1126 return error;
1127 (*curp)->bc_ptrs[level + 1]++;
1128 }
1129 *bnop = args.agbno;
1130 *stat = 1;
1131 return 0;
1132}
1133
1134/*
1135 * Externally visible routines. 978 * Externally visible routines.
1136 */ 979 */
1137 980
@@ -1286,6 +1129,48 @@ xfs_inobt_dup_cursor(
1286} 1129}
1287 1130
1288STATIC int 1131STATIC int
1132xfs_inobt_alloc_block(
1133 struct xfs_btree_cur *cur,
1134 union xfs_btree_ptr *start,
1135 union xfs_btree_ptr *new,
1136 int length,
1137 int *stat)
1138{
1139 xfs_alloc_arg_t args; /* block allocation args */
1140 int error; /* error return value */
1141 xfs_agblock_t sbno = be32_to_cpu(start->s);
1142
1143 XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
1144
1145 memset(&args, 0, sizeof(args));
1146 args.tp = cur->bc_tp;
1147 args.mp = cur->bc_mp;
1148 args.fsbno = XFS_AGB_TO_FSB(args.mp, cur->bc_private.a.agno, sbno);
1149 args.minlen = 1;
1150 args.maxlen = 1;
1151 args.prod = 1;
1152 args.type = XFS_ALLOCTYPE_NEAR_BNO;
1153
1154 error = xfs_alloc_vextent(&args);
1155 if (error) {
1156 XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
1157 return error;
1158 }
1159 if (args.fsbno == NULLFSBLOCK) {
1160 XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
1161 *stat = 0;
1162 return 0;
1163 }
1164 ASSERT(args.len == 1);
1165 XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
1166
1167 new->s = cpu_to_be32(XFS_FSB_TO_AGBNO(args.mp, args.fsbno));
1168 *stat = 1;
1169 return 0;
1170}
1171
1172
1173STATIC int
1289xfs_inobt_get_maxrecs( 1174xfs_inobt_get_maxrecs(
1290 struct xfs_btree_cur *cur, 1175 struct xfs_btree_cur *cur,
1291 int level) 1176 int level)
@@ -1396,6 +1281,7 @@ static const struct xfs_btree_ops xfs_inobt_ops = {
1396 .key_len = sizeof(xfs_inobt_key_t), 1281 .key_len = sizeof(xfs_inobt_key_t),
1397 1282
1398 .dup_cursor = xfs_inobt_dup_cursor, 1283 .dup_cursor = xfs_inobt_dup_cursor,
1284 .alloc_block = xfs_inobt_alloc_block,
1399 .get_maxrecs = xfs_inobt_get_maxrecs, 1285 .get_maxrecs = xfs_inobt_get_maxrecs,
1400 .init_key_from_rec = xfs_inobt_init_key_from_rec, 1286 .init_key_from_rec = xfs_inobt_init_key_from_rec,
1401 .init_ptr_from_cur = xfs_inobt_init_ptr_from_cur, 1287 .init_ptr_from_cur = xfs_inobt_init_ptr_from_cur,