diff options
Diffstat (limited to 'fs/ext4')
-rw-r--r-- | fs/ext4/balloc.c | 8 | ||||
-rw-r--r-- | fs/ext4/inode.c | 14 | ||||
-rw-r--r-- | fs/ext4/mballoc.c | 7 |
3 files changed, 24 insertions, 5 deletions
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index 1707850301d..57909882c08 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -1738,10 +1738,16 @@ ext4_fsblk_t ext4_old_new_blocks(handle_t *handle, struct inode *inode, /* * With delalloc we already reserved the blocks */ - if (ext4_claim_free_blocks(sbi, *count)) { + while (*count && ext4_claim_free_blocks(sbi, *count)) { + /* let others to free the space */ + yield(); + *count = *count >> 1; + } + if (!*count) { *errp = -ENOSPC; return 0; /*return with ENOSPC error */ } + num = *count; } /* * Check quota for allocation of this block. diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index b778d5a33ea..eb9d449817d 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -1521,6 +1521,7 @@ static int ext4_journalled_write_end(struct file *file, static int ext4_da_reserve_space(struct inode *inode, int nrblocks) { + int retries = 0; struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); unsigned long md_needed, mdblocks, total = 0; @@ -1529,6 +1530,7 @@ static int ext4_da_reserve_space(struct inode *inode, int nrblocks) * in order to allocate nrblocks * worse case is one extent per block */ +repeat: spin_lock(&EXT4_I(inode)->i_block_reservation_lock); total = EXT4_I(inode)->i_reserved_data_blocks + nrblocks; mdblocks = ext4_calc_metadata_amount(inode, total); @@ -1539,6 +1541,10 @@ static int ext4_da_reserve_space(struct inode *inode, int nrblocks) if (ext4_claim_free_blocks(sbi, total)) { spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); + if (ext4_should_retry_alloc(inode->i_sb, &retries)) { + yield(); + goto repeat; + } return -ENOSPC; } EXT4_I(inode)->i_reserved_data_blocks += nrblocks; @@ -1825,20 +1831,18 @@ static void ext4_da_block_invalidatepages(struct mpage_da_data *mpd, static int mpage_da_map_blocks(struct mpage_da_data *mpd) { int err = 0; + struct buffer_head new; struct buffer_head *lbh = &mpd->lbh; sector_t next = lbh->b_blocknr; - struct buffer_head new; /* * We consider only non-mapped and non-allocated blocks */ if (buffer_mapped(lbh) && !buffer_delay(lbh)) return 0; - new.b_state = lbh->b_state; new.b_blocknr = 0; new.b_size = lbh->b_size; - /* * If we didn't accumulate anything * to write simply return @@ -1871,6 +1875,10 @@ static int mpage_da_map_blocks(struct mpage_da_data *mpd) lbh->b_size >> mpd->inode->i_blkbits, err); printk(KERN_EMERG "This should not happen.!! " "Data will be lost\n"); + if (err == -ENOSPC) { + printk(KERN_CRIT "Total free blocks count %lld\n", + ext4_count_free_blocks(mpd->inode->i_sb)); + } /* invlaidate all the pages */ ext4_da_block_invalidatepages(mpd, next, lbh->b_size >> mpd->inode->i_blkbits); diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 2c10b5058a8..e4f30de11a9 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -4395,7 +4395,12 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle, /* * With delalloc we already reserved the blocks */ - if (ext4_claim_free_blocks(sbi, ar->len)) { + while (ar->len && ext4_claim_free_blocks(sbi, ar->len)) { + /* let others to free the space */ + yield(); + ar->len = ar->len >> 1; + } + if (!ar->len) { *errp = -ENOSPC; return 0; } |