diff options
Diffstat (limited to 'fs/ext4')
-rw-r--r-- | fs/ext4/balloc.c | 77 | ||||
-rw-r--r-- | fs/ext4/ext4.h | 3 | ||||
-rw-r--r-- | fs/ext4/ialloc.c | 2 | ||||
-rw-r--r-- | fs/ext4/inode.c | 7 | ||||
-rw-r--r-- | fs/ext4/mballoc.c | 1 | ||||
-rw-r--r-- | fs/ext4/super.c | 35 |
6 files changed, 53 insertions, 72 deletions
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index b9821be709bd..d2003cdc36aa 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c | |||
@@ -589,21 +589,23 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode, | |||
589 | return; | 589 | return; |
590 | } | 590 | } |
591 | 591 | ||
592 | int ext4_claim_free_blocks(struct ext4_sb_info *sbi, | 592 | /** |
593 | s64 nblocks) | 593 | * ext4_has_free_blocks() |
594 | * @sbi: in-core super block structure. | ||
595 | * @nblocks: number of needed blocks | ||
596 | * | ||
597 | * Check if filesystem has nblocks free & available for allocation. | ||
598 | * On success return 1, return 0 on failure. | ||
599 | */ | ||
600 | int ext4_has_free_blocks(struct ext4_sb_info *sbi, s64 nblocks) | ||
594 | { | 601 | { |
595 | s64 free_blocks, dirty_blocks; | 602 | s64 free_blocks, dirty_blocks, root_blocks; |
596 | s64 root_blocks = 0; | ||
597 | struct percpu_counter *fbc = &sbi->s_freeblocks_counter; | 603 | struct percpu_counter *fbc = &sbi->s_freeblocks_counter; |
598 | struct percpu_counter *dbc = &sbi->s_dirtyblocks_counter; | 604 | struct percpu_counter *dbc = &sbi->s_dirtyblocks_counter; |
599 | 605 | ||
600 | free_blocks = percpu_counter_read_positive(fbc); | 606 | free_blocks = percpu_counter_read_positive(fbc); |
601 | dirty_blocks = percpu_counter_read_positive(dbc); | 607 | dirty_blocks = percpu_counter_read_positive(dbc); |
602 | 608 | root_blocks = ext4_r_blocks_count(sbi->s_es); | |
603 | if (!capable(CAP_SYS_RESOURCE) && | ||
604 | sbi->s_resuid != current->fsuid && | ||
605 | (sbi->s_resgid == 0 || !in_group_p(sbi->s_resgid))) | ||
606 | root_blocks = ext4_r_blocks_count(sbi->s_es); | ||
607 | 609 | ||
608 | if (free_blocks - (nblocks + root_blocks + dirty_blocks) < | 610 | if (free_blocks - (nblocks + root_blocks + dirty_blocks) < |
609 | EXT4_FREEBLOCKS_WATERMARK) { | 611 | EXT4_FREEBLOCKS_WATERMARK) { |
@@ -616,57 +618,32 @@ int ext4_claim_free_blocks(struct ext4_sb_info *sbi, | |||
616 | } | 618 | } |
617 | } | 619 | } |
618 | /* Check whether we have space after | 620 | /* Check whether we have space after |
619 | * accounting for current dirty blocks | 621 | * accounting for current dirty blocks & root reserved blocks. |
620 | */ | 622 | */ |
621 | if (free_blocks < ((root_blocks + nblocks) + dirty_blocks)) | 623 | if (free_blocks >= ((root_blocks + nblocks) + dirty_blocks)) |
622 | /* we don't have free space */ | 624 | return 1; |
623 | return -ENOSPC; | 625 | |
626 | /* Hm, nope. Are (enough) root reserved blocks available? */ | ||
627 | if (sbi->s_resuid == current->fsuid || | ||
628 | ((sbi->s_resgid != 0) && in_group_p(sbi->s_resgid)) || | ||
629 | capable(CAP_SYS_RESOURCE)) { | ||
630 | if (free_blocks >= (nblocks + dirty_blocks)) | ||
631 | return 1; | ||
632 | } | ||
624 | 633 | ||
625 | /* Add the blocks to nblocks */ | ||
626 | percpu_counter_add(dbc, nblocks); | ||
627 | return 0; | 634 | return 0; |
628 | } | 635 | } |
629 | 636 | ||
630 | /** | 637 | int ext4_claim_free_blocks(struct ext4_sb_info *sbi, |
631 | * ext4_has_free_blocks() | ||
632 | * @sbi: in-core super block structure. | ||
633 | * @nblocks: number of neeed blocks | ||
634 | * | ||
635 | * Check if filesystem has free blocks available for allocation. | ||
636 | * Return the number of blocks avaible for allocation for this request | ||
637 | * On success, return nblocks | ||
638 | */ | ||
639 | ext4_fsblk_t ext4_has_free_blocks(struct ext4_sb_info *sbi, | ||
640 | s64 nblocks) | 638 | s64 nblocks) |
641 | { | 639 | { |
642 | s64 free_blocks, dirty_blocks; | 640 | if (ext4_has_free_blocks(sbi, nblocks)) { |
643 | s64 root_blocks = 0; | 641 | percpu_counter_add(&sbi->s_dirtyblocks_counter, nblocks); |
644 | struct percpu_counter *fbc = &sbi->s_freeblocks_counter; | ||
645 | struct percpu_counter *dbc = &sbi->s_dirtyblocks_counter; | ||
646 | |||
647 | free_blocks = percpu_counter_read_positive(fbc); | ||
648 | dirty_blocks = percpu_counter_read_positive(dbc); | ||
649 | |||
650 | if (!capable(CAP_SYS_RESOURCE) && | ||
651 | sbi->s_resuid != current->fsuid && | ||
652 | (sbi->s_resgid == 0 || !in_group_p(sbi->s_resgid))) | ||
653 | root_blocks = ext4_r_blocks_count(sbi->s_es); | ||
654 | |||
655 | if (free_blocks - (nblocks + root_blocks + dirty_blocks) < | ||
656 | EXT4_FREEBLOCKS_WATERMARK) { | ||
657 | free_blocks = percpu_counter_sum(fbc); | ||
658 | dirty_blocks = percpu_counter_sum(dbc); | ||
659 | } | ||
660 | if (free_blocks <= (root_blocks + dirty_blocks)) | ||
661 | /* we don't have free space */ | ||
662 | return 0; | 642 | return 0; |
663 | 643 | } else | |
664 | if (free_blocks - (root_blocks + dirty_blocks) < nblocks) | 644 | return -ENOSPC; |
665 | return free_blocks - (root_blocks + dirty_blocks); | ||
666 | return nblocks; | ||
667 | } | 645 | } |
668 | 646 | ||
669 | |||
670 | /** | 647 | /** |
671 | * ext4_should_retry_alloc() | 648 | * ext4_should_retry_alloc() |
672 | * @sb: super block | 649 | * @sb: super block |
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 4880cc3e6727..b0537c827024 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -1003,8 +1003,7 @@ extern ext4_fsblk_t ext4_new_blocks(handle_t *handle, struct inode *inode, | |||
1003 | ext4_lblk_t iblock, ext4_fsblk_t goal, | 1003 | ext4_lblk_t iblock, ext4_fsblk_t goal, |
1004 | unsigned long *count, int *errp); | 1004 | unsigned long *count, int *errp); |
1005 | extern int ext4_claim_free_blocks(struct ext4_sb_info *sbi, s64 nblocks); | 1005 | extern int ext4_claim_free_blocks(struct ext4_sb_info *sbi, s64 nblocks); |
1006 | extern ext4_fsblk_t ext4_has_free_blocks(struct ext4_sb_info *sbi, | 1006 | extern int ext4_has_free_blocks(struct ext4_sb_info *sbi, s64 nblocks); |
1007 | s64 nblocks); | ||
1008 | extern void ext4_free_blocks(handle_t *handle, struct inode *inode, | 1007 | extern void ext4_free_blocks(handle_t *handle, struct inode *inode, |
1009 | ext4_fsblk_t block, unsigned long count, int metadata); | 1008 | ext4_fsblk_t block, unsigned long count, int metadata); |
1010 | extern void ext4_free_blocks_sb(handle_t *handle, struct super_block *sb, | 1009 | extern void ext4_free_blocks_sb(handle_t *handle, struct super_block *sb, |
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index fe34d74cfb19..2a117e286e54 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c | |||
@@ -718,6 +718,8 @@ got: | |||
718 | gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT); | 718 | gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT); |
719 | free = ext4_free_blocks_after_init(sb, group, gdp); | 719 | free = ext4_free_blocks_after_init(sb, group, gdp); |
720 | gdp->bg_free_blocks_count = cpu_to_le16(free); | 720 | gdp->bg_free_blocks_count = cpu_to_le16(free); |
721 | gdp->bg_checksum = ext4_group_desc_csum(sbi, group, | ||
722 | gdp); | ||
721 | } | 723 | } |
722 | spin_unlock(sb_bgl_lock(sbi, group)); | 724 | spin_unlock(sb_bgl_lock(sbi, group)); |
723 | 725 | ||
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 8dbf6953845b..be21a5ae33cb 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -2329,6 +2329,8 @@ static int ext4_da_writepage(struct page *page, | |||
2329 | unlock_page(page); | 2329 | unlock_page(page); |
2330 | return 0; | 2330 | return 0; |
2331 | } | 2331 | } |
2332 | /* now mark the buffer_heads as dirty and uptodate */ | ||
2333 | block_commit_write(page, 0, PAGE_CACHE_SIZE); | ||
2332 | } | 2334 | } |
2333 | 2335 | ||
2334 | if (test_opt(inode->i_sb, NOBH) && ext4_should_writeback_data(inode)) | 2336 | if (test_opt(inode->i_sb, NOBH) && ext4_should_writeback_data(inode)) |
@@ -4580,9 +4582,10 @@ static int ext4_indirect_trans_blocks(struct inode *inode, int nrblocks, | |||
4580 | static int ext4_index_trans_blocks(struct inode *inode, int nrblocks, int chunk) | 4582 | static int ext4_index_trans_blocks(struct inode *inode, int nrblocks, int chunk) |
4581 | { | 4583 | { |
4582 | if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL)) | 4584 | if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL)) |
4583 | return ext4_indirect_trans_blocks(inode, nrblocks, 0); | 4585 | return ext4_indirect_trans_blocks(inode, nrblocks, chunk); |
4584 | return ext4_ext_index_trans_blocks(inode, nrblocks, 0); | 4586 | return ext4_ext_index_trans_blocks(inode, nrblocks, chunk); |
4585 | } | 4587 | } |
4588 | |||
4586 | /* | 4589 | /* |
4587 | * Account for index blocks, block groups bitmaps and block group | 4590 | * Account for index blocks, block groups bitmaps and block group |
4588 | * descriptor blocks if modify datablocks and index blocks | 4591 | * descriptor blocks if modify datablocks and index blocks |
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index dfe17a134052..444ad998f72e 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c | |||
@@ -4441,6 +4441,7 @@ ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b, | |||
4441 | else if (block >= (entry->start_blk + entry->count)) | 4441 | else if (block >= (entry->start_blk + entry->count)) |
4442 | n = &(*n)->rb_right; | 4442 | n = &(*n)->rb_right; |
4443 | else { | 4443 | else { |
4444 | ext4_unlock_group(sb, group); | ||
4444 | ext4_error(sb, __func__, | 4445 | ext4_error(sb, __func__, |
4445 | "Double free of blocks %d (%d %d)\n", | 4446 | "Double free of blocks %d (%d %d)\n", |
4446 | block, entry->start_blk, entry->count); | 4447 | block, entry->start_blk, entry->count); |
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index bdddea14e782..e4a241c65dbe 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
@@ -333,7 +333,8 @@ void ext4_abort(struct super_block *sb, const char *function, | |||
333 | EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS; | 333 | EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS; |
334 | sb->s_flags |= MS_RDONLY; | 334 | sb->s_flags |= MS_RDONLY; |
335 | EXT4_SB(sb)->s_mount_opt |= EXT4_MOUNT_ABORT; | 335 | EXT4_SB(sb)->s_mount_opt |= EXT4_MOUNT_ABORT; |
336 | jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO); | 336 | if (EXT4_SB(sb)->s_journal) |
337 | jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO); | ||
337 | } | 338 | } |
338 | 339 | ||
339 | void ext4_warning(struct super_block *sb, const char *function, | 340 | void ext4_warning(struct super_block *sb, const char *function, |
@@ -442,14 +443,16 @@ static void ext4_put_super(struct super_block *sb) | |||
442 | { | 443 | { |
443 | struct ext4_sb_info *sbi = EXT4_SB(sb); | 444 | struct ext4_sb_info *sbi = EXT4_SB(sb); |
444 | struct ext4_super_block *es = sbi->s_es; | 445 | struct ext4_super_block *es = sbi->s_es; |
445 | int i; | 446 | int i, err; |
446 | 447 | ||
447 | ext4_mb_release(sb); | 448 | ext4_mb_release(sb); |
448 | ext4_ext_release(sb); | 449 | ext4_ext_release(sb); |
449 | ext4_xattr_put_super(sb); | 450 | ext4_xattr_put_super(sb); |
450 | if (jbd2_journal_destroy(sbi->s_journal) < 0) | 451 | err = jbd2_journal_destroy(sbi->s_journal); |
451 | ext4_abort(sb, __func__, "Couldn't clean up the journal"); | ||
452 | sbi->s_journal = NULL; | 452 | sbi->s_journal = NULL; |
453 | if (err < 0) | ||
454 | ext4_abort(sb, __func__, "Couldn't clean up the journal"); | ||
455 | |||
453 | if (!(sb->s_flags & MS_RDONLY)) { | 456 | if (!(sb->s_flags & MS_RDONLY)) { |
454 | EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER); | 457 | EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER); |
455 | es->s_state = cpu_to_le16(sbi->s_mount_state); | 458 | es->s_state = cpu_to_le16(sbi->s_mount_state); |
@@ -1455,9 +1458,8 @@ static int ext4_fill_flex_info(struct super_block *sb) | |||
1455 | 1458 | ||
1456 | /* We allocate both existing and potentially added groups */ | 1459 | /* We allocate both existing and potentially added groups */ |
1457 | flex_group_count = ((sbi->s_groups_count + groups_per_flex - 1) + | 1460 | flex_group_count = ((sbi->s_groups_count + groups_per_flex - 1) + |
1458 | ((sbi->s_es->s_reserved_gdt_blocks +1 ) << | 1461 | ((le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) + 1) << |
1459 | EXT4_DESC_PER_BLOCK_BITS(sb))) / | 1462 | EXT4_DESC_PER_BLOCK_BITS(sb))) / groups_per_flex; |
1460 | groups_per_flex; | ||
1461 | sbi->s_flex_groups = kzalloc(flex_group_count * | 1463 | sbi->s_flex_groups = kzalloc(flex_group_count * |
1462 | sizeof(struct flex_groups), GFP_KERNEL); | 1464 | sizeof(struct flex_groups), GFP_KERNEL); |
1463 | if (sbi->s_flex_groups == NULL) { | 1465 | if (sbi->s_flex_groups == NULL) { |
@@ -2882,12 +2884,9 @@ int ext4_force_commit(struct super_block *sb) | |||
2882 | /* | 2884 | /* |
2883 | * Ext4 always journals updates to the superblock itself, so we don't | 2885 | * Ext4 always journals updates to the superblock itself, so we don't |
2884 | * have to propagate any other updates to the superblock on disk at this | 2886 | * have to propagate any other updates to the superblock on disk at this |
2885 | * point. Just start an async writeback to get the buffers on their way | 2887 | * point. (We can probably nuke this function altogether, and remove |
2886 | * to the disk. | 2888 | * any mention to sb->s_dirt in all of fs/ext4; eventual cleanup...) |
2887 | * | ||
2888 | * This implicitly triggers the writebehind on sync(). | ||
2889 | */ | 2889 | */ |
2890 | |||
2891 | static void ext4_write_super(struct super_block *sb) | 2890 | static void ext4_write_super(struct super_block *sb) |
2892 | { | 2891 | { |
2893 | if (mutex_trylock(&sb->s_lock) != 0) | 2892 | if (mutex_trylock(&sb->s_lock) != 0) |
@@ -2897,15 +2896,15 @@ static void ext4_write_super(struct super_block *sb) | |||
2897 | 2896 | ||
2898 | static int ext4_sync_fs(struct super_block *sb, int wait) | 2897 | static int ext4_sync_fs(struct super_block *sb, int wait) |
2899 | { | 2898 | { |
2900 | tid_t target; | 2899 | int ret = 0; |
2901 | 2900 | ||
2902 | trace_mark(ext4_sync_fs, "dev %s wait %d", sb->s_id, wait); | 2901 | trace_mark(ext4_sync_fs, "dev %s wait %d", sb->s_id, wait); |
2903 | sb->s_dirt = 0; | 2902 | sb->s_dirt = 0; |
2904 | if (jbd2_journal_start_commit(EXT4_SB(sb)->s_journal, &target)) { | 2903 | if (wait) |
2905 | if (wait) | 2904 | ret = ext4_force_commit(sb); |
2906 | jbd2_log_wait_commit(EXT4_SB(sb)->s_journal, target); | 2905 | else |
2907 | } | 2906 | jbd2_journal_start_commit(EXT4_SB(sb)->s_journal, NULL); |
2908 | return 0; | 2907 | return ret; |
2909 | } | 2908 | } |
2910 | 2909 | ||
2911 | /* | 2910 | /* |