diff options
Diffstat (limited to 'fs/ext4/move_extent.c')
-rw-r--r-- | fs/ext4/move_extent.c | 149 |
1 files changed, 109 insertions, 40 deletions
diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c index e4bd8761498a..2258560e9722 100644 --- a/fs/ext4/move_extent.c +++ b/fs/ext4/move_extent.c | |||
@@ -128,6 +128,31 @@ mext_next_extent(struct inode *inode, struct ext4_ext_path *path, | |||
128 | } | 128 | } |
129 | 129 | ||
130 | /** | 130 | /** |
131 | * mext_check_null_inode - NULL check for two inodes | ||
132 | * | ||
133 | * If inode1 or inode2 is NULL, return -EIO. Otherwise, return 0. | ||
134 | */ | ||
135 | static int | ||
136 | mext_check_null_inode(struct inode *inode1, struct inode *inode2, | ||
137 | const char *function) | ||
138 | { | ||
139 | int ret = 0; | ||
140 | |||
141 | if (inode1 == NULL) { | ||
142 | ext4_error(inode2->i_sb, function, | ||
143 | "Both inodes should not be NULL: " | ||
144 | "inode1 NULL inode2 %lu", inode2->i_ino); | ||
145 | ret = -EIO; | ||
146 | } else if (inode2 == NULL) { | ||
147 | ext4_error(inode1->i_sb, function, | ||
148 | "Both inodes should not be NULL: " | ||
149 | "inode1 %lu inode2 NULL", inode1->i_ino); | ||
150 | ret = -EIO; | ||
151 | } | ||
152 | return ret; | ||
153 | } | ||
154 | |||
155 | /** | ||
131 | * mext_double_down_read - Acquire two inodes' read semaphore | 156 | * mext_double_down_read - Acquire two inodes' read semaphore |
132 | * | 157 | * |
133 | * @orig_inode: original inode structure | 158 | * @orig_inode: original inode structure |
@@ -139,8 +164,6 @@ mext_double_down_read(struct inode *orig_inode, struct inode *donor_inode) | |||
139 | { | 164 | { |
140 | struct inode *first = orig_inode, *second = donor_inode; | 165 | struct inode *first = orig_inode, *second = donor_inode; |
141 | 166 | ||
142 | BUG_ON(orig_inode == NULL || donor_inode == NULL); | ||
143 | |||
144 | /* | 167 | /* |
145 | * Use the inode number to provide the stable locking order instead | 168 | * Use the inode number to provide the stable locking order instead |
146 | * of its address, because the C language doesn't guarantee you can | 169 | * of its address, because the C language doesn't guarantee you can |
@@ -167,8 +190,6 @@ mext_double_down_write(struct inode *orig_inode, struct inode *donor_inode) | |||
167 | { | 190 | { |
168 | struct inode *first = orig_inode, *second = donor_inode; | 191 | struct inode *first = orig_inode, *second = donor_inode; |
169 | 192 | ||
170 | BUG_ON(orig_inode == NULL || donor_inode == NULL); | ||
171 | |||
172 | /* | 193 | /* |
173 | * Use the inode number to provide the stable locking order instead | 194 | * Use the inode number to provide the stable locking order instead |
174 | * of its address, because the C language doesn't guarantee you can | 195 | * of its address, because the C language doesn't guarantee you can |
@@ -193,8 +214,6 @@ mext_double_down_write(struct inode *orig_inode, struct inode *donor_inode) | |||
193 | static void | 214 | static void |
194 | mext_double_up_read(struct inode *orig_inode, struct inode *donor_inode) | 215 | mext_double_up_read(struct inode *orig_inode, struct inode *donor_inode) |
195 | { | 216 | { |
196 | BUG_ON(orig_inode == NULL || donor_inode == NULL); | ||
197 | |||
198 | up_read(&EXT4_I(orig_inode)->i_data_sem); | 217 | up_read(&EXT4_I(orig_inode)->i_data_sem); |
199 | up_read(&EXT4_I(donor_inode)->i_data_sem); | 218 | up_read(&EXT4_I(donor_inode)->i_data_sem); |
200 | } | 219 | } |
@@ -209,8 +228,6 @@ mext_double_up_read(struct inode *orig_inode, struct inode *donor_inode) | |||
209 | static void | 228 | static void |
210 | mext_double_up_write(struct inode *orig_inode, struct inode *donor_inode) | 229 | mext_double_up_write(struct inode *orig_inode, struct inode *donor_inode) |
211 | { | 230 | { |
212 | BUG_ON(orig_inode == NULL || donor_inode == NULL); | ||
213 | |||
214 | up_write(&EXT4_I(orig_inode)->i_data_sem); | 231 | up_write(&EXT4_I(orig_inode)->i_data_sem); |
215 | up_write(&EXT4_I(donor_inode)->i_data_sem); | 232 | up_write(&EXT4_I(donor_inode)->i_data_sem); |
216 | } | 233 | } |
@@ -534,7 +551,15 @@ mext_leaf_block(handle_t *handle, struct inode *orig_inode, | |||
534 | * oext |-----------| | 551 | * oext |-----------| |
535 | * new_ext |-------| | 552 | * new_ext |-------| |
536 | */ | 553 | */ |
537 | BUG_ON(le32_to_cpu(oext->ee_block) + oext_alen - 1 < new_ext_end); | 554 | if (le32_to_cpu(oext->ee_block) + oext_alen - 1 < new_ext_end) { |
555 | ext4_error(orig_inode->i_sb, __func__, | ||
556 | "new_ext_end(%u) should be less than or equal to " | ||
557 | "oext->ee_block(%u) + oext_alen(%d) - 1", | ||
558 | new_ext_end, le32_to_cpu(oext->ee_block), | ||
559 | oext_alen); | ||
560 | ret = -EIO; | ||
561 | goto out; | ||
562 | } | ||
538 | 563 | ||
539 | /* | 564 | /* |
540 | * Case: new_ext is smaller than original extent | 565 | * Case: new_ext is smaller than original extent |
@@ -558,6 +583,7 @@ mext_leaf_block(handle_t *handle, struct inode *orig_inode, | |||
558 | 583 | ||
559 | ret = mext_insert_extents(handle, orig_inode, orig_path, o_start, | 584 | ret = mext_insert_extents(handle, orig_inode, orig_path, o_start, |
560 | o_end, &start_ext, &new_ext, &end_ext); | 585 | o_end, &start_ext, &new_ext, &end_ext); |
586 | out: | ||
561 | return ret; | 587 | return ret; |
562 | } | 588 | } |
563 | 589 | ||
@@ -668,7 +694,20 @@ mext_replace_branches(handle_t *handle, struct inode *orig_inode, | |||
668 | /* Loop for the donor extents */ | 694 | /* Loop for the donor extents */ |
669 | while (1) { | 695 | while (1) { |
670 | /* The extent for donor must be found. */ | 696 | /* The extent for donor must be found. */ |
671 | BUG_ON(!dext || donor_off != le32_to_cpu(tmp_dext.ee_block)); | 697 | if (!dext) { |
698 | ext4_error(donor_inode->i_sb, __func__, | ||
699 | "The extent for donor must be found"); | ||
700 | err = -EIO; | ||
701 | goto out; | ||
702 | } else if (donor_off != le32_to_cpu(tmp_dext.ee_block)) { | ||
703 | ext4_error(donor_inode->i_sb, __func__, | ||
704 | "Donor offset(%u) and the first block of donor " | ||
705 | "extent(%u) should be equal", | ||
706 | donor_off, | ||
707 | le32_to_cpu(tmp_dext.ee_block)); | ||
708 | err = -EIO; | ||
709 | goto out; | ||
710 | } | ||
672 | 711 | ||
673 | /* Set donor extent to orig extent */ | 712 | /* Set donor extent to orig extent */ |
674 | err = mext_leaf_block(handle, orig_inode, | 713 | err = mext_leaf_block(handle, orig_inode, |
@@ -1050,18 +1089,23 @@ mext_check_arguments(struct inode *orig_inode, | |||
1050 | * @inode1: the inode structure | 1089 | * @inode1: the inode structure |
1051 | * @inode2: the inode structure | 1090 | * @inode2: the inode structure |
1052 | * | 1091 | * |
1053 | * Lock two inodes' i_mutex by i_ino order. This function is moved from | 1092 | * Lock two inodes' i_mutex by i_ino order. |
1054 | * fs/inode.c. | 1093 | * If inode1 or inode2 is NULL, return -EIO. Otherwise, return 0. |
1055 | */ | 1094 | */ |
1056 | static void | 1095 | static int |
1057 | mext_inode_double_lock(struct inode *inode1, struct inode *inode2) | 1096 | mext_inode_double_lock(struct inode *inode1, struct inode *inode2) |
1058 | { | 1097 | { |
1059 | if (inode1 == NULL || inode2 == NULL || inode1 == inode2) { | 1098 | int ret = 0; |
1060 | if (inode1) | 1099 | |
1061 | mutex_lock(&inode1->i_mutex); | 1100 | BUG_ON(inode1 == NULL && inode2 == NULL); |
1062 | else if (inode2) | 1101 | |
1063 | mutex_lock(&inode2->i_mutex); | 1102 | ret = mext_check_null_inode(inode1, inode2, __func__); |
1064 | return; | 1103 | if (ret < 0) |
1104 | goto out; | ||
1105 | |||
1106 | if (inode1 == inode2) { | ||
1107 | mutex_lock(&inode1->i_mutex); | ||
1108 | goto out; | ||
1065 | } | 1109 | } |
1066 | 1110 | ||
1067 | if (inode1->i_ino < inode2->i_ino) { | 1111 | if (inode1->i_ino < inode2->i_ino) { |
@@ -1071,6 +1115,9 @@ mext_inode_double_lock(struct inode *inode1, struct inode *inode2) | |||
1071 | mutex_lock_nested(&inode2->i_mutex, I_MUTEX_PARENT); | 1115 | mutex_lock_nested(&inode2->i_mutex, I_MUTEX_PARENT); |
1072 | mutex_lock_nested(&inode1->i_mutex, I_MUTEX_CHILD); | 1116 | mutex_lock_nested(&inode1->i_mutex, I_MUTEX_CHILD); |
1073 | } | 1117 | } |
1118 | |||
1119 | out: | ||
1120 | return ret; | ||
1074 | } | 1121 | } |
1075 | 1122 | ||
1076 | /** | 1123 | /** |
@@ -1079,17 +1126,28 @@ mext_inode_double_lock(struct inode *inode1, struct inode *inode2) | |||
1079 | * @inode1: the inode that is released first | 1126 | * @inode1: the inode that is released first |
1080 | * @inode2: the inode that is released second | 1127 | * @inode2: the inode that is released second |
1081 | * | 1128 | * |
1082 | * This function is moved from fs/inode.c. | 1129 | * If inode1 or inode2 is NULL, return -EIO. Otherwise, return 0. |
1083 | */ | 1130 | */ |
1084 | 1131 | ||
1085 | static void | 1132 | static int |
1086 | mext_inode_double_unlock(struct inode *inode1, struct inode *inode2) | 1133 | mext_inode_double_unlock(struct inode *inode1, struct inode *inode2) |
1087 | { | 1134 | { |
1135 | int ret = 0; | ||
1136 | |||
1137 | BUG_ON(inode1 == NULL && inode2 == NULL); | ||
1138 | |||
1139 | ret = mext_check_null_inode(inode1, inode2, __func__); | ||
1140 | if (ret < 0) | ||
1141 | goto out; | ||
1142 | |||
1088 | if (inode1) | 1143 | if (inode1) |
1089 | mutex_unlock(&inode1->i_mutex); | 1144 | mutex_unlock(&inode1->i_mutex); |
1090 | 1145 | ||
1091 | if (inode2 && inode2 != inode1) | 1146 | if (inode2 && inode2 != inode1) |
1092 | mutex_unlock(&inode2->i_mutex); | 1147 | mutex_unlock(&inode2->i_mutex); |
1148 | |||
1149 | out: | ||
1150 | return ret; | ||
1093 | } | 1151 | } |
1094 | 1152 | ||
1095 | /** | 1153 | /** |
@@ -1146,21 +1204,23 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, | |||
1146 | ext4_lblk_t block_end, seq_start, add_blocks, file_end, seq_blocks = 0; | 1204 | ext4_lblk_t block_end, seq_start, add_blocks, file_end, seq_blocks = 0; |
1147 | ext4_lblk_t rest_blocks; | 1205 | ext4_lblk_t rest_blocks; |
1148 | pgoff_t orig_page_offset = 0, seq_end_page; | 1206 | pgoff_t orig_page_offset = 0, seq_end_page; |
1149 | int ret, depth, last_extent = 0; | 1207 | int ret1, ret2, depth, last_extent = 0; |
1150 | int blocks_per_page = PAGE_CACHE_SIZE >> orig_inode->i_blkbits; | 1208 | int blocks_per_page = PAGE_CACHE_SIZE >> orig_inode->i_blkbits; |
1151 | int data_offset_in_page; | 1209 | int data_offset_in_page; |
1152 | int block_len_in_page; | 1210 | int block_len_in_page; |
1153 | int uninit; | 1211 | int uninit; |
1154 | 1212 | ||
1155 | /* protect orig and donor against a truncate */ | 1213 | /* protect orig and donor against a truncate */ |
1156 | mext_inode_double_lock(orig_inode, donor_inode); | 1214 | ret1 = mext_inode_double_lock(orig_inode, donor_inode); |
1215 | if (ret1 < 0) | ||
1216 | return ret1; | ||
1157 | 1217 | ||
1158 | mext_double_down_read(orig_inode, donor_inode); | 1218 | mext_double_down_read(orig_inode, donor_inode); |
1159 | /* Check the filesystem environment whether move_extent can be done */ | 1219 | /* Check the filesystem environment whether move_extent can be done */ |
1160 | ret = mext_check_arguments(orig_inode, donor_inode, orig_start, | 1220 | ret1 = mext_check_arguments(orig_inode, donor_inode, orig_start, |
1161 | donor_start, &len, *moved_len); | 1221 | donor_start, &len, *moved_len); |
1162 | mext_double_up_read(orig_inode, donor_inode); | 1222 | mext_double_up_read(orig_inode, donor_inode); |
1163 | if (ret) | 1223 | if (ret1) |
1164 | goto out2; | 1224 | goto out2; |
1165 | 1225 | ||
1166 | file_end = (i_size_read(orig_inode) - 1) >> orig_inode->i_blkbits; | 1226 | file_end = (i_size_read(orig_inode) - 1) >> orig_inode->i_blkbits; |
@@ -1168,19 +1228,19 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, | |||
1168 | if (file_end < block_end) | 1228 | if (file_end < block_end) |
1169 | len -= block_end - file_end; | 1229 | len -= block_end - file_end; |
1170 | 1230 | ||
1171 | ret = get_ext_path(orig_inode, block_start, &orig_path); | 1231 | ret1 = get_ext_path(orig_inode, block_start, &orig_path); |
1172 | if (orig_path == NULL) | 1232 | if (orig_path == NULL) |
1173 | goto out2; | 1233 | goto out2; |
1174 | 1234 | ||
1175 | /* Get path structure to check the hole */ | 1235 | /* Get path structure to check the hole */ |
1176 | ret = get_ext_path(orig_inode, block_start, &holecheck_path); | 1236 | ret1 = get_ext_path(orig_inode, block_start, &holecheck_path); |
1177 | if (holecheck_path == NULL) | 1237 | if (holecheck_path == NULL) |
1178 | goto out; | 1238 | goto out; |
1179 | 1239 | ||
1180 | depth = ext_depth(orig_inode); | 1240 | depth = ext_depth(orig_inode); |
1181 | ext_cur = holecheck_path[depth].p_ext; | 1241 | ext_cur = holecheck_path[depth].p_ext; |
1182 | if (ext_cur == NULL) { | 1242 | if (ext_cur == NULL) { |
1183 | ret = -EINVAL; | 1243 | ret1 = -EINVAL; |
1184 | goto out; | 1244 | goto out; |
1185 | } | 1245 | } |
1186 | 1246 | ||
@@ -1193,13 +1253,13 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, | |||
1193 | last_extent = mext_next_extent(orig_inode, | 1253 | last_extent = mext_next_extent(orig_inode, |
1194 | holecheck_path, &ext_cur); | 1254 | holecheck_path, &ext_cur); |
1195 | if (last_extent < 0) { | 1255 | if (last_extent < 0) { |
1196 | ret = last_extent; | 1256 | ret1 = last_extent; |
1197 | goto out; | 1257 | goto out; |
1198 | } | 1258 | } |
1199 | last_extent = mext_next_extent(orig_inode, orig_path, | 1259 | last_extent = mext_next_extent(orig_inode, orig_path, |
1200 | &ext_dummy); | 1260 | &ext_dummy); |
1201 | if (last_extent < 0) { | 1261 | if (last_extent < 0) { |
1202 | ret = last_extent; | 1262 | ret1 = last_extent; |
1203 | goto out; | 1263 | goto out; |
1204 | } | 1264 | } |
1205 | } | 1265 | } |
@@ -1209,7 +1269,7 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, | |||
1209 | if (le32_to_cpu(ext_cur->ee_block) > block_end) { | 1269 | if (le32_to_cpu(ext_cur->ee_block) > block_end) { |
1210 | ext4_debug("ext4 move extent: The specified range of file " | 1270 | ext4_debug("ext4 move extent: The specified range of file " |
1211 | "may be the hole\n"); | 1271 | "may be the hole\n"); |
1212 | ret = -EINVAL; | 1272 | ret1 = -EINVAL; |
1213 | goto out; | 1273 | goto out; |
1214 | } | 1274 | } |
1215 | 1275 | ||
@@ -1229,7 +1289,7 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, | |||
1229 | last_extent = mext_next_extent(orig_inode, holecheck_path, | 1289 | last_extent = mext_next_extent(orig_inode, holecheck_path, |
1230 | &ext_cur); | 1290 | &ext_cur); |
1231 | if (last_extent < 0) { | 1291 | if (last_extent < 0) { |
1232 | ret = last_extent; | 1292 | ret1 = last_extent; |
1233 | break; | 1293 | break; |
1234 | } | 1294 | } |
1235 | add_blocks = ext4_ext_get_actual_len(ext_cur); | 1295 | add_blocks = ext4_ext_get_actual_len(ext_cur); |
@@ -1281,16 +1341,23 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, | |||
1281 | while (orig_page_offset <= seq_end_page) { | 1341 | while (orig_page_offset <= seq_end_page) { |
1282 | 1342 | ||
1283 | /* Swap original branches with new branches */ | 1343 | /* Swap original branches with new branches */ |
1284 | ret = move_extent_per_page(o_filp, donor_inode, | 1344 | ret1 = move_extent_per_page(o_filp, donor_inode, |
1285 | orig_page_offset, | 1345 | orig_page_offset, |
1286 | data_offset_in_page, | 1346 | data_offset_in_page, |
1287 | block_len_in_page, uninit); | 1347 | block_len_in_page, uninit); |
1288 | if (ret < 0) | 1348 | if (ret1 < 0) |
1289 | goto out; | 1349 | goto out; |
1290 | orig_page_offset++; | 1350 | orig_page_offset++; |
1291 | /* Count how many blocks we have exchanged */ | 1351 | /* Count how many blocks we have exchanged */ |
1292 | *moved_len += block_len_in_page; | 1352 | *moved_len += block_len_in_page; |
1293 | BUG_ON(*moved_len > len); | 1353 | if (*moved_len > len) { |
1354 | ext4_error(orig_inode->i_sb, __func__, | ||
1355 | "We replaced blocks too much! " | ||
1356 | "sum of replaced: %llu requested: %llu", | ||
1357 | *moved_len, len); | ||
1358 | ret1 = -EIO; | ||
1359 | goto out; | ||
1360 | } | ||
1294 | 1361 | ||
1295 | data_offset_in_page = 0; | 1362 | data_offset_in_page = 0; |
1296 | rest_blocks -= block_len_in_page; | 1363 | rest_blocks -= block_len_in_page; |
@@ -1303,7 +1370,7 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, | |||
1303 | /* Decrease buffer counter */ | 1370 | /* Decrease buffer counter */ |
1304 | if (holecheck_path) | 1371 | if (holecheck_path) |
1305 | ext4_ext_drop_refs(holecheck_path); | 1372 | ext4_ext_drop_refs(holecheck_path); |
1306 | ret = get_ext_path(orig_inode, seq_start, &holecheck_path); | 1373 | ret1 = get_ext_path(orig_inode, seq_start, &holecheck_path); |
1307 | if (holecheck_path == NULL) | 1374 | if (holecheck_path == NULL) |
1308 | break; | 1375 | break; |
1309 | depth = holecheck_path->p_depth; | 1376 | depth = holecheck_path->p_depth; |
@@ -1311,7 +1378,7 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, | |||
1311 | /* Decrease buffer counter */ | 1378 | /* Decrease buffer counter */ |
1312 | if (orig_path) | 1379 | if (orig_path) |
1313 | ext4_ext_drop_refs(orig_path); | 1380 | ext4_ext_drop_refs(orig_path); |
1314 | ret = get_ext_path(orig_inode, seq_start, &orig_path); | 1381 | ret1 = get_ext_path(orig_inode, seq_start, &orig_path); |
1315 | if (orig_path == NULL) | 1382 | if (orig_path == NULL) |
1316 | break; | 1383 | break; |
1317 | 1384 | ||
@@ -1330,10 +1397,12 @@ out: | |||
1330 | kfree(holecheck_path); | 1397 | kfree(holecheck_path); |
1331 | } | 1398 | } |
1332 | out2: | 1399 | out2: |
1333 | mext_inode_double_unlock(orig_inode, donor_inode); | 1400 | ret2 = mext_inode_double_unlock(orig_inode, donor_inode); |
1334 | 1401 | ||
1335 | if (ret) | 1402 | if (ret1) |
1336 | return ret; | 1403 | return ret1; |
1404 | else if (ret2) | ||
1405 | return ret2; | ||
1337 | 1406 | ||
1338 | return 0; | 1407 | return 0; |
1339 | } | 1408 | } |