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, |
