diff options
Diffstat (limited to 'fs/ext4/balloc.c')
-rw-r--r-- | fs/ext4/balloc.c | 51 |
1 files changed, 33 insertions, 18 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 | */ |