BUG in writeback_inodes()?

From: Kirill Korotaev
Date: Mon Sep 13 2004 - 11:02:24 EST


Hello All,

It looks like there is a small race bug in writeback_inodes()
Have a look at this 2 call chains:

writeback_inodes()
{
....
sb->s_count++;
spin_unlock(&sb_lock);
....
spin_lock(&sb_lock);
if (__put_super(sb)) <<< X
goto restart;
}
}

deactivate_super()
{
fs->kill_sb(s);
kill_block_super(sb)
generic_shutdown_super(sb)
spin_lock(&sb_lock);
list_del(&sb->s_list); <<< Y
spin_unlock(&sb_lock);
....
put_super(s);
spin_lock(&sb_lock);
__put_super(sb); <<< Z
spin_unlock(&sb_lock);
}

The problem with it is that writeback_inodes() supposes that if __put_super() returns 0 then no super block was deleted from the list and we can safely traverse sb list further.

But as it is obvious from the deactivate_super() it's not actually true. because at point Y we delete super block from the list and drop the lock. We do __put_super() very much later... So we can find sb with poisoned sb->s_list at point X and we won't be the last sb reference holders. The last reference will be dropped in point Z.

So in case of the following sequence of execution Y -> X -> Z we'll get an oops after point X in writeback_inodes().

Am I correct with it?

Kirill

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/