diff -ru lum-2.4.18-um30/fs/ext3/balloc.c uml-2.4.18-12.5/fs/ext3/balloc.c --- lum-2.4.18-um30/fs/ext3/balloc.c Mon Feb 25 12:38:08 2002 +++ uml-2.4.18-12.5/fs/ext3/balloc.c Thu Sep 19 13:40:11 2002 @@ -276,7 +276,8 @@ } lock_super (sb); es = sb->u.ext3_sb.s_es; - if (block < le32_to_cpu(es->s_first_data_block) || + if (block < le32_to_cpu(es->s_first_data_block) || + block + count < block || (block + count) > le32_to_cpu(es->s_blocks_count)) { ext3_error (sb, "ext3_free_blocks", "Freeing blocks not in datazone - " @@ -309,17 +310,6 @@ if (!gdp) goto error_return; - if (in_range (le32_to_cpu(gdp->bg_block_bitmap), block, count) || - in_range (le32_to_cpu(gdp->bg_inode_bitmap), block, count) || - in_range (block, le32_to_cpu(gdp->bg_inode_table), - sb->u.ext3_sb.s_itb_per_group) || - in_range (block + count - 1, le32_to_cpu(gdp->bg_inode_table), - sb->u.ext3_sb.s_itb_per_group)) - ext3_error (sb, "ext3_free_blocks", - "Freeing blocks in system zones - " - "Block = %lu, count = %lu", - block, count); - /* * We are about to start releasing blocks in the bitmap, * so we need undo access. @@ -345,14 +335,24 @@ if (err) goto error_return; - for (i = 0; i < count; i++) { + for (i = 0; i < count; i++, block++) { + if (block == le32_to_cpu(gdp->bg_block_bitmap) || + block == le32_to_cpu(gdp->bg_inode_bitmap) || + in_range(block, le32_to_cpu(gdp->bg_inode_table), + sb->u.ext2_sb.s_itb_per_group)) { + ext3_error(sb, __FUNCTION__, + "Freeing block in system zone - block = %lu", + block); + continue; + } + /* * An HJ special. This is expensive... */ #ifdef CONFIG_JBD_DEBUG { struct buffer_head *debug_bh; - debug_bh = sb_get_hash_table(sb, block + i); + debug_bh = sb_get_hash_table(sb, block); if (debug_bh) { BUFFER_TRACE(debug_bh, "Deleted!"); if (!bh2jh(bitmap_bh)->b_committed_data) @@ -365,9 +365,8 @@ #endif BUFFER_TRACE(bitmap_bh, "clear bit"); if (!ext3_clear_bit (bit + i, bitmap_bh->b_data)) { - ext3_error (sb, __FUNCTION__, - "bit already cleared for block %lu", - block + i); + ext3_error(sb, __FUNCTION__, + "bit already cleared for block %lu", block); BUFFER_TRACE(bitmap_bh, "bit already cleared"); } else { dquot_freed_blocks++; @@ -415,7 +417,6 @@ if (!err) err = ret; if (overflow && !err) { - block += count; count = overflow; goto do_more; } @@ -575,6 +577,7 @@ ext3_debug ("goal=%lu.\n", goal); +repeat: /* * First, test whether the goal block is free. */ @@ -684,10 +686,21 @@ if (tmp == le32_to_cpu(gdp->bg_block_bitmap) || tmp == le32_to_cpu(gdp->bg_inode_bitmap) || in_range (tmp, le32_to_cpu(gdp->bg_inode_table), - sb->u.ext3_sb.s_itb_per_group)) - ext3_error (sb, "ext3_new_block", - "Allocating block in system zone - " - "block = %u", tmp); + EXT3_SB(sb)->s_itb_per_group)) { + ext3_error(sb, __FUNCTION__, + "Allocating block in system zone - block = %u", tmp); + + /* Note: This will potentially use up one of the handle's + * buffer credits. Normally we have way too many credits, + * so that is OK. In _very_ rare cases it might not be OK. + * We will trigger an assertion if we run out of credits, + * and we will have to do a full fsck of the filesystem - + * better than randomly corrupting filesystem metadata. + */ + ext3_set_bit(j, bh->b_data); + goto repeat; + } + /* The superblock lock should guard against anybody else beating * us to this point! */ diff -ru lum-2.4.18-um30/fs/ext3/namei.c uml-2.4.18-12.5/fs/ext3/namei.c --- lum-2.4.18-um30/fs/ext3/namei.c Fri Nov 9 15:25:04 2001 +++ uml-2.4.18-12.5/fs/ext3/namei.c Thu Sep 19 13:40:11 2002 @@ -354,8 +355,8 @@ */ dir->i_mtime = dir->i_ctime = CURRENT_TIME; dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL; - ext3_mark_inode_dirty(handle, dir); dir->i_version = ++event; + ext3_mark_inode_dirty(handle, dir); BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); ext3_journal_dirty_metadata(handle, bh); brelse(bh); @@ -464,8 +465,8 @@ inode->i_op = &ext3_file_inode_operations; inode->i_fop = &ext3_file_operations; inode->i_mapping->a_ops = &ext3_aops; - ext3_mark_inode_dirty(handle, inode); err = ext3_add_nondir(handle, dentry, inode); + ext3_mark_inode_dirty(handle, inode); } ext3_journal_stop(handle, dir); return err; @@ -489,8 +490,8 @@ err = PTR_ERR(inode); if (!IS_ERR(inode)) { init_special_inode(inode, mode, rdev); - ext3_mark_inode_dirty(handle, inode); err = ext3_add_nondir(handle, dentry, inode); + ext3_mark_inode_dirty(handle, inode); } ext3_journal_stop(handle, dir); return err; @@ -933,8 +934,8 @@ inode->i_size = l-1; } inode->u.ext3_i.i_disksize = inode->i_size; - ext3_mark_inode_dirty(handle, inode); err = ext3_add_nondir(handle, dentry, inode); + ext3_mark_inode_dirty(handle, inode); out_stop: ext3_journal_stop(handle, dir); return err; @@ -970,8 +971,8 @@ ext3_inc_count(handle, inode); atomic_inc(&inode->i_count); - ext3_mark_inode_dirty(handle, inode); err = ext3_add_nondir(handle, dentry, inode); + ext3_mark_inode_dirty(handle, inode); ext3_journal_stop(handle, dir); return err; }