X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fext3%2Fballoc.c;h=3b3160d8e49a8af4881a649ad9d5a25a43eab0a3;hb=9bf4aaab3e101692164d49b7ca357651eb691cb6;hp=bff5a0ddaa96caedd867dffbe832ef61d41419ff;hpb=db216c3d5e4c040e557a50f8f5d35d5c415e8c1c;p=linux-2.6.git diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c index bff5a0dda..3b3160d8e 100644 --- a/fs/ext3/balloc.c +++ b/fs/ext3/balloc.c @@ -19,6 +19,7 @@ #include #include #include +#include #include /* @@ -468,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 @@ -488,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; @@ -517,14 +562,7 @@ ext3_new_block(handle_t *handle, struct inode *inode, unsigned long goal, 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); - - DLIMIT_ADJUST_BLOCK(sb, vx_current_xid(), &free_blocks, &root_blocks); - - 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; } @@ -679,7 +717,8 @@ allocated: io_error: *errp = -EIO; out: - DLIMIT_FREE_BLOCK(sb, inode->i_xid, 1); + if (!performed_allocation) + DLIMIT_FREE_BLOCK(sb, inode->i_xid, 1); out_dlimit: if (fatal) { *errp = fatal; @@ -688,10 +727,8 @@ out_dlimit: /* * Undo the block allocation */ - if (!performed_allocation) { - DLIMIT_FREE_BLOCK(sb, inode->i_xid, 1); + if (!performed_allocation) DQUOT_FREE_BLOCK(inode, 1); - } brelse(bitmap_bh); return 0; }