diff options
-rw-r--r-- | fs/ext4/balloc.c | 62 | ||||
-rw-r--r-- | fs/ext4/ext4_sb.h | 1 | ||||
-rw-r--r-- | fs/ext4/inode.c | 22 | ||||
-rw-r--r-- | fs/ext4/mballoc.c | 31 | ||||
-rw-r--r-- | fs/ext4/super.c | 8 |
5 files changed, 73 insertions, 51 deletions
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index 57909882c084..edef0023e6e6 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c | |||
@@ -1605,26 +1605,38 @@ out: | |||
1605 | int ext4_claim_free_blocks(struct ext4_sb_info *sbi, | 1605 | int ext4_claim_free_blocks(struct ext4_sb_info *sbi, |
1606 | ext4_fsblk_t nblocks) | 1606 | ext4_fsblk_t nblocks) |
1607 | { | 1607 | { |
1608 | s64 free_blocks; | 1608 | s64 free_blocks, dirty_blocks; |
1609 | ext4_fsblk_t root_blocks = 0; | 1609 | ext4_fsblk_t root_blocks = 0; |
1610 | struct percpu_counter *fbc = &sbi->s_freeblocks_counter; | 1610 | struct percpu_counter *fbc = &sbi->s_freeblocks_counter; |
1611 | struct percpu_counter *dbc = &sbi->s_dirtyblocks_counter; | ||
1611 | 1612 | ||
1612 | free_blocks = percpu_counter_read(fbc); | 1613 | free_blocks = percpu_counter_read_positive(fbc); |
1614 | dirty_blocks = percpu_counter_read_positive(dbc); | ||
1613 | 1615 | ||
1614 | if (!capable(CAP_SYS_RESOURCE) && | 1616 | if (!capable(CAP_SYS_RESOURCE) && |
1615 | sbi->s_resuid != current->fsuid && | 1617 | sbi->s_resuid != current->fsuid && |
1616 | (sbi->s_resgid == 0 || !in_group_p(sbi->s_resgid))) | 1618 | (sbi->s_resgid == 0 || !in_group_p(sbi->s_resgid))) |
1617 | root_blocks = ext4_r_blocks_count(sbi->s_es); | 1619 | root_blocks = ext4_r_blocks_count(sbi->s_es); |
1618 | 1620 | ||
1619 | if (free_blocks - (nblocks + root_blocks) < EXT4_FREEBLOCKS_WATERMARK) | 1621 | if (free_blocks - (nblocks + root_blocks + dirty_blocks) < |
1620 | free_blocks = percpu_counter_sum(&sbi->s_freeblocks_counter); | 1622 | EXT4_FREEBLOCKS_WATERMARK) { |
1621 | 1623 | free_blocks = percpu_counter_sum(fbc); | |
1622 | if (free_blocks < (root_blocks + nblocks)) | 1624 | dirty_blocks = percpu_counter_sum(dbc); |
1625 | if (dirty_blocks < 0) { | ||
1626 | printk(KERN_CRIT "Dirty block accounting " | ||
1627 | "went wrong %lld\n", | ||
1628 | dirty_blocks); | ||
1629 | } | ||
1630 | } | ||
1631 | /* Check whether we have space after | ||
1632 | * accounting for current dirty blocks | ||
1633 | */ | ||
1634 | if (free_blocks < ((s64)(root_blocks + nblocks) + dirty_blocks)) | ||
1623 | /* we don't have free space */ | 1635 | /* we don't have free space */ |
1624 | return -ENOSPC; | 1636 | return -ENOSPC; |
1625 | 1637 | ||
1626 | /* reduce fs free blocks counter */ | 1638 | /* Add the blocks to nblocks */ |
1627 | percpu_counter_sub(fbc, nblocks); | 1639 | percpu_counter_add(dbc, nblocks); |
1628 | return 0; | 1640 | return 0; |
1629 | } | 1641 | } |
1630 | 1642 | ||
@@ -1640,23 +1652,28 @@ int ext4_claim_free_blocks(struct ext4_sb_info *sbi, | |||
1640 | ext4_fsblk_t ext4_has_free_blocks(struct ext4_sb_info *sbi, | 1652 | ext4_fsblk_t ext4_has_free_blocks(struct ext4_sb_info *sbi, |
1641 | ext4_fsblk_t nblocks) | 1653 | ext4_fsblk_t nblocks) |
1642 | { | 1654 | { |
1643 | ext4_fsblk_t free_blocks; | 1655 | ext4_fsblk_t free_blocks, dirty_blocks; |
1644 | ext4_fsblk_t root_blocks = 0; | 1656 | ext4_fsblk_t root_blocks = 0; |
1657 | struct percpu_counter *fbc = &sbi->s_freeblocks_counter; | ||
1658 | struct percpu_counter *dbc = &sbi->s_dirtyblocks_counter; | ||
1645 | 1659 | ||
1646 | free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter); | 1660 | free_blocks = percpu_counter_read_positive(fbc); |
1661 | dirty_blocks = percpu_counter_read_positive(dbc); | ||
1647 | 1662 | ||
1648 | if (!capable(CAP_SYS_RESOURCE) && | 1663 | if (!capable(CAP_SYS_RESOURCE) && |
1649 | sbi->s_resuid != current->fsuid && | 1664 | sbi->s_resuid != current->fsuid && |
1650 | (sbi->s_resgid == 0 || !in_group_p(sbi->s_resgid))) | 1665 | (sbi->s_resgid == 0 || !in_group_p(sbi->s_resgid))) |
1651 | root_blocks = ext4_r_blocks_count(sbi->s_es); | 1666 | root_blocks = ext4_r_blocks_count(sbi->s_es); |
1652 | 1667 | ||
1653 | if (free_blocks - (nblocks + root_blocks) < EXT4_FREEBLOCKS_WATERMARK) | 1668 | if (free_blocks - (nblocks + root_blocks + dirty_blocks) < |
1654 | free_blocks = percpu_counter_sum_positive(&sbi->s_freeblocks_counter); | 1669 | EXT4_FREEBLOCKS_WATERMARK) { |
1655 | 1670 | free_blocks = percpu_counter_sum_positive(fbc); | |
1656 | if (free_blocks <= root_blocks) | 1671 | dirty_blocks = percpu_counter_sum_positive(dbc); |
1672 | } | ||
1673 | if (free_blocks <= (root_blocks + dirty_blocks)) | ||
1657 | /* we don't have free space */ | 1674 | /* we don't have free space */ |
1658 | return 0; | 1675 | return 0; |
1659 | if (free_blocks - root_blocks < nblocks) | 1676 | if (free_blocks - (root_blocks + dirty_blocks) < nblocks) |
1660 | return free_blocks - root_blocks; | 1677 | return free_blocks - root_blocks; |
1661 | return nblocks; | 1678 | return nblocks; |
1662 | } | 1679 | } |
@@ -1943,13 +1960,14 @@ allocated: | |||
1943 | le16_add_cpu(&gdp->bg_free_blocks_count, -num); | 1960 | le16_add_cpu(&gdp->bg_free_blocks_count, -num); |
1944 | gdp->bg_checksum = ext4_group_desc_csum(sbi, group_no, gdp); | 1961 | gdp->bg_checksum = ext4_group_desc_csum(sbi, group_no, gdp); |
1945 | spin_unlock(sb_bgl_lock(sbi, group_no)); | 1962 | spin_unlock(sb_bgl_lock(sbi, group_no)); |
1946 | if (!EXT4_I(inode)->i_delalloc_reserved_flag && (*count != num)) { | 1963 | percpu_counter_sub(&sbi->s_freeblocks_counter, num); |
1947 | /* | 1964 | /* |
1948 | * we allocated less blocks than we | 1965 | * Now reduce the dirty block count also. Should not go negative |
1949 | * claimed. Add the difference back. | 1966 | */ |
1950 | */ | 1967 | if (!EXT4_I(inode)->i_delalloc_reserved_flag) |
1951 | percpu_counter_add(&sbi->s_freeblocks_counter, *count - num); | 1968 | percpu_counter_sub(&sbi->s_dirtyblocks_counter, *count); |
1952 | } | 1969 | else |
1970 | percpu_counter_sub(&sbi->s_dirtyblocks_counter, num); | ||
1953 | if (sbi->s_log_groups_per_flex) { | 1971 | if (sbi->s_log_groups_per_flex) { |
1954 | ext4_group_t flex_group = ext4_flex_group(sbi, group_no); | 1972 | ext4_group_t flex_group = ext4_flex_group(sbi, group_no); |
1955 | spin_lock(sb_bgl_lock(sbi, flex_group)); | 1973 | spin_lock(sb_bgl_lock(sbi, flex_group)); |
diff --git a/fs/ext4/ext4_sb.h b/fs/ext4/ext4_sb.h index 69810a252539..a5577e0ccd3b 100644 --- a/fs/ext4/ext4_sb.h +++ b/fs/ext4/ext4_sb.h | |||
@@ -59,6 +59,7 @@ struct ext4_sb_info { | |||
59 | struct percpu_counter s_freeblocks_counter; | 59 | struct percpu_counter s_freeblocks_counter; |
60 | struct percpu_counter s_freeinodes_counter; | 60 | struct percpu_counter s_freeinodes_counter; |
61 | struct percpu_counter s_dirs_counter; | 61 | struct percpu_counter s_dirs_counter; |
62 | struct percpu_counter s_dirtyblocks_counter; | ||
62 | struct blockgroup_lock s_blockgroup_lock; | 63 | struct blockgroup_lock s_blockgroup_lock; |
63 | 64 | ||
64 | /* root of the per fs reservation window tree */ | 65 | /* root of the per fs reservation window tree */ |
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index eb9d449817d0..7875a2dd54b9 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -1030,19 +1030,20 @@ static void ext4_da_update_reserve_space(struct inode *inode, int used) | |||
1030 | BUG_ON(mdb > EXT4_I(inode)->i_reserved_meta_blocks); | 1030 | BUG_ON(mdb > EXT4_I(inode)->i_reserved_meta_blocks); |
1031 | mdb_free = EXT4_I(inode)->i_reserved_meta_blocks - mdb; | 1031 | mdb_free = EXT4_I(inode)->i_reserved_meta_blocks - mdb; |
1032 | 1032 | ||
1033 | /* Account for allocated meta_blocks */ | 1033 | if (mdb_free) { |
1034 | mdb_free -= EXT4_I(inode)->i_allocated_meta_blocks; | 1034 | /* Account for allocated meta_blocks */ |
1035 | 1035 | mdb_free -= EXT4_I(inode)->i_allocated_meta_blocks; | |
1036 | /* update fs free blocks counter for truncate case */ | 1036 | |
1037 | percpu_counter_add(&sbi->s_freeblocks_counter, mdb_free); | 1037 | /* update fs dirty blocks counter */ |
1038 | percpu_counter_sub(&sbi->s_dirtyblocks_counter, mdb_free); | ||
1039 | EXT4_I(inode)->i_allocated_meta_blocks = 0; | ||
1040 | EXT4_I(inode)->i_reserved_meta_blocks = mdb; | ||
1041 | } | ||
1038 | 1042 | ||
1039 | /* update per-inode reservations */ | 1043 | /* update per-inode reservations */ |
1040 | BUG_ON(used > EXT4_I(inode)->i_reserved_data_blocks); | 1044 | BUG_ON(used > EXT4_I(inode)->i_reserved_data_blocks); |
1041 | EXT4_I(inode)->i_reserved_data_blocks -= used; | 1045 | EXT4_I(inode)->i_reserved_data_blocks -= used; |
1042 | 1046 | ||
1043 | BUG_ON(mdb > EXT4_I(inode)->i_reserved_meta_blocks); | ||
1044 | EXT4_I(inode)->i_reserved_meta_blocks = mdb; | ||
1045 | EXT4_I(inode)->i_allocated_meta_blocks = 0; | ||
1046 | spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); | 1047 | spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); |
1047 | } | 1048 | } |
1048 | 1049 | ||
@@ -1588,8 +1589,8 @@ static void ext4_da_release_space(struct inode *inode, int to_free) | |||
1588 | 1589 | ||
1589 | release = to_free + mdb_free; | 1590 | release = to_free + mdb_free; |
1590 | 1591 | ||
1591 | /* update fs free blocks counter for truncate case */ | 1592 | /* update fs dirty blocks counter for truncate case */ |
1592 | percpu_counter_add(&sbi->s_freeblocks_counter, release); | 1593 | percpu_counter_sub(&sbi->s_dirtyblocks_counter, release); |
1593 | 1594 | ||
1594 | /* update per-inode reservations */ | 1595 | /* update per-inode reservations */ |
1595 | BUG_ON(to_free > EXT4_I(inode)->i_reserved_data_blocks); | 1596 | BUG_ON(to_free > EXT4_I(inode)->i_reserved_data_blocks); |
@@ -2471,7 +2472,6 @@ static int ext4_da_write_begin(struct file *file, struct address_space *mapping, | |||
2471 | index = pos >> PAGE_CACHE_SHIFT; | 2472 | index = pos >> PAGE_CACHE_SHIFT; |
2472 | from = pos & (PAGE_CACHE_SIZE - 1); | 2473 | from = pos & (PAGE_CACHE_SIZE - 1); |
2473 | to = from + len; | 2474 | to = from + len; |
2474 | |||
2475 | retry: | 2475 | retry: |
2476 | /* | 2476 | /* |
2477 | * With delayed allocation, we don't log the i_disksize update | 2477 | * With delayed allocation, we don't log the i_disksize update |
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index e4f30de11a9d..585c25950184 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c | |||
@@ -2880,7 +2880,7 @@ void exit_ext4_mballoc(void) | |||
2880 | */ | 2880 | */ |
2881 | static noinline_for_stack int | 2881 | static noinline_for_stack int |
2882 | ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac, | 2882 | ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac, |
2883 | handle_t *handle) | 2883 | handle_t *handle, unsigned long reserv_blks) |
2884 | { | 2884 | { |
2885 | struct buffer_head *bitmap_bh = NULL; | 2885 | struct buffer_head *bitmap_bh = NULL; |
2886 | struct ext4_super_block *es; | 2886 | struct ext4_super_block *es; |
@@ -2969,21 +2969,16 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac, | |||
2969 | le16_add_cpu(&gdp->bg_free_blocks_count, -ac->ac_b_ex.fe_len); | 2969 | le16_add_cpu(&gdp->bg_free_blocks_count, -ac->ac_b_ex.fe_len); |
2970 | gdp->bg_checksum = ext4_group_desc_csum(sbi, ac->ac_b_ex.fe_group, gdp); | 2970 | gdp->bg_checksum = ext4_group_desc_csum(sbi, ac->ac_b_ex.fe_group, gdp); |
2971 | spin_unlock(sb_bgl_lock(sbi, ac->ac_b_ex.fe_group)); | 2971 | spin_unlock(sb_bgl_lock(sbi, ac->ac_b_ex.fe_group)); |
2972 | 2972 | percpu_counter_sub(&sbi->s_freeblocks_counter, ac->ac_b_ex.fe_len); | |
2973 | /* | 2973 | /* |
2974 | * free blocks account has already be reduced/reserved | 2974 | * Now reduce the dirty block count also. Should not go negative |
2975 | * at write_begin() time for delayed allocation | ||
2976 | * do not double accounting | ||
2977 | */ | 2975 | */ |
2978 | if (!(ac->ac_flags & EXT4_MB_DELALLOC_RESERVED) && | 2976 | if (!(ac->ac_flags & EXT4_MB_DELALLOC_RESERVED)) |
2979 | ac->ac_o_ex.fe_len != ac->ac_b_ex.fe_len) { | 2977 | /* release all the reserved blocks if non delalloc */ |
2980 | /* | 2978 | percpu_counter_sub(&sbi->s_dirtyblocks_counter, reserv_blks); |
2981 | * we allocated less blocks than we calimed | 2979 | else |
2982 | * Add the difference back | 2980 | percpu_counter_sub(&sbi->s_dirtyblocks_counter, |
2983 | */ | 2981 | ac->ac_b_ex.fe_len); |
2984 | percpu_counter_add(&sbi->s_freeblocks_counter, | ||
2985 | ac->ac_o_ex.fe_len - ac->ac_b_ex.fe_len); | ||
2986 | } | ||
2987 | 2982 | ||
2988 | if (sbi->s_log_groups_per_flex) { | 2983 | if (sbi->s_log_groups_per_flex) { |
2989 | ext4_group_t flex_group = ext4_flex_group(sbi, | 2984 | ext4_group_t flex_group = ext4_flex_group(sbi, |
@@ -4376,12 +4371,13 @@ static int ext4_mb_discard_preallocations(struct super_block *sb, int needed) | |||
4376 | ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle, | 4371 | ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle, |
4377 | struct ext4_allocation_request *ar, int *errp) | 4372 | struct ext4_allocation_request *ar, int *errp) |
4378 | { | 4373 | { |
4374 | int freed; | ||
4379 | struct ext4_allocation_context *ac = NULL; | 4375 | struct ext4_allocation_context *ac = NULL; |
4380 | struct ext4_sb_info *sbi; | 4376 | struct ext4_sb_info *sbi; |
4381 | struct super_block *sb; | 4377 | struct super_block *sb; |
4382 | ext4_fsblk_t block = 0; | 4378 | ext4_fsblk_t block = 0; |
4383 | int freed; | 4379 | unsigned long inquota; |
4384 | int inquota; | 4380 | unsigned long reserv_blks = 0; |
4385 | 4381 | ||
4386 | sb = ar->inode->i_sb; | 4382 | sb = ar->inode->i_sb; |
4387 | sbi = EXT4_SB(sb); | 4383 | sbi = EXT4_SB(sb); |
@@ -4404,6 +4400,7 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle, | |||
4404 | *errp = -ENOSPC; | 4400 | *errp = -ENOSPC; |
4405 | return 0; | 4401 | return 0; |
4406 | } | 4402 | } |
4403 | reserv_blks = ar->len; | ||
4407 | } | 4404 | } |
4408 | while (ar->len && DQUOT_ALLOC_BLOCK(ar->inode, ar->len)) { | 4405 | while (ar->len && DQUOT_ALLOC_BLOCK(ar->inode, ar->len)) { |
4409 | ar->flags |= EXT4_MB_HINT_NOPREALLOC; | 4406 | ar->flags |= EXT4_MB_HINT_NOPREALLOC; |
@@ -4450,7 +4447,7 @@ repeat: | |||
4450 | } | 4447 | } |
4451 | 4448 | ||
4452 | if (likely(ac->ac_status == AC_STATUS_FOUND)) { | 4449 | if (likely(ac->ac_status == AC_STATUS_FOUND)) { |
4453 | *errp = ext4_mb_mark_diskspace_used(ac, handle); | 4450 | *errp = ext4_mb_mark_diskspace_used(ac, handle, reserv_blks); |
4454 | if (*errp == -EAGAIN) { | 4451 | if (*errp == -EAGAIN) { |
4455 | ac->ac_b_ex.fe_group = 0; | 4452 | ac->ac_b_ex.fe_group = 0; |
4456 | ac->ac_b_ex.fe_start = 0; | 4453 | ac->ac_b_ex.fe_start = 0; |
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 7de6ca0c9e9b..efa40d9d3792 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
@@ -520,6 +520,7 @@ static void ext4_put_super(struct super_block *sb) | |||
520 | percpu_counter_destroy(&sbi->s_freeblocks_counter); | 520 | percpu_counter_destroy(&sbi->s_freeblocks_counter); |
521 | percpu_counter_destroy(&sbi->s_freeinodes_counter); | 521 | percpu_counter_destroy(&sbi->s_freeinodes_counter); |
522 | percpu_counter_destroy(&sbi->s_dirs_counter); | 522 | percpu_counter_destroy(&sbi->s_dirs_counter); |
523 | percpu_counter_destroy(&sbi->s_dirtyblocks_counter); | ||
523 | brelse(sbi->s_sbh); | 524 | brelse(sbi->s_sbh); |
524 | #ifdef CONFIG_QUOTA | 525 | #ifdef CONFIG_QUOTA |
525 | for (i = 0; i < MAXQUOTAS; i++) | 526 | for (i = 0; i < MAXQUOTAS; i++) |
@@ -2259,6 +2260,9 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
2259 | err = percpu_counter_init(&sbi->s_dirs_counter, | 2260 | err = percpu_counter_init(&sbi->s_dirs_counter, |
2260 | ext4_count_dirs(sb)); | 2261 | ext4_count_dirs(sb)); |
2261 | } | 2262 | } |
2263 | if (!err) { | ||
2264 | err = percpu_counter_init(&sbi->s_dirtyblocks_counter, 0); | ||
2265 | } | ||
2262 | if (err) { | 2266 | if (err) { |
2263 | printk(KERN_ERR "EXT4-fs: insufficient memory\n"); | 2267 | printk(KERN_ERR "EXT4-fs: insufficient memory\n"); |
2264 | goto failed_mount3; | 2268 | goto failed_mount3; |
@@ -2491,6 +2495,7 @@ failed_mount3: | |||
2491 | percpu_counter_destroy(&sbi->s_freeblocks_counter); | 2495 | percpu_counter_destroy(&sbi->s_freeblocks_counter); |
2492 | percpu_counter_destroy(&sbi->s_freeinodes_counter); | 2496 | percpu_counter_destroy(&sbi->s_freeinodes_counter); |
2493 | percpu_counter_destroy(&sbi->s_dirs_counter); | 2497 | percpu_counter_destroy(&sbi->s_dirs_counter); |
2498 | percpu_counter_destroy(&sbi->s_dirtyblocks_counter); | ||
2494 | failed_mount2: | 2499 | failed_mount2: |
2495 | for (i = 0; i < db_count; i++) | 2500 | for (i = 0; i < db_count; i++) |
2496 | brelse(sbi->s_group_desc[i]); | 2501 | brelse(sbi->s_group_desc[i]); |
@@ -3169,7 +3174,8 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
3169 | buf->f_type = EXT4_SUPER_MAGIC; | 3174 | buf->f_type = EXT4_SUPER_MAGIC; |
3170 | buf->f_bsize = sb->s_blocksize; | 3175 | buf->f_bsize = sb->s_blocksize; |
3171 | buf->f_blocks = ext4_blocks_count(es) - sbi->s_overhead_last; | 3176 | buf->f_blocks = ext4_blocks_count(es) - sbi->s_overhead_last; |
3172 | buf->f_bfree = percpu_counter_sum_positive(&sbi->s_freeblocks_counter); | 3177 | buf->f_bfree = percpu_counter_sum_positive(&sbi->s_freeblocks_counter) - |
3178 | percpu_counter_sum_positive(&sbi->s_dirtyblocks_counter); | ||
3173 | ext4_free_blocks_count_set(es, buf->f_bfree); | 3179 | ext4_free_blocks_count_set(es, buf->f_bfree); |
3174 | buf->f_bavail = buf->f_bfree - ext4_r_blocks_count(es); | 3180 | buf->f_bavail = buf->f_bfree - ext4_r_blocks_count(es); |
3175 | if (buf->f_bfree < ext4_r_blocks_count(es)) | 3181 | if (buf->f_bfree < ext4_r_blocks_count(es)) |