X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fext3%2Fballoc.c;h=3b3160d8e49a8af4881a649ad9d5a25a43eab0a3;hb=9bf4aaab3e101692164d49b7ca357651eb691cb6;hp=893b08bd5c1798a2375382dbc787222bcc1f9126;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c index 893b08bd5..3b3160d8e 100644 --- a/fs/ext3/balloc.c +++ b/fs/ext3/balloc.c @@ -19,6 +19,8 @@ #include #include #include +#include +#include /* * balloc.c contains the blocks allocation and deallocation routines @@ -275,8 +277,10 @@ do_more: error_return: brelse(bitmap_bh); ext3_std_error(sb, err); - if (dquot_freed_blocks) + if (dquot_freed_blocks) { + DLIMIT_FREE_BLOCK(sb, inode->i_xid, dquot_freed_blocks); DQUOT_FREE_BLOCK(inode, dquot_freed_blocks); + } return; } @@ -465,6 +469,50 @@ fail: return -1; } +static int ext3_has_free_blocks(struct super_block *sb) +{ + struct ext3_sb_info *sbi = EXT3_SB(sb); + int free_blocks, root_blocks, cond; + + free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter); + root_blocks = le32_to_cpu(sbi->s_es->s_r_blocks_count); + + vxdprintk(VXD_CBIT(dlim, 3), + "ext3_has_free_blocks(%p): free=%u, root=%u", + sb, free_blocks, root_blocks); + + DLIMIT_ADJUST_BLOCK(sb, vx_current_xid(), &free_blocks, &root_blocks); + + cond = (free_blocks < root_blocks + 1 && + !capable(CAP_SYS_RESOURCE) && + sbi->s_resuid != current->fsuid && + (sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))); + + vxdprintk(VXD_CBIT(dlim, 3), + "ext3_has_free_blocks(%p): %u<%u+1, %c, %u!=%u r=%d", + sb, free_blocks, root_blocks, + !capable(CAP_SYS_RESOURCE)?'1':'0', + sbi->s_resuid, current->fsuid, cond?0:1); + + return (cond ? 0 : 1); +} + +/* + * ext3_should_retry_alloc() is called when ENOSPC is returned, and if + * it is profitable to retry the operation, this function will wait + * for the current or commiting transaction to complete, and then + * return TRUE. + */ +int ext3_should_retry_alloc(struct super_block *sb, int *retries) +{ + if (!ext3_has_free_blocks(sb) || (*retries)++ > 3) + return 0; + + jbd_debug(1, "%s: retrying operation after ENOSPC\n", sb->s_id); + + return journal_force_commit_nested(EXT3_SB(sb)->s_journal); +} + /* * ext3_new_block uses a goal block to assist allocation. If the goal is * free, or there is a free block within 32 blocks of the goal, that block @@ -485,7 +533,7 @@ ext3_new_block(handle_t *handle, struct inode *inode, unsigned long goal, int target_block; /* tmp */ int fatal = 0, err; int performed_allocation = 0; - int free_blocks, root_blocks; + int free_blocks; struct super_block *sb; struct ext3_group_desc *gdp; struct ext3_super_block *es; @@ -507,16 +555,14 @@ ext3_new_block(handle_t *handle, struct inode *inode, unsigned long goal, *errp = -EDQUOT; return 0; } + if (DLIMIT_ALLOC_BLOCK(sb, inode->i_xid, 1)) + goto out_dlimit; sbi = EXT3_SB(sb); es = EXT3_SB(sb)->s_es; ext3_debug("goal=%lu.\n", goal); - free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter); - root_blocks = le32_to_cpu(es->s_r_blocks_count); - if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) && - sbi->s_resuid != current->fsuid && - (sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) { + if (!ext3_has_free_blocks(sb)) { *errp = -ENOSPC; goto out; } @@ -671,6 +717,9 @@ allocated: io_error: *errp = -EIO; out: + if (!performed_allocation) + DLIMIT_FREE_BLOCK(sb, inode->i_xid, 1); +out_dlimit: if (fatal) { *errp = fatal; ext3_std_error(sb, fatal);