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; } @@ -542,6 +543,7 @@ int i, j, k, tmp, alloctmp; int bitmap_nr; int fatal = 0, err; + int performed_allocation = 0; struct super_block * sb; struct ext3_group_desc * gdp; struct ext3_super_block * es; @@ -575,6 +577,7 @@ ext3_debug ("goal=%lu.\n", goal); +repeat: /* * First, test whether the goal block is free. */ @@ -644,8 +647,7 @@ } /* No space left on the device */ - unlock_super (sb); - return 0; + goto out; search_back: /* @@ -684,16 +686,28 @@ 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! */ J_ASSERT_BH(bh, !ext3_test_bit(j, bh->b_data)); BUFFER_TRACE(bh, "setting bitmap bit"); ext3_set_bit(j, bh->b_data); + performed_allocation = 1; #ifdef CONFIG_JBD_DEBUG { @@ -815,6 +829,11 @@ ext3_std_error(sb, fatal); } unlock_super (sb); + /* + * Undo the block allocation + */ + if (!performed_allocation) + DQUOT_FREE_BLOCK(inode, 1); return 0; } diff -ru lum-2.4.18-um30/fs/ext3/file.c uml-2.4.18-12.5/fs/ext3/file.c --- lum-2.4.18-um30/fs/ext3/file.c Thu Nov 15 14:37:55 2001 +++ uml-2.4.18-12.5/fs/ext3/file.c Thu Sep 19 13:40:11 2002 @@ -61,19 +61,52 @@ static ssize_t ext3_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { + int ret, err; struct inode *inode = file->f_dentry->d_inode; - /* - * Nasty: if the file is subject to synchronous writes then we need - * to force generic_osync_inode() to call ext3_write_inode(). - * We do that by marking the inode dirty. This adds much more - * computational expense than we need, but we're going to sync - * anyway. - */ - if (IS_SYNC(inode) || (file->f_flags & O_SYNC)) - mark_inode_dirty(inode); + ret = generic_file_write(file, buf, count, ppos); - return generic_file_write(file, buf, count, ppos); + /* Skip file flushing code if there was an error, or if nothing + was written. */ + if (ret <= 0) + return ret; + + /* If the inode is IS_SYNC, or is O_SYNC and we are doing + data-journaling, then we need to make sure that we force the + transaction to disk to keep all metadata uptodate + synchronously. */ + + if (file->f_flags & O_SYNC) { + /* If we are non-data-journaled, then the dirty data has + already been flushed to backing store by + generic_osync_inode, and the inode has been flushed + too if there have been any modifications other than + mere timestamp updates. + + Open question --- do we care about flushing + timestamps too if the inode is IS_SYNC? */ + if (!ext3_should_journal_data(inode)) + return ret; + + goto force_commit; + } + + /* So we know that there has been no forced data flush. If the + inode is marked IS_SYNC, we need to force one ourselves. */ + if (!IS_SYNC(inode)) + return ret; + + /* Open question #2 --- should we force data to disk here too? + If we don't, the only impact is that data=writeback + filesystems won't flush data to disk automatically on + IS_SYNC, only metadata (but historically, that is what ext2 + has done.) */ + +force_commit: + err = ext3_force_commit(inode->i_sb); + if (err) + return err; + return ret; } struct file_operations ext3_file_operations = { diff -ru lum-2.4.18-um30/fs/ext3/fsync.c uml-2.4.18-12.5/fs/ext3/fsync.c --- lum-2.4.18-um30/fs/ext3/fsync.c Tue Nov 20 22:34:13 2001 +++ uml-2.4.18-12.5/fs/ext3/fsync.c Thu Sep 19 13:40:11 2002 @@ -62,7 +62,12 @@ * we'll end up waiting on them in commit. */ ret = fsync_inode_buffers(inode); - ret |= fsync_inode_data_buffers(inode); + + /* In writeback mode, we need to force out data buffers too. In + * the other modes, ext3_force_commit takes care of forcing out + * just the right data blocks. */ + if (test_opt(inode->i_sb, DATA_FLAGS) == EXT3_MOUNT_WRITEBACK_DATA) + ret |= fsync_inode_data_buffers(inode); ext3_force_commit(inode->i_sb); diff -ru lum-2.4.18-um30/fs/ext3/ialloc.c uml-2.4.18-12.5/fs/ext3/ialloc.c --- lum-2.4.18-um30/fs/ext3/ialloc.c Mon Feb 25 12:38:08 2002 +++ uml-2.4.18-12.5/fs/ext3/ialloc.c Thu Sep 19 13:40:11 2002 @@ -392,7 +392,7 @@ err = -ENOSPC; if (!gdp) - goto fail; + goto out; err = -EIO; bitmap_nr = load_inode_bitmap (sb, i); @@ -523,9 +523,10 @@ return inode; fail: + ext3_std_error(sb, err); +out: unlock_super(sb); iput(inode); - ext3_std_error(sb, err); return ERR_PTR(err); } diff -ru lum-2.4.18-um30/fs/ext3/inode.c uml-2.4.18-12.5/fs/ext3/inode.c --- lum-2.4.18-um30/fs/ext3/inode.c Mon Feb 25 12:38:08 2002 +++ uml-2.4.18-12.5/fs/ext3/inode.c Thu Sep 19 13:40:11 2002 @@ -412,6 +412,7 @@ return NULL; changed: + brelse(bh); *err = -EAGAIN; goto no_block; failure: @@ -581,8 +582,6 @@ parent = nr; } - if (IS_SYNC(inode)) - handle->h_sync = 1; } if (n == num) return 0; @@ -1015,8 +1018,8 @@ unsigned from, unsigned to) { struct inode *inode = page->mapping->host; - handle_t *handle = ext3_journal_current_handle(); int ret, needed_blocks = ext3_writepage_trans_blocks(inode); + handle_t *handle; lock_kernel(); handle = ext3_journal_start(inode, needed_blocks); 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; } diff -ru lum-2.4.18-um30/fs/ext3/super.c uml-2.4.18-12.5/fs/ext3/super.c --- lum-2.4.18-um30/fs/ext3/super.c Fri Jul 12 17:59:37 2002 +++ uml-2.4.18-12.5/fs/ext3/super.c Thu Sep 19 13:40:11 2002 @@ -1589,8 +1589,10 @@ journal_t *journal = EXT3_SB(sb)->s_journal; /* Now we set up the journal barrier. */ + unlock_super(sb); journal_lock_updates(journal); journal_flush(journal); + lock_super(sb); /* Journal blocked and flushed, clear needs_recovery flag. */ EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER);