X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Ffs-writeback.c;h=da522d511f2d149e370d15239a016eeed26fbda6;hb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;hp=5f3ccf9890531a6a4f23cb7d7293def4155179eb;hpb=9213980e6a70d8473e0ffd4b39ab5b6caaba9ff5;p=linux-2.6.git diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 5f3ccf989..da522d511 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -133,10 +133,11 @@ out: EXPORT_SYMBOL(__mark_inode_dirty); -static void write_inode(struct inode *inode, int sync) +static int write_inode(struct inode *inode, int sync) { if (inode->i_sb->s_op->write_inode && !is_bad_inode(inode)) - inode->i_sb->s_op->write_inode(inode, sync); + return inode->i_sb->s_op->write_inode(inode, sync); + return 0; } /* @@ -170,8 +171,11 @@ __sync_single_inode(struct inode *inode, struct writeback_control *wbc) ret = do_writepages(mapping, wbc); /* Don't write the inode if only I_DIRTY_PAGES was set */ - if (dirty & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) - write_inode(inode, wait); + if (dirty & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) { + int err = write_inode(inode, wait); + if (ret == 0) + ret = err; + } if (wait) { int err = filemap_fdatawait(mapping); @@ -213,8 +217,9 @@ __sync_single_inode(struct inode *inode, struct writeback_control *wbc) } else if (inode->i_state & I_DIRTY) { /* * Someone redirtied the inode while were writing back - * the pages: nothing to do. + * the pages. */ + list_move(&inode->i_list, &sb->s_dirty); } else if (atomic_read(&inode->i_count)) { /* * The inode is clean, inuse @@ -225,6 +230,7 @@ __sync_single_inode(struct inode *inode, struct writeback_control *wbc) * The inode is clean, unused */ list_move(&inode->i_list, &inode_unused); + inodes_stat.nr_unused++; } } wake_up_inode(inode); @@ -302,14 +308,20 @@ sync_sb_inodes(struct super_block *sb, struct writeback_control *wbc) long pages_skipped; if (bdi->memory_backed) { + list_move(&inode->i_list, &sb->s_dirty); if (sb == blockdev_superblock) { /* * Dirty memory-backed blockdev: the ramdisk - * driver does this. + * driver does this. Skip just this inode */ - list_move(&inode->i_list, &sb->s_dirty); continue; } + /* + * Dirty memory-backed inode against a filesystem other + * than the kernel-internal bdev filesystem. Skip the + * entire superblock. + */ + break; } if (wbc->nonblocking && bdi_write_congested(bdi)) { @@ -390,7 +402,7 @@ writeback_inodes(struct writeback_control *wbc) { struct super_block *sb; - spin_lock(&inode_lock); + might_sleep(); spin_lock(&sb_lock); restart: sb = sb_entry(super_blocks.prev); @@ -405,19 +417,21 @@ restart: * be unmounted by the time it is released. */ if (down_read_trylock(&sb->s_umount)) { - if (sb->s_root) + if (sb->s_root) { + spin_lock(&inode_lock); sync_sb_inodes(sb, wbc); + spin_unlock(&inode_lock); + } up_read(&sb->s_umount); } spin_lock(&sb_lock); - if (__put_super(sb)) + if (__put_super_and_need_restart(sb)) goto restart; } if (wbc->nr_to_write <= 0) break; } spin_unlock(&sb_lock); - spin_unlock(&inode_lock); } /* @@ -545,6 +559,7 @@ void write_inode_now(struct inode *inode, int sync) if (inode->i_mapping->backing_dev_info->memory_backed) return; + might_sleep(); spin_lock(&inode_lock); __writeback_single_inode(inode, &wbc); spin_unlock(&inode_lock);