Skip to content
  • Al Viro's avatar
    Fix the locking in dcache_readdir() and friends · 664ec2db
    Al Viro authored
    commit d4f4de5e
    
     upstream.
    
    There are two problems in dcache_readdir() - one is that lockless traversal
    of the list needs non-trivial cooperation of d_alloc() (at least a switch
    to list_add_rcu(), and probably more than just that) and another is that
    it assumes that no removal will happen without the directory locked exclusive.
    Said assumption had always been there, never had been stated explicitly and
    is violated by several places in the kernel (devpts and selinuxfs).
    
            * replacement of next_positive() with different calling conventions:
    it returns struct list_head * instead of struct dentry *; the latter is
    passed in and out by reference, grabbing the result and dropping the original
    value.
            * scan is under ->d_lock.  If we run out of timeslice, cursor is moved
    after the last position we'd reached and we reschedule; then the scan continues
    from that place.  To avoid livelocks between multiple lseek() (with cursors
    getting moved past each other, never reaching the real entries) we always
    skip the cursors, need_resched() or not.
            * returned list_head * is either ->d_child of dentry we'd found or
    ->d_subdirs of parent (if we got to the end of the list).
            * dcache_readdir() and dcache_dir_lseek() switched to new helper.
    dcache_readdir() always holds a reference to dentry passed to dir_emit() now.
    Cursor is moved to just before the entry where dir_emit() has failed or into
    the very end of the list, if we'd run out.
            * move_cursor() eliminated - it had sucky calling conventions and
    after fixing that it became simply list_move() (in lseek and scan_positives)
    or list_move_tail() (in readdir).
    
            All operations with the list are under ->d_lock now, and we do not
    depend upon having all file removals done with parent locked exclusive
    anymore.
    
    Cc: stable@vger.kernel.org
    Reported-by: default avatar"zhengbin (A)" <zhengbin13@huawei.com>
    Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    664ec2db