Juggle dirty pages and dirty inodes and dirty superblocks and various different writeback modes and livelock avoidance and fairness to recover from the loss of mapping->io_pages. --- 25-akpm/fs/fs-writeback.c | 50 +++++++++++++++++++++++++++++++++------------- 1 files changed, 36 insertions(+), 14 deletions(-) diff -puN fs/fs-writeback.c~kupdate-function-fix fs/fs-writeback.c --- 25/fs/fs-writeback.c~kupdate-function-fix 2004-04-03 03:00:12.654307808 -0800 +++ 25-akpm/fs/fs-writeback.c 2004-04-03 03:00:12.657307352 -0800 @@ -147,12 +147,6 @@ __sync_single_inode(struct inode *inode, inode->i_state |= I_LOCK; inode->i_state &= ~I_DIRTY; - /* - * smp_rmb(); note: if you remove write_lock below, you must add this. - * mark_inode_dirty doesn't take spinlock, make sure that inode is not - * read speculatively by this cpu before &= ~I_DIRTY -- mikulas - */ - spin_unlock(&inode_lock); ret = do_writepages(mapping, wbc); @@ -170,18 +164,46 @@ __sync_single_inode(struct inode *inode, spin_lock(&inode_lock); inode->i_state &= ~I_LOCK; if (!(inode->i_state & I_FREEING)) { - if (mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) { - /* Redirtied */ - inode->i_state |= I_DIRTY_PAGES; - inode->dirtied_when = jiffies; - list_move(&inode->i_list, &sb->s_dirty); + if (!(inode->i_state & I_DIRTY) && + mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) { + /* + * We didn't write back all the pages. Redirty the + * inode. It is still on sb->s_dirty. + */ + if (wbc->for_kupdate) { + /* + * For the kupdate function we leave the inode + * where it is on sb_dirty so it will get more + * writeout as soon as the queue becomes + * uncongested. + */ + inode->i_state |= I_DIRTY_PAGES; + } else { + /* + * Otherwise fully redirty the inode so that + * other inodes on this superblock will get some + * writeout. Otherwise heavy writing to one + * file would indefinitely suspend writeout of + * all the other files. + */ + inode->i_state |= I_DIRTY_PAGES; + inode->dirtied_when = jiffies; + list_move(&inode->i_list, &sb->s_dirty); + } } else if (inode->i_state & I_DIRTY) { - /* Redirtied */ - inode->dirtied_when = jiffies; - list_move(&inode->i_list, &sb->s_dirty); + /* + * Someone redirtied the inode while were writing back + * the pages: nothing to do. + */ } else if (atomic_read(&inode->i_count)) { + /* + * The inode is clean, inuse + */ list_move(&inode->i_list, &inode_in_use); } else { + /* + * The inode is clean, unused + */ list_move(&inode->i_list, &inode_unused); } } _