diff options
author | Christoph Hellwig <hch@infradead.org> | 2008-10-30 01:57:03 -0400 |
---|---|---|
committer | Lachlan McIlroy <lachlan@sgi.com> | 2008-10-30 01:57:03 -0400 |
commit | f5eb8e7ca58bc1e92436614444006120d21668ba (patch) | |
tree | 94825b885653224f74c6087956cb4e1930380467 /fs/xfs/xfs_ialloc_btree.c | |
parent | 687b890a184fef263ebb773926e1f4aa69240d01 (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.c | 212 |
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); | |||
44 | STATIC void xfs_inobt_log_ptrs(xfs_btree_cur_t *, xfs_buf_t *, int, int); | 45 | STATIC void xfs_inobt_log_ptrs(xfs_btree_cur_t *, xfs_buf_t *, int, int); |
45 | STATIC void xfs_inobt_log_recs(xfs_btree_cur_t *, xfs_buf_t *, int, int); | 46 | STATIC void xfs_inobt_log_recs(xfs_btree_cur_t *, xfs_buf_t *, int, int); |
46 | STATIC int xfs_inobt_newroot(xfs_btree_cur_t *, int *); | 47 | STATIC int xfs_inobt_newroot(xfs_btree_cur_t *, int *); |
47 | STATIC 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 | */ | ||
979 | STATIC int /* error */ | ||
980 | xfs_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 | ||
1288 | STATIC int | 1131 | STATIC int |
1132 | xfs_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 | |||
1173 | STATIC int | ||
1289 | xfs_inobt_get_maxrecs( | 1174 | xfs_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, |