• Kirill Korotaev's avatar
    [PATCH] Fix of race in writeback_inodes() · 4e56755a
    Kirill Korotaev authored
    This patch fixes race in writeback_inodes() described below:
    
    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().
    
    This patch introduces __put_super_and_need_restart() function which allows
    safe traversing of sb list.  I'll send a couple of patches later which
    remove O(n^2) algos and using this function.
    Signed-Off-By: default avatarKirill Korotaev <dev@sw.ru>
    Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
    Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
    4e56755a
super.c 19.5 KB