diff options
Diffstat (limited to 'fs/ext4/balloc.c')
| -rw-r--r-- | fs/ext4/balloc.c | 77 |
1 files changed, 27 insertions, 50 deletions
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index b9821be709bd..d2003cdc36aa 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c | |||
| @@ -589,21 +589,23 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode, | |||
| 589 | return; | 589 | return; |
| 590 | } | 590 | } |
| 591 | 591 | ||
| 592 | int ext4_claim_free_blocks(struct ext4_sb_info *sbi, | 592 | /** |
| 593 | s64 nblocks) | 593 | * ext4_has_free_blocks() |
| 594 | * @sbi: in-core super block structure. | ||
| 595 | * @nblocks: number of needed blocks | ||
| 596 | * | ||
| 597 | * Check if filesystem has nblocks free & available for allocation. | ||
| 598 | * On success return 1, return 0 on failure. | ||
| 599 | */ | ||
| 600 | int ext4_has_free_blocks(struct ext4_sb_info *sbi, s64 nblocks) | ||
| 594 | { | 601 | { |
| 595 | s64 free_blocks, dirty_blocks; | 602 | s64 free_blocks, dirty_blocks, root_blocks; |
| 596 | s64 root_blocks = 0; | ||
| 597 | struct percpu_counter *fbc = &sbi->s_freeblocks_counter; | 603 | struct percpu_counter *fbc = &sbi->s_freeblocks_counter; |
| 598 | struct percpu_counter *dbc = &sbi->s_dirtyblocks_counter; | 604 | struct percpu_counter *dbc = &sbi->s_dirtyblocks_counter; |
| 599 | 605 | ||
| 600 | free_blocks = percpu_counter_read_positive(fbc); | 606 | free_blocks = percpu_counter_read_positive(fbc); |
| 601 | dirty_blocks = percpu_counter_read_positive(dbc); | 607 | dirty_blocks = percpu_counter_read_positive(dbc); |
| 602 | 608 | root_blocks = ext4_r_blocks_count(sbi->s_es); | |
| 603 | if (!capable(CAP_SYS_RESOURCE) && | ||
| 604 | sbi->s_resuid != current->fsuid && | ||
| 605 | (sbi->s_resgid == 0 || !in_group_p(sbi->s_resgid))) | ||
| 606 | root_blocks = ext4_r_blocks_count(sbi->s_es); | ||
| 607 | 609 | ||
| 608 | if (free_blocks - (nblocks + root_blocks + dirty_blocks) < | 610 | if (free_blocks - (nblocks + root_blocks + dirty_blocks) < |
| 609 | EXT4_FREEBLOCKS_WATERMARK) { | 611 | EXT4_FREEBLOCKS_WATERMARK) { |
| @@ -616,57 +618,32 @@ int ext4_claim_free_blocks(struct ext4_sb_info *sbi, | |||
| 616 | } | 618 | } |
| 617 | } | 619 | } |
| 618 | /* Check whether we have space after | 620 | /* Check whether we have space after |
| 619 | * accounting for current dirty blocks | 621 | * accounting for current dirty blocks & root reserved blocks. |
| 620 | */ | 622 | */ |
| 621 | if (free_blocks < ((root_blocks + nblocks) + dirty_blocks)) | 623 | if (free_blocks >= ((root_blocks + nblocks) + dirty_blocks)) |
| 622 | /* we don't have free space */ | 624 | return 1; |
| 623 | return -ENOSPC; | 625 | |
| 626 | /* Hm, nope. Are (enough) root reserved blocks available? */ | ||
| 627 | if (sbi->s_resuid == current->fsuid || | ||
| 628 | ((sbi->s_resgid != 0) && in_group_p(sbi->s_resgid)) || | ||
| 629 | capable(CAP_SYS_RESOURCE)) { | ||
| 630 | if (free_blocks >= (nblocks + dirty_blocks)) | ||
| 631 | return 1; | ||
| 632 | } | ||
| 624 | 633 | ||
| 625 | /* Add the blocks to nblocks */ | ||
| 626 | percpu_counter_add(dbc, nblocks); | ||
| 627 | return 0; | 634 | return 0; |
| 628 | } | 635 | } |
| 629 | 636 | ||
| 630 | /** | 637 | int ext4_claim_free_blocks(struct ext4_sb_info *sbi, |
| 631 | * ext4_has_free_blocks() | ||
| 632 | * @sbi: in-core super block structure. | ||
| 633 | * @nblocks: number of neeed blocks | ||
| 634 | * | ||
| 635 | * Check if filesystem has free blocks available for allocation. | ||
| 636 | * Return the number of blocks avaible for allocation for this request | ||
| 637 | * On success, return nblocks | ||
| 638 | */ | ||
| 639 | ext4_fsblk_t ext4_has_free_blocks(struct ext4_sb_info *sbi, | ||
| 640 | s64 nblocks) | 638 | s64 nblocks) |
| 641 | { | 639 | { |
| 642 | s64 free_blocks, dirty_blocks; | 640 | if (ext4_has_free_blocks(sbi, nblocks)) { |
| 643 | s64 root_blocks = 0; | 641 | percpu_counter_add(&sbi->s_dirtyblocks_counter, nblocks); |
| 644 | struct percpu_counter *fbc = &sbi->s_freeblocks_counter; | ||
| 645 | struct percpu_counter *dbc = &sbi->s_dirtyblocks_counter; | ||
| 646 | |||
| 647 | free_blocks = percpu_counter_read_positive(fbc); | ||
| 648 | dirty_blocks = percpu_counter_read_positive(dbc); | ||
| 649 | |||
| 650 | if (!capable(CAP_SYS_RESOURCE) && | ||
| 651 | sbi->s_resuid != current->fsuid && | ||
| 652 | (sbi->s_resgid == 0 || !in_group_p(sbi->s_resgid))) | ||
| 653 | root_blocks = ext4_r_blocks_count(sbi->s_es); | ||
| 654 | |||
| 655 | if (free_blocks - (nblocks + root_blocks + dirty_blocks) < | ||
| 656 | EXT4_FREEBLOCKS_WATERMARK) { | ||
| 657 | free_blocks = percpu_counter_sum(fbc); | ||
| 658 | dirty_blocks = percpu_counter_sum(dbc); | ||
| 659 | } | ||
| 660 | if (free_blocks <= (root_blocks + dirty_blocks)) | ||
| 661 | /* we don't have free space */ | ||
| 662 | return 0; | 642 | return 0; |
| 663 | 643 | } else | |
| 664 | if (free_blocks - (root_blocks + dirty_blocks) < nblocks) | 644 | return -ENOSPC; |
| 665 | return free_blocks - (root_blocks + dirty_blocks); | ||
| 666 | return nblocks; | ||
| 667 | } | 645 | } |
| 668 | 646 | ||
| 669 | |||
| 670 | /** | 647 | /** |
| 671 | * ext4_should_retry_alloc() | 648 | * ext4_should_retry_alloc() |
| 672 | * @sb: super block | 649 | * @sb: super block |
