diff options
-rw-r--r-- | fs/ext4/balloc.c | 14 | ||||
-rw-r--r-- | fs/ext4/ext4.h | 25 | ||||
-rw-r--r-- | fs/ext4/ext4_sb.h | 3 | ||||
-rw-r--r-- | fs/ext4/ialloc.c | 96 | ||||
-rw-r--r-- | fs/ext4/mballoc.c | 15 | ||||
-rw-r--r-- | fs/ext4/super.c | 57 |
6 files changed, 209 insertions, 1 deletions
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index ba411233cc25..0b2b7549ac63 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c | |||
@@ -809,6 +809,13 @@ do_more: | |||
809 | spin_unlock(sb_bgl_lock(sbi, block_group)); | 809 | spin_unlock(sb_bgl_lock(sbi, block_group)); |
810 | percpu_counter_add(&sbi->s_freeblocks_counter, count); | 810 | percpu_counter_add(&sbi->s_freeblocks_counter, count); |
811 | 811 | ||
812 | if (sbi->s_log_groups_per_flex) { | ||
813 | ext4_group_t flex_group = ext4_flex_group(sbi, block_group); | ||
814 | spin_lock(sb_bgl_lock(sbi, flex_group)); | ||
815 | sbi->s_flex_groups[flex_group].free_blocks += count; | ||
816 | spin_unlock(sb_bgl_lock(sbi, flex_group)); | ||
817 | } | ||
818 | |||
812 | /* We dirtied the bitmap block */ | 819 | /* We dirtied the bitmap block */ |
813 | BUFFER_TRACE(bitmap_bh, "dirtied bitmap block"); | 820 | BUFFER_TRACE(bitmap_bh, "dirtied bitmap block"); |
814 | err = ext4_journal_dirty_metadata(handle, bitmap_bh); | 821 | err = ext4_journal_dirty_metadata(handle, bitmap_bh); |
@@ -1883,6 +1890,13 @@ allocated: | |||
1883 | spin_unlock(sb_bgl_lock(sbi, group_no)); | 1890 | spin_unlock(sb_bgl_lock(sbi, group_no)); |
1884 | percpu_counter_sub(&sbi->s_freeblocks_counter, num); | 1891 | percpu_counter_sub(&sbi->s_freeblocks_counter, num); |
1885 | 1892 | ||
1893 | if (sbi->s_log_groups_per_flex) { | ||
1894 | ext4_group_t flex_group = ext4_flex_group(sbi, group_no); | ||
1895 | spin_lock(sb_bgl_lock(sbi, flex_group)); | ||
1896 | sbi->s_flex_groups[flex_group].free_blocks -= num; | ||
1897 | spin_unlock(sb_bgl_lock(sbi, flex_group)); | ||
1898 | } | ||
1899 | |||
1886 | BUFFER_TRACE(gdp_bh, "journal_dirty_metadata for group descriptor"); | 1900 | BUFFER_TRACE(gdp_bh, "journal_dirty_metadata for group descriptor"); |
1887 | err = ext4_journal_dirty_metadata(handle, gdp_bh); | 1901 | err = ext4_journal_dirty_metadata(handle, gdp_bh); |
1888 | if (!fatal) | 1902 | if (!fatal) |
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 109c7d4c19ad..0bfeae18f1a2 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -170,6 +170,15 @@ struct ext4_group_desc | |||
170 | __u32 bg_reserved2[3]; | 170 | __u32 bg_reserved2[3]; |
171 | }; | 171 | }; |
172 | 172 | ||
173 | /* | ||
174 | * Structure of a flex block group info | ||
175 | */ | ||
176 | |||
177 | struct flex_groups { | ||
178 | __u32 free_inodes; | ||
179 | __u32 free_blocks; | ||
180 | }; | ||
181 | |||
173 | #define EXT4_BG_INODE_UNINIT 0x0001 /* Inode table/bitmap not in use */ | 182 | #define EXT4_BG_INODE_UNINIT 0x0001 /* Inode table/bitmap not in use */ |
174 | #define EXT4_BG_BLOCK_UNINIT 0x0002 /* Block bitmap not in use */ | 183 | #define EXT4_BG_BLOCK_UNINIT 0x0002 /* Block bitmap not in use */ |
175 | #define EXT4_BG_INODE_ZEROED 0x0004 /* On-disk itable initialized to zero */ | 184 | #define EXT4_BG_INODE_ZEROED 0x0004 /* On-disk itable initialized to zero */ |
@@ -647,7 +656,10 @@ struct ext4_super_block { | |||
647 | __le16 s_mmp_interval; /* # seconds to wait in MMP checking */ | 656 | __le16 s_mmp_interval; /* # seconds to wait in MMP checking */ |
648 | __le64 s_mmp_block; /* Block for multi-mount protection */ | 657 | __le64 s_mmp_block; /* Block for multi-mount protection */ |
649 | __le32 s_raid_stripe_width; /* blocks on all data disks (N*stride)*/ | 658 | __le32 s_raid_stripe_width; /* blocks on all data disks (N*stride)*/ |
650 | __u32 s_reserved[163]; /* Padding to the end of the block */ | 659 | __u8 s_log_groups_per_flex; /* FLEX_BG group size */ |
660 | __u8 s_reserved_char_pad2; | ||
661 | __le16 s_reserved_pad; | ||
662 | __u32 s_reserved[162]; /* Padding to the end of the block */ | ||
651 | }; | 663 | }; |
652 | 664 | ||
653 | #ifdef __KERNEL__ | 665 | #ifdef __KERNEL__ |
@@ -1160,6 +1172,17 @@ struct ext4_group_info *ext4_get_group_info(struct super_block *sb, | |||
1160 | } | 1172 | } |
1161 | 1173 | ||
1162 | 1174 | ||
1175 | static inline ext4_group_t ext4_flex_group(struct ext4_sb_info *sbi, | ||
1176 | ext4_group_t block_group) | ||
1177 | { | ||
1178 | return block_group >> sbi->s_log_groups_per_flex; | ||
1179 | } | ||
1180 | |||
1181 | static inline unsigned int ext4_flex_bg_size(struct ext4_sb_info *sbi) | ||
1182 | { | ||
1183 | return 1 << sbi->s_log_groups_per_flex; | ||
1184 | } | ||
1185 | |||
1163 | #define ext4_std_error(sb, errno) \ | 1186 | #define ext4_std_error(sb, errno) \ |
1164 | do { \ | 1187 | do { \ |
1165 | if ((errno)) \ | 1188 | if ((errno)) \ |
diff --git a/fs/ext4/ext4_sb.h b/fs/ext4/ext4_sb.h index 4de9a75ca6af..6300226d5531 100644 --- a/fs/ext4/ext4_sb.h +++ b/fs/ext4/ext4_sb.h | |||
@@ -143,6 +143,9 @@ struct ext4_sb_info { | |||
143 | 143 | ||
144 | /* locality groups */ | 144 | /* locality groups */ |
145 | struct ext4_locality_group *s_locality_groups; | 145 | struct ext4_locality_group *s_locality_groups; |
146 | |||
147 | unsigned int s_log_groups_per_flex; | ||
148 | struct flex_groups *s_flex_groups; | ||
146 | }; | 149 | }; |
147 | 150 | ||
148 | #endif /* _EXT4_SB */ | 151 | #endif /* _EXT4_SB */ |
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index b30cc79b9fcb..8b0a10acd708 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c | |||
@@ -157,6 +157,7 @@ void ext4_free_inode (handle_t *handle, struct inode * inode) | |||
157 | struct ext4_super_block * es; | 157 | struct ext4_super_block * es; |
158 | struct ext4_sb_info *sbi; | 158 | struct ext4_sb_info *sbi; |
159 | int fatal = 0, err; | 159 | int fatal = 0, err; |
160 | ext4_group_t flex_group; | ||
160 | 161 | ||
161 | if (atomic_read(&inode->i_count) > 1) { | 162 | if (atomic_read(&inode->i_count) > 1) { |
162 | printk ("ext4_free_inode: inode has count=%d\n", | 163 | printk ("ext4_free_inode: inode has count=%d\n", |
@@ -232,6 +233,12 @@ void ext4_free_inode (handle_t *handle, struct inode * inode) | |||
232 | if (is_directory) | 233 | if (is_directory) |
233 | percpu_counter_dec(&sbi->s_dirs_counter); | 234 | percpu_counter_dec(&sbi->s_dirs_counter); |
234 | 235 | ||
236 | if (sbi->s_log_groups_per_flex) { | ||
237 | flex_group = ext4_flex_group(sbi, block_group); | ||
238 | spin_lock(sb_bgl_lock(sbi, flex_group)); | ||
239 | sbi->s_flex_groups[flex_group].free_inodes++; | ||
240 | spin_unlock(sb_bgl_lock(sbi, flex_group)); | ||
241 | } | ||
235 | } | 242 | } |
236 | BUFFER_TRACE(bh2, "call ext4_journal_dirty_metadata"); | 243 | BUFFER_TRACE(bh2, "call ext4_journal_dirty_metadata"); |
237 | err = ext4_journal_dirty_metadata(handle, bh2); | 244 | err = ext4_journal_dirty_metadata(handle, bh2); |
@@ -286,6 +293,80 @@ static int find_group_dir(struct super_block *sb, struct inode *parent, | |||
286 | return ret; | 293 | return ret; |
287 | } | 294 | } |
288 | 295 | ||
296 | #define free_block_ratio 10 | ||
297 | |||
298 | static int find_group_flex(struct super_block *sb, struct inode *parent, | ||
299 | ext4_group_t *best_group) | ||
300 | { | ||
301 | struct ext4_sb_info *sbi = EXT4_SB(sb); | ||
302 | struct ext4_group_desc *desc; | ||
303 | struct buffer_head *bh; | ||
304 | struct flex_groups *flex_group = sbi->s_flex_groups; | ||
305 | ext4_group_t parent_group = EXT4_I(parent)->i_block_group; | ||
306 | ext4_group_t parent_fbg_group = ext4_flex_group(sbi, parent_group); | ||
307 | ext4_group_t ngroups = sbi->s_groups_count; | ||
308 | int flex_size = ext4_flex_bg_size(sbi); | ||
309 | ext4_group_t best_flex = parent_fbg_group; | ||
310 | int blocks_per_flex = sbi->s_blocks_per_group * flex_size; | ||
311 | int flexbg_free_blocks; | ||
312 | int flex_freeb_ratio; | ||
313 | ext4_group_t n_fbg_groups; | ||
314 | ext4_group_t i; | ||
315 | |||
316 | n_fbg_groups = (sbi->s_groups_count + flex_size - 1) >> | ||
317 | sbi->s_log_groups_per_flex; | ||
318 | |||
319 | find_close_to_parent: | ||
320 | flexbg_free_blocks = flex_group[best_flex].free_blocks; | ||
321 | flex_freeb_ratio = flexbg_free_blocks * 100 / blocks_per_flex; | ||
322 | if (flex_group[best_flex].free_inodes && | ||
323 | flex_freeb_ratio > free_block_ratio) | ||
324 | goto found_flexbg; | ||
325 | |||
326 | if (best_flex && best_flex == parent_fbg_group) { | ||
327 | best_flex--; | ||
328 | goto find_close_to_parent; | ||
329 | } | ||
330 | |||
331 | for (i = 0; i < n_fbg_groups; i++) { | ||
332 | if (i == parent_fbg_group || i == parent_fbg_group - 1) | ||
333 | continue; | ||
334 | |||
335 | flexbg_free_blocks = flex_group[i].free_blocks; | ||
336 | flex_freeb_ratio = flexbg_free_blocks * 100 / blocks_per_flex; | ||
337 | |||
338 | if (flex_freeb_ratio > free_block_ratio && | ||
339 | flex_group[i].free_inodes) { | ||
340 | best_flex = i; | ||
341 | goto found_flexbg; | ||
342 | } | ||
343 | |||
344 | if (best_flex < 0 || | ||
345 | (flex_group[i].free_blocks > | ||
346 | flex_group[best_flex].free_blocks && | ||
347 | flex_group[i].free_inodes)) | ||
348 | best_flex = i; | ||
349 | } | ||
350 | |||
351 | if (!flex_group[best_flex].free_inodes || | ||
352 | !flex_group[best_flex].free_blocks) | ||
353 | return -1; | ||
354 | |||
355 | found_flexbg: | ||
356 | for (i = best_flex * flex_size; i < ngroups && | ||
357 | i < (best_flex + 1) * flex_size; i++) { | ||
358 | desc = ext4_get_group_desc(sb, i, &bh); | ||
359 | if (le16_to_cpu(desc->bg_free_inodes_count)) { | ||
360 | *best_group = i; | ||
361 | goto out; | ||
362 | } | ||
363 | } | ||
364 | |||
365 | return -1; | ||
366 | out: | ||
367 | return 0; | ||
368 | } | ||
369 | |||
289 | /* | 370 | /* |
290 | * Orlov's allocator for directories. | 371 | * Orlov's allocator for directories. |
291 | * | 372 | * |
@@ -501,6 +582,7 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode * dir, int mode) | |||
501 | struct inode *ret; | 582 | struct inode *ret; |
502 | ext4_group_t i; | 583 | ext4_group_t i; |
503 | int free = 0; | 584 | int free = 0; |
585 | ext4_group_t flex_group; | ||
504 | 586 | ||
505 | /* Cannot create files in a deleted directory */ | 587 | /* Cannot create files in a deleted directory */ |
506 | if (!dir || !dir->i_nlink) | 588 | if (!dir || !dir->i_nlink) |
@@ -514,6 +596,12 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode * dir, int mode) | |||
514 | 596 | ||
515 | sbi = EXT4_SB(sb); | 597 | sbi = EXT4_SB(sb); |
516 | es = sbi->s_es; | 598 | es = sbi->s_es; |
599 | |||
600 | if (sbi->s_log_groups_per_flex) { | ||
601 | ret2 = find_group_flex(sb, dir, &group); | ||
602 | goto got_group; | ||
603 | } | ||
604 | |||
517 | if (S_ISDIR(mode)) { | 605 | if (S_ISDIR(mode)) { |
518 | if (test_opt (sb, OLDALLOC)) | 606 | if (test_opt (sb, OLDALLOC)) |
519 | ret2 = find_group_dir(sb, dir, &group); | 607 | ret2 = find_group_dir(sb, dir, &group); |
@@ -522,6 +610,7 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode * dir, int mode) | |||
522 | } else | 610 | } else |
523 | ret2 = find_group_other(sb, dir, &group); | 611 | ret2 = find_group_other(sb, dir, &group); |
524 | 612 | ||
613 | got_group: | ||
525 | err = -ENOSPC; | 614 | err = -ENOSPC; |
526 | if (ret2 == -1) | 615 | if (ret2 == -1) |
527 | goto out; | 616 | goto out; |
@@ -676,6 +765,13 @@ got: | |||
676 | percpu_counter_inc(&sbi->s_dirs_counter); | 765 | percpu_counter_inc(&sbi->s_dirs_counter); |
677 | sb->s_dirt = 1; | 766 | sb->s_dirt = 1; |
678 | 767 | ||
768 | if (sbi->s_log_groups_per_flex) { | ||
769 | flex_group = ext4_flex_group(sbi, group); | ||
770 | spin_lock(sb_bgl_lock(sbi, flex_group)); | ||
771 | sbi->s_flex_groups[flex_group].free_inodes--; | ||
772 | spin_unlock(sb_bgl_lock(sbi, flex_group)); | ||
773 | } | ||
774 | |||
679 | inode->i_uid = current->fsuid; | 775 | inode->i_uid = current->fsuid; |
680 | if (test_opt (sb, GRPID)) | 776 | if (test_opt (sb, GRPID)) |
681 | inode->i_gid = dir->i_gid; | 777 | inode->i_gid = dir->i_gid; |
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index b882868f4661..5dcb826401bb 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c | |||
@@ -2842,6 +2842,14 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac, | |||
2842 | spin_unlock(sb_bgl_lock(sbi, ac->ac_b_ex.fe_group)); | 2842 | spin_unlock(sb_bgl_lock(sbi, ac->ac_b_ex.fe_group)); |
2843 | percpu_counter_sub(&sbi->s_freeblocks_counter, ac->ac_b_ex.fe_len); | 2843 | percpu_counter_sub(&sbi->s_freeblocks_counter, ac->ac_b_ex.fe_len); |
2844 | 2844 | ||
2845 | if (sbi->s_log_groups_per_flex) { | ||
2846 | ext4_group_t flex_group = ext4_flex_group(sbi, | ||
2847 | ac->ac_b_ex.fe_group); | ||
2848 | spin_lock(sb_bgl_lock(sbi, flex_group)); | ||
2849 | sbi->s_flex_groups[flex_group].free_blocks -= ac->ac_b_ex.fe_len; | ||
2850 | spin_unlock(sb_bgl_lock(sbi, flex_group)); | ||
2851 | } | ||
2852 | |||
2845 | err = ext4_journal_dirty_metadata(handle, bitmap_bh); | 2853 | err = ext4_journal_dirty_metadata(handle, bitmap_bh); |
2846 | if (err) | 2854 | if (err) |
2847 | goto out_err; | 2855 | goto out_err; |
@@ -4342,6 +4350,13 @@ do_more: | |||
4342 | spin_unlock(sb_bgl_lock(sbi, block_group)); | 4350 | spin_unlock(sb_bgl_lock(sbi, block_group)); |
4343 | percpu_counter_add(&sbi->s_freeblocks_counter, count); | 4351 | percpu_counter_add(&sbi->s_freeblocks_counter, count); |
4344 | 4352 | ||
4353 | if (sbi->s_log_groups_per_flex) { | ||
4354 | ext4_group_t flex_group = ext4_flex_group(sbi, block_group); | ||
4355 | spin_lock(sb_bgl_lock(sbi, flex_group)); | ||
4356 | sbi->s_flex_groups[flex_group].free_blocks += count; | ||
4357 | spin_unlock(sb_bgl_lock(sbi, flex_group)); | ||
4358 | } | ||
4359 | |||
4345 | ext4_mb_release_desc(&e4b); | 4360 | ext4_mb_release_desc(&e4b); |
4346 | 4361 | ||
4347 | *freed += count; | 4362 | *freed += count; |
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 588cfb408642..b9ad3d852061 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
@@ -517,6 +517,7 @@ static void ext4_put_super (struct super_block * sb) | |||
517 | for (i = 0; i < sbi->s_gdb_count; i++) | 517 | for (i = 0; i < sbi->s_gdb_count; i++) |
518 | brelse(sbi->s_group_desc[i]); | 518 | brelse(sbi->s_group_desc[i]); |
519 | kfree(sbi->s_group_desc); | 519 | kfree(sbi->s_group_desc); |
520 | kfree(sbi->s_flex_groups); | ||
520 | percpu_counter_destroy(&sbi->s_freeblocks_counter); | 521 | percpu_counter_destroy(&sbi->s_freeblocks_counter); |
521 | percpu_counter_destroy(&sbi->s_freeinodes_counter); | 522 | percpu_counter_destroy(&sbi->s_freeinodes_counter); |
522 | percpu_counter_destroy(&sbi->s_dirs_counter); | 523 | percpu_counter_destroy(&sbi->s_dirs_counter); |
@@ -1442,6 +1443,54 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es, | |||
1442 | return res; | 1443 | return res; |
1443 | } | 1444 | } |
1444 | 1445 | ||
1446 | static int ext4_fill_flex_info(struct super_block *sb) | ||
1447 | { | ||
1448 | struct ext4_sb_info *sbi = EXT4_SB(sb); | ||
1449 | struct ext4_group_desc *gdp = NULL; | ||
1450 | struct buffer_head *bh; | ||
1451 | ext4_group_t flex_group_count; | ||
1452 | ext4_group_t flex_group; | ||
1453 | int groups_per_flex = 0; | ||
1454 | __u64 block_bitmap = 0; | ||
1455 | int i; | ||
1456 | |||
1457 | if (!sbi->s_es->s_log_groups_per_flex) { | ||
1458 | sbi->s_log_groups_per_flex = 0; | ||
1459 | return 1; | ||
1460 | } | ||
1461 | |||
1462 | sbi->s_log_groups_per_flex = sbi->s_es->s_log_groups_per_flex; | ||
1463 | groups_per_flex = 1 << sbi->s_log_groups_per_flex; | ||
1464 | |||
1465 | flex_group_count = (sbi->s_groups_count + groups_per_flex - 1) / | ||
1466 | groups_per_flex; | ||
1467 | sbi->s_flex_groups = kmalloc(flex_group_count * | ||
1468 | sizeof(struct flex_groups), GFP_KERNEL); | ||
1469 | if (sbi->s_flex_groups == NULL) { | ||
1470 | printk(KERN_ERR "EXT4-fs: not enough memory\n"); | ||
1471 | goto failed; | ||
1472 | } | ||
1473 | memset(sbi->s_flex_groups, 0, flex_group_count * | ||
1474 | sizeof(struct flex_groups)); | ||
1475 | |||
1476 | gdp = ext4_get_group_desc(sb, 1, &bh); | ||
1477 | block_bitmap = ext4_block_bitmap(sb, gdp) - 1; | ||
1478 | |||
1479 | for (i = 0; i < sbi->s_groups_count; i++) { | ||
1480 | gdp = ext4_get_group_desc(sb, i, &bh); | ||
1481 | |||
1482 | flex_group = ext4_flex_group(sbi, i); | ||
1483 | sbi->s_flex_groups[flex_group].free_inodes += | ||
1484 | le16_to_cpu(gdp->bg_free_inodes_count); | ||
1485 | sbi->s_flex_groups[flex_group].free_blocks += | ||
1486 | le16_to_cpu(gdp->bg_free_blocks_count); | ||
1487 | } | ||
1488 | |||
1489 | return 1; | ||
1490 | failed: | ||
1491 | return 0; | ||
1492 | } | ||
1493 | |||
1445 | __le16 ext4_group_desc_csum(struct ext4_sb_info *sbi, __u32 block_group, | 1494 | __le16 ext4_group_desc_csum(struct ext4_sb_info *sbi, __u32 block_group, |
1446 | struct ext4_group_desc *gdp) | 1495 | struct ext4_group_desc *gdp) |
1447 | { | 1496 | { |
@@ -2137,6 +2186,14 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) | |||
2137 | printk(KERN_ERR "EXT4-fs: group descriptors corrupted!\n"); | 2186 | printk(KERN_ERR "EXT4-fs: group descriptors corrupted!\n"); |
2138 | goto failed_mount2; | 2187 | goto failed_mount2; |
2139 | } | 2188 | } |
2189 | if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG)) | ||
2190 | if (!ext4_fill_flex_info(sb)) { | ||
2191 | printk(KERN_ERR | ||
2192 | "EXT4-fs: unable to initialize " | ||
2193 | "flex_bg meta info!\n"); | ||
2194 | goto failed_mount2; | ||
2195 | } | ||
2196 | |||
2140 | sbi->s_gdb_count = db_count; | 2197 | sbi->s_gdb_count = db_count; |
2141 | get_random_bytes(&sbi->s_next_generation, sizeof(u32)); | 2198 | get_random_bytes(&sbi->s_next_generation, sizeof(u32)); |
2142 | spin_lock_init(&sbi->s_next_gen_lock); | 2199 | spin_lock_init(&sbi->s_next_gen_lock); |