diff options
Diffstat (limited to 'fs/ext4/balloc.c')
-rw-r--r-- | fs/ext4/balloc.c | 62 |
1 files changed, 40 insertions, 22 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)); |