diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ext4/balloc.c | 51 | ||||
-rw-r--r-- | fs/ext4/ext4.h | 2 | ||||
-rw-r--r-- | fs/ext4/mballoc.c | 7 |
3 files changed, 41 insertions, 19 deletions
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index 48787e86d438..25f63d8c1b3d 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c | |||
@@ -1599,23 +1599,35 @@ out: | |||
1599 | 1599 | ||
1600 | /** | 1600 | /** |
1601 | * ext4_has_free_blocks() | 1601 | * ext4_has_free_blocks() |
1602 | * @sbi: in-core super block structure. | 1602 | * @sbi: in-core super block structure. |
1603 | * @nblocks: number of neeed blocks | ||
1603 | * | 1604 | * |
1604 | * Check if filesystem has at least 1 free block available for allocation. | 1605 | * Check if filesystem has free blocks available for allocation. |
1606 | * Return the number of blocks avaible for allocation for this request | ||
1607 | * On success, return nblocks | ||
1605 | */ | 1608 | */ |
1606 | static int ext4_has_free_blocks(struct ext4_sb_info *sbi) | 1609 | ext4_fsblk_t ext4_has_free_blocks(struct ext4_sb_info *sbi, |
1610 | ext4_fsblk_t nblocks) | ||
1607 | { | 1611 | { |
1608 | ext4_fsblk_t free_blocks, root_blocks; | 1612 | ext4_fsblk_t free_blocks; |
1613 | ext4_fsblk_t root_blocks = 0; | ||
1609 | 1614 | ||
1610 | free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter); | 1615 | free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter); |
1611 | root_blocks = ext4_r_blocks_count(sbi->s_es); | 1616 | |
1612 | if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) && | 1617 | if (!capable(CAP_SYS_RESOURCE) && |
1613 | sbi->s_resuid != current->fsuid && | 1618 | sbi->s_resuid != current->fsuid && |
1614 | (sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) { | 1619 | (sbi->s_resgid == 0 || !in_group_p(sbi->s_resgid))) |
1615 | return 0; | 1620 | root_blocks = ext4_r_blocks_count(sbi->s_es); |
1616 | } | 1621 | #ifdef CONFIG_SMP |
1617 | return 1; | 1622 | if (free_blocks - root_blocks < FBC_BATCH) |
1618 | } | 1623 | free_blocks = |
1624 | percpu_counter_sum_positive(&sbi->s_freeblocks_counter); | ||
1625 | #endif | ||
1626 | if (free_blocks - root_blocks < nblocks) | ||
1627 | return free_blocks - root_blocks; | ||
1628 | return nblocks; | ||
1629 | } | ||
1630 | |||
1619 | 1631 | ||
1620 | /** | 1632 | /** |
1621 | * ext4_should_retry_alloc() | 1633 | * ext4_should_retry_alloc() |
@@ -1631,7 +1643,7 @@ static int ext4_has_free_blocks(struct ext4_sb_info *sbi) | |||
1631 | */ | 1643 | */ |
1632 | int ext4_should_retry_alloc(struct super_block *sb, int *retries) | 1644 | int ext4_should_retry_alloc(struct super_block *sb, int *retries) |
1633 | { | 1645 | { |
1634 | if (!ext4_has_free_blocks(EXT4_SB(sb)) || (*retries)++ > 3) | 1646 | if (!ext4_has_free_blocks(EXT4_SB(sb), 1) || (*retries)++ > 3) |
1635 | return 0; | 1647 | return 0; |
1636 | 1648 | ||
1637 | jbd_debug(1, "%s: retrying operation after ENOSPC\n", sb->s_id); | 1649 | jbd_debug(1, "%s: retrying operation after ENOSPC\n", sb->s_id); |
@@ -1681,13 +1693,21 @@ ext4_fsblk_t ext4_old_new_blocks(handle_t *handle, struct inode *inode, | |||
1681 | ext4_group_t ngroups; | 1693 | ext4_group_t ngroups; |
1682 | unsigned long num = *count; | 1694 | unsigned long num = *count; |
1683 | 1695 | ||
1684 | *errp = -ENOSPC; | ||
1685 | sb = inode->i_sb; | 1696 | sb = inode->i_sb; |
1686 | if (!sb) { | 1697 | if (!sb) { |
1698 | *errp = -ENODEV; | ||
1687 | printk("ext4_new_block: nonexistent device"); | 1699 | printk("ext4_new_block: nonexistent device"); |
1688 | return 0; | 1700 | return 0; |
1689 | } | 1701 | } |
1690 | 1702 | ||
1703 | sbi = EXT4_SB(sb); | ||
1704 | *count = ext4_has_free_blocks(sbi, *count); | ||
1705 | if (*count == 0) { | ||
1706 | *errp = -ENOSPC; | ||
1707 | return 0; /*return with ENOSPC error */ | ||
1708 | } | ||
1709 | num = *count; | ||
1710 | |||
1691 | /* | 1711 | /* |
1692 | * Check quota for allocation of this block. | 1712 | * Check quota for allocation of this block. |
1693 | */ | 1713 | */ |
@@ -1711,11 +1731,6 @@ ext4_fsblk_t ext4_old_new_blocks(handle_t *handle, struct inode *inode, | |||
1711 | if (block_i && ((windowsz = block_i->rsv_window_node.rsv_goal_size) > 0)) | 1731 | if (block_i && ((windowsz = block_i->rsv_window_node.rsv_goal_size) > 0)) |
1712 | my_rsv = &block_i->rsv_window_node; | 1732 | my_rsv = &block_i->rsv_window_node; |
1713 | 1733 | ||
1714 | if (!ext4_has_free_blocks(sbi)) { | ||
1715 | *errp = -ENOSPC; | ||
1716 | goto out; | ||
1717 | } | ||
1718 | |||
1719 | /* | 1734 | /* |
1720 | * First, test whether the goal block is free. | 1735 | * First, test whether the goal block is free. |
1721 | */ | 1736 | */ |
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index e622ade69d5c..2c4b48519c8b 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -979,6 +979,8 @@ extern ext4_fsblk_t ext4_new_blocks(handle_t *handle, struct inode *inode, | |||
979 | unsigned long *count, int *errp); | 979 | unsigned long *count, int *errp); |
980 | extern ext4_fsblk_t ext4_old_new_blocks(handle_t *handle, struct inode *inode, | 980 | extern ext4_fsblk_t ext4_old_new_blocks(handle_t *handle, struct inode *inode, |
981 | ext4_fsblk_t goal, unsigned long *count, int *errp); | 981 | ext4_fsblk_t goal, unsigned long *count, int *errp); |
982 | extern ext4_fsblk_t ext4_has_free_blocks(struct ext4_sb_info *sbi, | ||
983 | ext4_fsblk_t nblocks); | ||
982 | extern void ext4_free_blocks (handle_t *handle, struct inode *inode, | 984 | extern void ext4_free_blocks (handle_t *handle, struct inode *inode, |
983 | ext4_fsblk_t block, unsigned long count, int metadata); | 985 | ext4_fsblk_t block, unsigned long count, int metadata); |
984 | extern void ext4_free_blocks_sb (handle_t *handle, struct super_block *sb, | 986 | extern void ext4_free_blocks_sb (handle_t *handle, struct super_block *sb, |
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 816ba8cce79a..1666ac184e31 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c | |||
@@ -4045,6 +4045,12 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle, | |||
4045 | &(ar->len), errp); | 4045 | &(ar->len), errp); |
4046 | return block; | 4046 | return block; |
4047 | } | 4047 | } |
4048 | ar->len = ext4_has_free_blocks(sbi, ar->len); | ||
4049 | |||
4050 | if (ar->len == 0) { | ||
4051 | *errp = -ENOSPC; | ||
4052 | return 0; | ||
4053 | } | ||
4048 | 4054 | ||
4049 | while (ar->len && DQUOT_ALLOC_BLOCK(ar->inode, ar->len)) { | 4055 | while (ar->len && DQUOT_ALLOC_BLOCK(ar->inode, ar->len)) { |
4050 | ar->flags |= EXT4_MB_HINT_NOPREALLOC; | 4056 | ar->flags |= EXT4_MB_HINT_NOPREALLOC; |
@@ -4073,7 +4079,6 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle, | |||
4073 | 4079 | ||
4074 | ac->ac_op = EXT4_MB_HISTORY_PREALLOC; | 4080 | ac->ac_op = EXT4_MB_HISTORY_PREALLOC; |
4075 | if (!ext4_mb_use_preallocated(ac)) { | 4081 | if (!ext4_mb_use_preallocated(ac)) { |
4076 | |||
4077 | ac->ac_op = EXT4_MB_HISTORY_ALLOC; | 4082 | ac->ac_op = EXT4_MB_HISTORY_ALLOC; |
4078 | ext4_mb_normalize_request(ac, ar); | 4083 | ext4_mb_normalize_request(ac, ar); |
4079 | repeat: | 4084 | repeat: |