diff options
Diffstat (limited to 'fs/ext4/ialloc.c')
| -rw-r--r-- | fs/ext4/ialloc.c | 113 |
1 files changed, 107 insertions, 6 deletions
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index c6efbab0c801..a92eb305344f 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; |
| @@ -600,7 +689,7 @@ got: | |||
| 600 | /* We may have to initialize the block bitmap if it isn't already */ | 689 | /* We may have to initialize the block bitmap if it isn't already */ |
| 601 | if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM) && | 690 | if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM) && |
| 602 | gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { | 691 | gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { |
| 603 | struct buffer_head *block_bh = read_block_bitmap(sb, group); | 692 | struct buffer_head *block_bh = ext4_read_block_bitmap(sb, group); |
| 604 | 693 | ||
| 605 | BUFFER_TRACE(block_bh, "get block bitmap access"); | 694 | BUFFER_TRACE(block_bh, "get block bitmap access"); |
| 606 | err = ext4_journal_get_write_access(handle, block_bh); | 695 | err = ext4_journal_get_write_access(handle, block_bh); |
| @@ -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; |
| @@ -740,14 +836,10 @@ got: | |||
| 740 | goto fail_free_drop; | 836 | goto fail_free_drop; |
| 741 | 837 | ||
| 742 | if (test_opt(sb, EXTENTS)) { | 838 | if (test_opt(sb, EXTENTS)) { |
| 743 | /* set extent flag only for diretory, file and normal symlink*/ | 839 | /* set extent flag only for directory, file and normal symlink*/ |
| 744 | if (S_ISDIR(mode) || S_ISREG(mode) || S_ISLNK(mode)) { | 840 | if (S_ISDIR(mode) || S_ISREG(mode) || S_ISLNK(mode)) { |
| 745 | EXT4_I(inode)->i_flags |= EXT4_EXTENTS_FL; | 841 | EXT4_I(inode)->i_flags |= EXT4_EXTENTS_FL; |
| 746 | ext4_ext_tree_init(handle, inode); | 842 | ext4_ext_tree_init(handle, inode); |
| 747 | err = ext4_update_incompat_feature(handle, sb, | ||
| 748 | EXT4_FEATURE_INCOMPAT_EXTENTS); | ||
| 749 | if (err) | ||
| 750 | goto fail_free_drop; | ||
| 751 | } | 843 | } |
| 752 | } | 844 | } |
| 753 | 845 | ||
| @@ -817,6 +909,14 @@ struct inode *ext4_orphan_get(struct super_block *sb, unsigned long ino) | |||
| 817 | if (IS_ERR(inode)) | 909 | if (IS_ERR(inode)) |
| 818 | goto iget_failed; | 910 | goto iget_failed; |
| 819 | 911 | ||
| 912 | /* | ||
| 913 | * If the orphans has i_nlinks > 0 then it should be able to be | ||
| 914 | * truncated, otherwise it won't be removed from the orphan list | ||
| 915 | * during processing and an infinite loop will result. | ||
| 916 | */ | ||
| 917 | if (inode->i_nlink && !ext4_can_truncate(inode)) | ||
| 918 | goto bad_orphan; | ||
| 919 | |||
| 820 | if (NEXT_ORPHAN(inode) > max_ino) | 920 | if (NEXT_ORPHAN(inode) > max_ino) |
| 821 | goto bad_orphan; | 921 | goto bad_orphan; |
| 822 | brelse(bitmap_bh); | 922 | brelse(bitmap_bh); |
| @@ -838,6 +938,7 @@ bad_orphan: | |||
| 838 | printk(KERN_NOTICE "NEXT_ORPHAN(inode)=%u\n", | 938 | printk(KERN_NOTICE "NEXT_ORPHAN(inode)=%u\n", |
| 839 | NEXT_ORPHAN(inode)); | 939 | NEXT_ORPHAN(inode)); |
| 840 | printk(KERN_NOTICE "max_ino=%lu\n", max_ino); | 940 | printk(KERN_NOTICE "max_ino=%lu\n", max_ino); |
| 941 | printk(KERN_NOTICE "i_nlink=%u\n", inode->i_nlink); | ||
| 841 | /* Avoid freeing blocks if we got a bad deleted inode */ | 942 | /* Avoid freeing blocks if we got a bad deleted inode */ |
| 842 | if (inode->i_nlink == 0) | 943 | if (inode->i_nlink == 0) |
| 843 | inode->i_blocks = 0; | 944 | inode->i_blocks = 0; |
