For an appending write, ext3_commit_write() will call the expensive ext3_mark_inode_dirty() twice. Once in generic_commit_write()'s extension of i_size and once in ext3_commit_write() itself where i_disksize is updated. But by updating i_disksize _before_ calling generic_commit_write() these can be piggybacked. The patch takes the overhead of a write() from 1.96 microseconds down to 1.63. fs/ext3/inode.c | 24 +++++++++++++++++------- 1 files changed, 17 insertions(+), 7 deletions(-) diff -puN fs/ext3/inode.c~ext3_mark_inode_dirty-less-calls fs/ext3/inode.c --- 25/fs/ext3/inode.c~ext3_mark_inode_dirty-less-calls 2003-04-02 22:51:41.000000000 -0800 +++ 25-akpm/fs/ext3/inode.c 2003-04-02 22:51:41.000000000 -0800 @@ -1165,6 +1165,12 @@ static int ext3_commit_write(struct file if (pos > inode->i_size) inode->i_size = pos; EXT3_I(inode)->i_state |= EXT3_STATE_JDATA; + if (inode->i_size > EXT3_I(inode)->i_disksize) { + EXT3_I(inode)->i_disksize = inode->i_size; + ret2 = ext3_mark_inode_dirty(handle, inode); + if (!ret) + ret = ret2; + } } else { if (ext3_should_order_data(inode)) { ret = walk_page_buffers(handle, page_buffers(page), @@ -1172,14 +1178,18 @@ static int ext3_commit_write(struct file } /* Be careful here if generic_commit_write becomes a * required invocation after block_prepare_write. */ - if (ret == 0) + if (ret == 0) { + /* + * generic_commit_write() will run mark_inode_dirty() + * if i_size changes. So let's piggyback the + * i_disksize mark_inode_dirty into that. + */ + loff_t new_i_size = + ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; + if (new_i_size > EXT3_I(inode)->i_disksize) + EXT3_I(inode)->i_disksize = new_i_size; ret = generic_commit_write(file, page, from, to); - } - if (inode->i_size > EXT3_I(inode)->i_disksize) { - EXT3_I(inode)->i_disksize = inode->i_size; - ret2 = ext3_mark_inode_dirty(handle, inode); - if (!ret) - ret = ret2; + } } ret2 = ext3_journal_stop(handle); unlock_kernel(); _