diff options
-rw-r--r-- | fs/ext4/balloc.c | 58 | ||||
-rw-r--r-- | fs/ext4/ext4.h | 13 | ||||
-rw-r--r-- | fs/ext4/inode.c | 5 | ||||
-rw-r--r-- | fs/ext4/mballoc.c | 23 |
4 files changed, 69 insertions, 30 deletions
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index 58005c01abb8..1707850301d6 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c | |||
@@ -1602,6 +1602,32 @@ out: | |||
1602 | return ret; | 1602 | return ret; |
1603 | } | 1603 | } |
1604 | 1604 | ||
1605 | int ext4_claim_free_blocks(struct ext4_sb_info *sbi, | ||
1606 | ext4_fsblk_t nblocks) | ||
1607 | { | ||
1608 | s64 free_blocks; | ||
1609 | ext4_fsblk_t root_blocks = 0; | ||
1610 | struct percpu_counter *fbc = &sbi->s_freeblocks_counter; | ||
1611 | |||
1612 | free_blocks = percpu_counter_read(fbc); | ||
1613 | |||
1614 | if (!capable(CAP_SYS_RESOURCE) && | ||
1615 | sbi->s_resuid != current->fsuid && | ||
1616 | (sbi->s_resgid == 0 || !in_group_p(sbi->s_resgid))) | ||
1617 | root_blocks = ext4_r_blocks_count(sbi->s_es); | ||
1618 | |||
1619 | if (free_blocks - (nblocks + root_blocks) < EXT4_FREEBLOCKS_WATERMARK) | ||
1620 | free_blocks = percpu_counter_sum(&sbi->s_freeblocks_counter); | ||
1621 | |||
1622 | if (free_blocks < (root_blocks + nblocks)) | ||
1623 | /* we don't have free space */ | ||
1624 | return -ENOSPC; | ||
1625 | |||
1626 | /* reduce fs free blocks counter */ | ||
1627 | percpu_counter_sub(fbc, nblocks); | ||
1628 | return 0; | ||
1629 | } | ||
1630 | |||
1605 | /** | 1631 | /** |
1606 | * ext4_has_free_blocks() | 1632 | * ext4_has_free_blocks() |
1607 | * @sbi: in-core super block structure. | 1633 | * @sbi: in-core super block structure. |
@@ -1623,18 +1649,17 @@ ext4_fsblk_t ext4_has_free_blocks(struct ext4_sb_info *sbi, | |||
1623 | sbi->s_resuid != current->fsuid && | 1649 | sbi->s_resuid != current->fsuid && |
1624 | (sbi->s_resgid == 0 || !in_group_p(sbi->s_resgid))) | 1650 | (sbi->s_resgid == 0 || !in_group_p(sbi->s_resgid))) |
1625 | root_blocks = ext4_r_blocks_count(sbi->s_es); | 1651 | root_blocks = ext4_r_blocks_count(sbi->s_es); |
1626 | #ifdef CONFIG_SMP | 1652 | |
1627 | if (free_blocks - root_blocks < FBC_BATCH) | 1653 | if (free_blocks - (nblocks + root_blocks) < EXT4_FREEBLOCKS_WATERMARK) |
1628 | free_blocks = | 1654 | free_blocks = percpu_counter_sum_positive(&sbi->s_freeblocks_counter); |
1629 | percpu_counter_sum(&sbi->s_freeblocks_counter); | 1655 | |
1630 | #endif | ||
1631 | if (free_blocks <= root_blocks) | 1656 | if (free_blocks <= root_blocks) |
1632 | /* we don't have free space */ | 1657 | /* we don't have free space */ |
1633 | return 0; | 1658 | return 0; |
1634 | if (free_blocks - root_blocks < nblocks) | 1659 | if (free_blocks - root_blocks < nblocks) |
1635 | return free_blocks - root_blocks; | 1660 | return free_blocks - root_blocks; |
1636 | return nblocks; | 1661 | return nblocks; |
1637 | } | 1662 | } |
1638 | 1663 | ||
1639 | 1664 | ||
1640 | /** | 1665 | /** |
@@ -1713,14 +1738,11 @@ ext4_fsblk_t ext4_old_new_blocks(handle_t *handle, struct inode *inode, | |||
1713 | /* | 1738 | /* |
1714 | * With delalloc we already reserved the blocks | 1739 | * With delalloc we already reserved the blocks |
1715 | */ | 1740 | */ |
1716 | *count = ext4_has_free_blocks(sbi, *count); | 1741 | if (ext4_claim_free_blocks(sbi, *count)) { |
1717 | } | 1742 | *errp = -ENOSPC; |
1718 | if (*count == 0) { | 1743 | return 0; /*return with ENOSPC error */ |
1719 | *errp = -ENOSPC; | 1744 | } |
1720 | return 0; /*return with ENOSPC error */ | ||
1721 | } | 1745 | } |
1722 | num = *count; | ||
1723 | |||
1724 | /* | 1746 | /* |
1725 | * Check quota for allocation of this block. | 1747 | * Check quota for allocation of this block. |
1726 | */ | 1748 | */ |
@@ -1915,9 +1937,13 @@ allocated: | |||
1915 | le16_add_cpu(&gdp->bg_free_blocks_count, -num); | 1937 | le16_add_cpu(&gdp->bg_free_blocks_count, -num); |
1916 | gdp->bg_checksum = ext4_group_desc_csum(sbi, group_no, gdp); | 1938 | gdp->bg_checksum = ext4_group_desc_csum(sbi, group_no, gdp); |
1917 | spin_unlock(sb_bgl_lock(sbi, group_no)); | 1939 | spin_unlock(sb_bgl_lock(sbi, group_no)); |
1918 | if (!EXT4_I(inode)->i_delalloc_reserved_flag) | 1940 | if (!EXT4_I(inode)->i_delalloc_reserved_flag && (*count != num)) { |
1919 | percpu_counter_sub(&sbi->s_freeblocks_counter, num); | 1941 | /* |
1920 | 1942 | * we allocated less blocks than we | |
1943 | * claimed. Add the difference back. | ||
1944 | */ | ||
1945 | percpu_counter_add(&sbi->s_freeblocks_counter, *count - num); | ||
1946 | } | ||
1921 | if (sbi->s_log_groups_per_flex) { | 1947 | if (sbi->s_log_groups_per_flex) { |
1922 | ext4_group_t flex_group = ext4_flex_group(sbi, group_no); | 1948 | ext4_group_t flex_group = ext4_flex_group(sbi, group_no); |
1923 | spin_lock(sb_bgl_lock(sbi, flex_group)); | 1949 | spin_lock(sb_bgl_lock(sbi, flex_group)); |
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 8c701318844d..0154c2d0b242 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -983,6 +983,8 @@ extern ext4_fsblk_t ext4_new_blocks(handle_t *handle, struct inode *inode, | |||
983 | unsigned long *count, int *errp); | 983 | unsigned long *count, int *errp); |
984 | extern ext4_fsblk_t ext4_old_new_blocks(handle_t *handle, struct inode *inode, | 984 | extern ext4_fsblk_t ext4_old_new_blocks(handle_t *handle, struct inode *inode, |
985 | ext4_fsblk_t goal, unsigned long *count, int *errp); | 985 | ext4_fsblk_t goal, unsigned long *count, int *errp); |
986 | extern int ext4_claim_free_blocks(struct ext4_sb_info *sbi, | ||
987 | ext4_fsblk_t nblocks); | ||
986 | extern ext4_fsblk_t ext4_has_free_blocks(struct ext4_sb_info *sbi, | 988 | extern ext4_fsblk_t ext4_has_free_blocks(struct ext4_sb_info *sbi, |
987 | ext4_fsblk_t nblocks); | 989 | ext4_fsblk_t nblocks); |
988 | extern void ext4_free_blocks(handle_t *handle, struct inode *inode, | 990 | extern void ext4_free_blocks(handle_t *handle, struct inode *inode, |
@@ -1207,6 +1209,17 @@ do { \ | |||
1207 | __ext4_std_error((sb), __func__, (errno)); \ | 1209 | __ext4_std_error((sb), __func__, (errno)); \ |
1208 | } while (0) | 1210 | } while (0) |
1209 | 1211 | ||
1212 | #ifdef CONFIG_SMP | ||
1213 | /* Each CPU can accumulate FBC_BATCH blocks in their local | ||
1214 | * counters. So we need to make sure we have free blocks more | ||
1215 | * than FBC_BATCH * nr_cpu_ids. Also add a window of 4 times. | ||
1216 | */ | ||
1217 | #define EXT4_FREEBLOCKS_WATERMARK (4 * (FBC_BATCH * nr_cpu_ids)) | ||
1218 | #else | ||
1219 | #define EXT4_FREEBLOCKS_WATERMARK 0 | ||
1220 | #endif | ||
1221 | |||
1222 | |||
1210 | /* | 1223 | /* |
1211 | * Inodes and files operations | 1224 | * Inodes and files operations |
1212 | */ | 1225 | */ |
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index b6fa0c4087e9..b778d5a33ea7 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -1537,13 +1537,10 @@ static int ext4_da_reserve_space(struct inode *inode, int nrblocks) | |||
1537 | md_needed = mdblocks - EXT4_I(inode)->i_reserved_meta_blocks; | 1537 | md_needed = mdblocks - EXT4_I(inode)->i_reserved_meta_blocks; |
1538 | total = md_needed + nrblocks; | 1538 | total = md_needed + nrblocks; |
1539 | 1539 | ||
1540 | if (ext4_has_free_blocks(sbi, total) < total) { | 1540 | if (ext4_claim_free_blocks(sbi, total)) { |
1541 | spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); | 1541 | spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); |
1542 | return -ENOSPC; | 1542 | return -ENOSPC; |
1543 | } | 1543 | } |
1544 | /* reduce fs free blocks counter */ | ||
1545 | percpu_counter_sub(&sbi->s_freeblocks_counter, total); | ||
1546 | |||
1547 | EXT4_I(inode)->i_reserved_data_blocks += nrblocks; | 1544 | EXT4_I(inode)->i_reserved_data_blocks += nrblocks; |
1548 | EXT4_I(inode)->i_reserved_meta_blocks = mdblocks; | 1545 | EXT4_I(inode)->i_reserved_meta_blocks = mdblocks; |
1549 | 1546 | ||
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 0db2ccfa0dad..2c10b5058a8d 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c | |||
@@ -2975,9 +2975,15 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac, | |||
2975 | * at write_begin() time for delayed allocation | 2975 | * at write_begin() time for delayed allocation |
2976 | * do not double accounting | 2976 | * do not double accounting |
2977 | */ | 2977 | */ |
2978 | if (!(ac->ac_flags & EXT4_MB_DELALLOC_RESERVED)) | 2978 | if (!(ac->ac_flags & EXT4_MB_DELALLOC_RESERVED) && |
2979 | percpu_counter_sub(&sbi->s_freeblocks_counter, | 2979 | ac->ac_o_ex.fe_len != ac->ac_b_ex.fe_len) { |
2980 | ac->ac_b_ex.fe_len); | 2980 | /* |
2981 | * we allocated less blocks than we calimed | ||
2982 | * Add the difference back | ||
2983 | */ | ||
2984 | percpu_counter_add(&sbi->s_freeblocks_counter, | ||
2985 | ac->ac_o_ex.fe_len - ac->ac_b_ex.fe_len); | ||
2986 | } | ||
2981 | 2987 | ||
2982 | if (sbi->s_log_groups_per_flex) { | 2988 | if (sbi->s_log_groups_per_flex) { |
2983 | ext4_group_t flex_group = ext4_flex_group(sbi, | 2989 | ext4_group_t flex_group = ext4_flex_group(sbi, |
@@ -4389,14 +4395,11 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle, | |||
4389 | /* | 4395 | /* |
4390 | * With delalloc we already reserved the blocks | 4396 | * With delalloc we already reserved the blocks |
4391 | */ | 4397 | */ |
4392 | ar->len = ext4_has_free_blocks(sbi, ar->len); | 4398 | if (ext4_claim_free_blocks(sbi, ar->len)) { |
4393 | } | 4399 | *errp = -ENOSPC; |
4394 | 4400 | return 0; | |
4395 | if (ar->len == 0) { | 4401 | } |
4396 | *errp = -ENOSPC; | ||
4397 | return 0; | ||
4398 | } | 4402 | } |
4399 | |||
4400 | while (ar->len && DQUOT_ALLOC_BLOCK(ar->inode, ar->len)) { | 4403 | while (ar->len && DQUOT_ALLOC_BLOCK(ar->inode, ar->len)) { |
4401 | ar->flags |= EXT4_MB_HINT_NOPREALLOC; | 4404 | ar->flags |= EXT4_MB_HINT_NOPREALLOC; |
4402 | ar->len--; | 4405 | ar->len--; |