diff options
-rw-r--r-- | fs/ocfs2/alloc.c | 80 |
1 files changed, 76 insertions, 4 deletions
diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index 678a067d9251..9edcde4974aa 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c | |||
@@ -475,6 +475,12 @@ struct ocfs2_path { | |||
475 | #define path_leaf_el(_path) ((_path)->p_node[(_path)->p_tree_depth].el) | 475 | #define path_leaf_el(_path) ((_path)->p_node[(_path)->p_tree_depth].el) |
476 | #define path_num_items(_path) ((_path)->p_tree_depth + 1) | 476 | #define path_num_items(_path) ((_path)->p_tree_depth + 1) |
477 | 477 | ||
478 | static int ocfs2_find_path(struct inode *inode, struct ocfs2_path *path, | ||
479 | u32 cpos); | ||
480 | static void ocfs2_adjust_rightmost_records(struct inode *inode, | ||
481 | handle_t *handle, | ||
482 | struct ocfs2_path *path, | ||
483 | struct ocfs2_extent_rec *insert_rec); | ||
478 | /* | 484 | /* |
479 | * Reset the actual path elements so that we can re-use the structure | 485 | * Reset the actual path elements so that we can re-use the structure |
480 | * to build another path. Generally, this involves freeing the buffer | 486 | * to build another path. Generally, this involves freeing the buffer |
@@ -1013,6 +1019,54 @@ static inline u32 ocfs2_sum_rightmost_rec(struct ocfs2_extent_list *el) | |||
1013 | } | 1019 | } |
1014 | 1020 | ||
1015 | /* | 1021 | /* |
1022 | * Change range of the branches in the right most path according to the leaf | ||
1023 | * extent block's rightmost record. | ||
1024 | */ | ||
1025 | static int ocfs2_adjust_rightmost_branch(handle_t *handle, | ||
1026 | struct inode *inode, | ||
1027 | struct ocfs2_extent_tree *et) | ||
1028 | { | ||
1029 | int status; | ||
1030 | struct ocfs2_path *path = NULL; | ||
1031 | struct ocfs2_extent_list *el; | ||
1032 | struct ocfs2_extent_rec *rec; | ||
1033 | |||
1034 | path = ocfs2_new_path_from_et(et); | ||
1035 | if (!path) { | ||
1036 | status = -ENOMEM; | ||
1037 | return status; | ||
1038 | } | ||
1039 | |||
1040 | status = ocfs2_find_path(inode, path, UINT_MAX); | ||
1041 | if (status < 0) { | ||
1042 | mlog_errno(status); | ||
1043 | goto out; | ||
1044 | } | ||
1045 | |||
1046 | status = ocfs2_extend_trans(handle, path_num_items(path) + | ||
1047 | handle->h_buffer_credits); | ||
1048 | if (status < 0) { | ||
1049 | mlog_errno(status); | ||
1050 | goto out; | ||
1051 | } | ||
1052 | |||
1053 | status = ocfs2_journal_access_path(inode, handle, path); | ||
1054 | if (status < 0) { | ||
1055 | mlog_errno(status); | ||
1056 | goto out; | ||
1057 | } | ||
1058 | |||
1059 | el = path_leaf_el(path); | ||
1060 | rec = &el->l_recs[le32_to_cpu(el->l_next_free_rec) - 1]; | ||
1061 | |||
1062 | ocfs2_adjust_rightmost_records(inode, handle, path, rec); | ||
1063 | |||
1064 | out: | ||
1065 | ocfs2_free_path(path); | ||
1066 | return status; | ||
1067 | } | ||
1068 | |||
1069 | /* | ||
1016 | * Add an entire tree branch to our inode. eb_bh is the extent block | 1070 | * Add an entire tree branch to our inode. eb_bh is the extent block |
1017 | * to start at, if we don't want to start the branch at the dinode | 1071 | * to start at, if we don't want to start the branch at the dinode |
1018 | * structure. | 1072 | * structure. |
@@ -1038,7 +1092,7 @@ static int ocfs2_add_branch(struct ocfs2_super *osb, | |||
1038 | struct ocfs2_extent_block *eb; | 1092 | struct ocfs2_extent_block *eb; |
1039 | struct ocfs2_extent_list *eb_el; | 1093 | struct ocfs2_extent_list *eb_el; |
1040 | struct ocfs2_extent_list *el; | 1094 | struct ocfs2_extent_list *el; |
1041 | u32 new_cpos; | 1095 | u32 new_cpos, root_end; |
1042 | 1096 | ||
1043 | mlog_entry_void(); | 1097 | mlog_entry_void(); |
1044 | 1098 | ||
@@ -1055,6 +1109,27 @@ static int ocfs2_add_branch(struct ocfs2_super *osb, | |||
1055 | 1109 | ||
1056 | new_blocks = le16_to_cpu(el->l_tree_depth); | 1110 | new_blocks = le16_to_cpu(el->l_tree_depth); |
1057 | 1111 | ||
1112 | eb = (struct ocfs2_extent_block *)(*last_eb_bh)->b_data; | ||
1113 | new_cpos = ocfs2_sum_rightmost_rec(&eb->h_list); | ||
1114 | root_end = ocfs2_sum_rightmost_rec(et->et_root_el); | ||
1115 | |||
1116 | /* | ||
1117 | * If there is a gap before the root end and the real end | ||
1118 | * of the righmost leaf block, we need to remove the gap | ||
1119 | * between new_cpos and root_end first so that the tree | ||
1120 | * is consistent after we add a new branch(it will start | ||
1121 | * from new_cpos). | ||
1122 | */ | ||
1123 | if (root_end > new_cpos) { | ||
1124 | mlog(0, "adjust the cluster end from %u to %u\n", | ||
1125 | root_end, new_cpos); | ||
1126 | status = ocfs2_adjust_rightmost_branch(handle, inode, et); | ||
1127 | if (status) { | ||
1128 | mlog_errno(status); | ||
1129 | goto bail; | ||
1130 | } | ||
1131 | } | ||
1132 | |||
1058 | /* allocate the number of new eb blocks we need */ | 1133 | /* allocate the number of new eb blocks we need */ |
1059 | new_eb_bhs = kcalloc(new_blocks, sizeof(struct buffer_head *), | 1134 | new_eb_bhs = kcalloc(new_blocks, sizeof(struct buffer_head *), |
1060 | GFP_KERNEL); | 1135 | GFP_KERNEL); |
@@ -1071,9 +1146,6 @@ static int ocfs2_add_branch(struct ocfs2_super *osb, | |||
1071 | goto bail; | 1146 | goto bail; |
1072 | } | 1147 | } |
1073 | 1148 | ||
1074 | eb = (struct ocfs2_extent_block *)(*last_eb_bh)->b_data; | ||
1075 | new_cpos = ocfs2_sum_rightmost_rec(&eb->h_list); | ||
1076 | |||
1077 | /* Note: new_eb_bhs[new_blocks - 1] is the guy which will be | 1149 | /* Note: new_eb_bhs[new_blocks - 1] is the guy which will be |
1078 | * linked with the rest of the tree. | 1150 | * linked with the rest of the tree. |
1079 | * conversly, new_eb_bhs[0] is the new bottommost leaf. | 1151 | * conversly, new_eb_bhs[0] is the new bottommost leaf. |