diff options
Diffstat (limited to 'fs/ext3/balloc.c')
-rw-r--r-- | fs/ext3/balloc.c | 109 |
1 files changed, 86 insertions, 23 deletions
diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c index 46623f77666b..77927d6938f6 100644 --- a/fs/ext3/balloc.c +++ b/fs/ext3/balloc.c | |||
@@ -653,9 +653,11 @@ claim_block(spinlock_t *lock, int block, struct buffer_head *bh) | |||
653 | */ | 653 | */ |
654 | static int | 654 | static int |
655 | ext3_try_to_allocate(struct super_block *sb, handle_t *handle, int group, | 655 | ext3_try_to_allocate(struct super_block *sb, handle_t *handle, int group, |
656 | struct buffer_head *bitmap_bh, int goal, struct ext3_reserve_window *my_rsv) | 656 | struct buffer_head *bitmap_bh, int goal, |
657 | unsigned long *count, struct ext3_reserve_window *my_rsv) | ||
657 | { | 658 | { |
658 | int group_first_block, start, end; | 659 | int group_first_block, start, end; |
660 | unsigned long num = 0; | ||
659 | 661 | ||
660 | /* we do allocation within the reservation window if we have a window */ | 662 | /* we do allocation within the reservation window if we have a window */ |
661 | if (my_rsv) { | 663 | if (my_rsv) { |
@@ -713,8 +715,18 @@ repeat: | |||
713 | goto fail_access; | 715 | goto fail_access; |
714 | goto repeat; | 716 | goto repeat; |
715 | } | 717 | } |
716 | return goal; | 718 | num++; |
719 | goal++; | ||
720 | while (num < *count && goal < end | ||
721 | && ext3_test_allocatable(goal, bitmap_bh) | ||
722 | && claim_block(sb_bgl_lock(EXT3_SB(sb), group), goal, bitmap_bh)) { | ||
723 | num++; | ||
724 | goal++; | ||
725 | } | ||
726 | *count = num; | ||
727 | return goal - num; | ||
717 | fail_access: | 728 | fail_access: |
729 | *count = num; | ||
718 | return -1; | 730 | return -1; |
719 | } | 731 | } |
720 | 732 | ||
@@ -999,6 +1011,31 @@ retry: | |||
999 | goto retry; | 1011 | goto retry; |
1000 | } | 1012 | } |
1001 | 1013 | ||
1014 | static void try_to_extend_reservation(struct ext3_reserve_window_node *my_rsv, | ||
1015 | struct super_block *sb, int size) | ||
1016 | { | ||
1017 | struct ext3_reserve_window_node *next_rsv; | ||
1018 | struct rb_node *next; | ||
1019 | spinlock_t *rsv_lock = &EXT3_SB(sb)->s_rsv_window_lock; | ||
1020 | |||
1021 | if (!spin_trylock(rsv_lock)) | ||
1022 | return; | ||
1023 | |||
1024 | next = rb_next(&my_rsv->rsv_node); | ||
1025 | |||
1026 | if (!next) | ||
1027 | my_rsv->rsv_end += size; | ||
1028 | else { | ||
1029 | next_rsv = list_entry(next, struct ext3_reserve_window_node, rsv_node); | ||
1030 | |||
1031 | if ((next_rsv->rsv_start - my_rsv->rsv_end - 1) >= size) | ||
1032 | my_rsv->rsv_end += size; | ||
1033 | else | ||
1034 | my_rsv->rsv_end = next_rsv->rsv_start - 1; | ||
1035 | } | ||
1036 | spin_unlock(rsv_lock); | ||
1037 | } | ||
1038 | |||
1002 | /* | 1039 | /* |
1003 | * This is the main function used to allocate a new block and its reservation | 1040 | * This is the main function used to allocate a new block and its reservation |
1004 | * window. | 1041 | * window. |
@@ -1024,11 +1061,12 @@ static int | |||
1024 | ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle, | 1061 | ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle, |
1025 | unsigned int group, struct buffer_head *bitmap_bh, | 1062 | unsigned int group, struct buffer_head *bitmap_bh, |
1026 | int goal, struct ext3_reserve_window_node * my_rsv, | 1063 | int goal, struct ext3_reserve_window_node * my_rsv, |
1027 | int *errp) | 1064 | unsigned long *count, int *errp) |
1028 | { | 1065 | { |
1029 | unsigned long group_first_block; | 1066 | unsigned long group_first_block; |
1030 | int ret = 0; | 1067 | int ret = 0; |
1031 | int fatal; | 1068 | int fatal; |
1069 | unsigned long num = *count; | ||
1032 | 1070 | ||
1033 | *errp = 0; | 1071 | *errp = 0; |
1034 | 1072 | ||
@@ -1051,7 +1089,8 @@ ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle, | |||
1051 | * or last attempt to allocate a block with reservation turned on failed | 1089 | * or last attempt to allocate a block with reservation turned on failed |
1052 | */ | 1090 | */ |
1053 | if (my_rsv == NULL ) { | 1091 | if (my_rsv == NULL ) { |
1054 | ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, goal, NULL); | 1092 | ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, |
1093 | goal, count, NULL); | ||
1055 | goto out; | 1094 | goto out; |
1056 | } | 1095 | } |
1057 | /* | 1096 | /* |
@@ -1081,6 +1120,8 @@ ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle, | |||
1081 | while (1) { | 1120 | while (1) { |
1082 | if (rsv_is_empty(&my_rsv->rsv_window) || (ret < 0) || | 1121 | if (rsv_is_empty(&my_rsv->rsv_window) || (ret < 0) || |
1083 | !goal_in_my_reservation(&my_rsv->rsv_window, goal, group, sb)) { | 1122 | !goal_in_my_reservation(&my_rsv->rsv_window, goal, group, sb)) { |
1123 | if (my_rsv->rsv_goal_size < *count) | ||
1124 | my_rsv->rsv_goal_size = *count; | ||
1084 | ret = alloc_new_reservation(my_rsv, goal, sb, | 1125 | ret = alloc_new_reservation(my_rsv, goal, sb, |
1085 | group, bitmap_bh); | 1126 | group, bitmap_bh); |
1086 | if (ret < 0) | 1127 | if (ret < 0) |
@@ -1088,16 +1129,21 @@ ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle, | |||
1088 | 1129 | ||
1089 | if (!goal_in_my_reservation(&my_rsv->rsv_window, goal, group, sb)) | 1130 | if (!goal_in_my_reservation(&my_rsv->rsv_window, goal, group, sb)) |
1090 | goal = -1; | 1131 | goal = -1; |
1091 | } | 1132 | } else if (goal > 0 && (my_rsv->rsv_end-goal+1) < *count) |
1133 | try_to_extend_reservation(my_rsv, sb, | ||
1134 | *count-my_rsv->rsv_end + goal - 1); | ||
1135 | |||
1092 | if ((my_rsv->rsv_start >= group_first_block + EXT3_BLOCKS_PER_GROUP(sb)) | 1136 | if ((my_rsv->rsv_start >= group_first_block + EXT3_BLOCKS_PER_GROUP(sb)) |
1093 | || (my_rsv->rsv_end < group_first_block)) | 1137 | || (my_rsv->rsv_end < group_first_block)) |
1094 | BUG(); | 1138 | BUG(); |
1095 | ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, goal, | 1139 | ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, goal, |
1096 | &my_rsv->rsv_window); | 1140 | &num, &my_rsv->rsv_window); |
1097 | if (ret >= 0) { | 1141 | if (ret >= 0) { |
1098 | my_rsv->rsv_alloc_hit++; | 1142 | my_rsv->rsv_alloc_hit += num; |
1143 | *count = num; | ||
1099 | break; /* succeed */ | 1144 | break; /* succeed */ |
1100 | } | 1145 | } |
1146 | num = *count; | ||
1101 | } | 1147 | } |
1102 | out: | 1148 | out: |
1103 | if (ret >= 0) { | 1149 | if (ret >= 0) { |
@@ -1154,8 +1200,8 @@ int ext3_should_retry_alloc(struct super_block *sb, int *retries) | |||
1154 | * bitmap, and then for any free bit if that fails. | 1200 | * bitmap, and then for any free bit if that fails. |
1155 | * This function also updates quota and i_blocks field. | 1201 | * This function also updates quota and i_blocks field. |
1156 | */ | 1202 | */ |
1157 | int ext3_new_block(handle_t *handle, struct inode *inode, | 1203 | int ext3_new_blocks(handle_t *handle, struct inode *inode, |
1158 | unsigned long goal, int *errp) | 1204 | unsigned long goal, unsigned long *count, int *errp) |
1159 | { | 1205 | { |
1160 | struct buffer_head *bitmap_bh = NULL; | 1206 | struct buffer_head *bitmap_bh = NULL; |
1161 | struct buffer_head *gdp_bh; | 1207 | struct buffer_head *gdp_bh; |
@@ -1178,6 +1224,7 @@ int ext3_new_block(handle_t *handle, struct inode *inode, | |||
1178 | static int goal_hits, goal_attempts; | 1224 | static int goal_hits, goal_attempts; |
1179 | #endif | 1225 | #endif |
1180 | unsigned long ngroups; | 1226 | unsigned long ngroups; |
1227 | unsigned long num = *count; | ||
1181 | 1228 | ||
1182 | *errp = -ENOSPC; | 1229 | *errp = -ENOSPC; |
1183 | sb = inode->i_sb; | 1230 | sb = inode->i_sb; |
@@ -1189,7 +1236,7 @@ int ext3_new_block(handle_t *handle, struct inode *inode, | |||
1189 | /* | 1236 | /* |
1190 | * Check quota for allocation of this block. | 1237 | * Check quota for allocation of this block. |
1191 | */ | 1238 | */ |
1192 | if (DQUOT_ALLOC_BLOCK(inode, 1)) { | 1239 | if (DQUOT_ALLOC_BLOCK(inode, num)) { |
1193 | *errp = -EDQUOT; | 1240 | *errp = -EDQUOT; |
1194 | return 0; | 1241 | return 0; |
1195 | } | 1242 | } |
@@ -1244,7 +1291,7 @@ retry: | |||
1244 | if (!bitmap_bh) | 1291 | if (!bitmap_bh) |
1245 | goto io_error; | 1292 | goto io_error; |
1246 | ret_block = ext3_try_to_allocate_with_rsv(sb, handle, group_no, | 1293 | ret_block = ext3_try_to_allocate_with_rsv(sb, handle, group_no, |
1247 | bitmap_bh, ret_block, my_rsv, &fatal); | 1294 | bitmap_bh, ret_block, my_rsv, &num, &fatal); |
1248 | if (fatal) | 1295 | if (fatal) |
1249 | goto out; | 1296 | goto out; |
1250 | if (ret_block >= 0) | 1297 | if (ret_block >= 0) |
@@ -1281,7 +1328,7 @@ retry: | |||
1281 | if (!bitmap_bh) | 1328 | if (!bitmap_bh) |
1282 | goto io_error; | 1329 | goto io_error; |
1283 | ret_block = ext3_try_to_allocate_with_rsv(sb, handle, group_no, | 1330 | ret_block = ext3_try_to_allocate_with_rsv(sb, handle, group_no, |
1284 | bitmap_bh, -1, my_rsv, &fatal); | 1331 | bitmap_bh, -1, my_rsv, &num, &fatal); |
1285 | if (fatal) | 1332 | if (fatal) |
1286 | goto out; | 1333 | goto out; |
1287 | if (ret_block >= 0) | 1334 | if (ret_block >= 0) |
@@ -1316,13 +1363,15 @@ allocated: | |||
1316 | target_block = ret_block + group_no * EXT3_BLOCKS_PER_GROUP(sb) | 1363 | target_block = ret_block + group_no * EXT3_BLOCKS_PER_GROUP(sb) |
1317 | + le32_to_cpu(es->s_first_data_block); | 1364 | + le32_to_cpu(es->s_first_data_block); |
1318 | 1365 | ||
1319 | if (target_block == le32_to_cpu(gdp->bg_block_bitmap) || | 1366 | if (in_range(le32_to_cpu(gdp->bg_block_bitmap), target_block, num) || |
1320 | target_block == le32_to_cpu(gdp->bg_inode_bitmap) || | 1367 | in_range(le32_to_cpu(gdp->bg_inode_bitmap), target_block, num) || |
1321 | in_range(target_block, le32_to_cpu(gdp->bg_inode_table), | 1368 | in_range(target_block, le32_to_cpu(gdp->bg_inode_table), |
1369 | EXT3_SB(sb)->s_itb_per_group) || | ||
1370 | in_range(target_block + num - 1, le32_to_cpu(gdp->bg_inode_table), | ||
1322 | EXT3_SB(sb)->s_itb_per_group)) | 1371 | EXT3_SB(sb)->s_itb_per_group)) |
1323 | ext3_error(sb, "ext3_new_block", | 1372 | ext3_error(sb, "ext3_new_block", |
1324 | "Allocating block in system zone - " | 1373 | "Allocating block in system zone - " |
1325 | "block = %u", target_block); | 1374 | "blocks from %u, length %lu", target_block, num); |
1326 | 1375 | ||
1327 | performed_allocation = 1; | 1376 | performed_allocation = 1; |
1328 | 1377 | ||
@@ -1341,10 +1390,14 @@ allocated: | |||
1341 | jbd_lock_bh_state(bitmap_bh); | 1390 | jbd_lock_bh_state(bitmap_bh); |
1342 | spin_lock(sb_bgl_lock(sbi, group_no)); | 1391 | spin_lock(sb_bgl_lock(sbi, group_no)); |
1343 | if (buffer_jbd(bitmap_bh) && bh2jh(bitmap_bh)->b_committed_data) { | 1392 | if (buffer_jbd(bitmap_bh) && bh2jh(bitmap_bh)->b_committed_data) { |
1344 | if (ext3_test_bit(ret_block, | 1393 | int i; |
1345 | bh2jh(bitmap_bh)->b_committed_data)) { | 1394 | |
1346 | printk("%s: block was unexpectedly set in " | 1395 | for (i = 0; i < num; i++) { |
1347 | "b_committed_data\n", __FUNCTION__); | 1396 | if (ext3_test_bit(ret_block, |
1397 | bh2jh(bitmap_bh)->b_committed_data)) { | ||
1398 | printk("%s: block was unexpectedly set in " | ||
1399 | "b_committed_data\n", __FUNCTION__); | ||
1400 | } | ||
1348 | } | 1401 | } |
1349 | } | 1402 | } |
1350 | ext3_debug("found bit %d\n", ret_block); | 1403 | ext3_debug("found bit %d\n", ret_block); |
@@ -1355,7 +1408,7 @@ allocated: | |||
1355 | /* ret_block was blockgroup-relative. Now it becomes fs-relative */ | 1408 | /* ret_block was blockgroup-relative. Now it becomes fs-relative */ |
1356 | ret_block = target_block; | 1409 | ret_block = target_block; |
1357 | 1410 | ||
1358 | if (ret_block >= le32_to_cpu(es->s_blocks_count)) { | 1411 | if (ret_block + num - 1 >= le32_to_cpu(es->s_blocks_count)) { |
1359 | ext3_error(sb, "ext3_new_block", | 1412 | ext3_error(sb, "ext3_new_block", |
1360 | "block(%d) >= blocks count(%d) - " | 1413 | "block(%d) >= blocks count(%d) - " |
1361 | "block_group = %d, es == %p ", ret_block, | 1414 | "block_group = %d, es == %p ", ret_block, |
@@ -1373,9 +1426,9 @@ allocated: | |||
1373 | 1426 | ||
1374 | spin_lock(sb_bgl_lock(sbi, group_no)); | 1427 | spin_lock(sb_bgl_lock(sbi, group_no)); |
1375 | gdp->bg_free_blocks_count = | 1428 | gdp->bg_free_blocks_count = |
1376 | cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) - 1); | 1429 | cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) - num); |
1377 | spin_unlock(sb_bgl_lock(sbi, group_no)); | 1430 | spin_unlock(sb_bgl_lock(sbi, group_no)); |
1378 | percpu_counter_mod(&sbi->s_freeblocks_counter, -1); | 1431 | percpu_counter_mod(&sbi->s_freeblocks_counter, -num); |
1379 | 1432 | ||
1380 | BUFFER_TRACE(gdp_bh, "journal_dirty_metadata for group descriptor"); | 1433 | BUFFER_TRACE(gdp_bh, "journal_dirty_metadata for group descriptor"); |
1381 | err = ext3_journal_dirty_metadata(handle, gdp_bh); | 1434 | err = ext3_journal_dirty_metadata(handle, gdp_bh); |
@@ -1388,6 +1441,8 @@ allocated: | |||
1388 | 1441 | ||
1389 | *errp = 0; | 1442 | *errp = 0; |
1390 | brelse(bitmap_bh); | 1443 | brelse(bitmap_bh); |
1444 | DQUOT_FREE_BLOCK(inode, *count-num); | ||
1445 | *count = num; | ||
1391 | return ret_block; | 1446 | return ret_block; |
1392 | 1447 | ||
1393 | io_error: | 1448 | io_error: |
@@ -1401,11 +1456,19 @@ out: | |||
1401 | * Undo the block allocation | 1456 | * Undo the block allocation |
1402 | */ | 1457 | */ |
1403 | if (!performed_allocation) | 1458 | if (!performed_allocation) |
1404 | DQUOT_FREE_BLOCK(inode, 1); | 1459 | DQUOT_FREE_BLOCK(inode, *count); |
1405 | brelse(bitmap_bh); | 1460 | brelse(bitmap_bh); |
1406 | return 0; | 1461 | return 0; |
1407 | } | 1462 | } |
1408 | 1463 | ||
1464 | int ext3_new_block(handle_t *handle, struct inode *inode, | ||
1465 | unsigned long goal, int *errp) | ||
1466 | { | ||
1467 | unsigned long count = 1; | ||
1468 | |||
1469 | return ext3_new_blocks(handle, inode, goal, &count, errp); | ||
1470 | } | ||
1471 | |||
1409 | unsigned long ext3_count_free_blocks(struct super_block *sb) | 1472 | unsigned long ext3_count_free_blocks(struct super_block *sb) |
1410 | { | 1473 | { |
1411 | unsigned long desc_count; | 1474 | unsigned long desc_count; |