• A
    fix races between __d_instantiate() and checks of dentry flags · 22213318
    Al Viro 提交于
    in non-lazy walk we need to be careful about dentry switching from
    negative to positive - both ->d_flags and ->d_inode are updated,
    and in some places we might see only one store.  The cases where
    dentry has been obtained by dcache lookup with ->i_mutex held on
    parent are safe - ->d_lock and ->i_mutex provide all the barriers
    we need.  However, there are several places where we run into
    trouble:
    	* do_last() fetches ->d_inode, then checks ->d_flags and
    assumes that inode won't be NULL unless d_is_negative() is true.
    Race with e.g. creat() - we might have fetched the old value of
    ->d_inode (still NULL) and new value of ->d_flags (already not
    DCACHE_MISS_TYPE).  Lin Ming has observed and reported the resulting
    oops.
    	* a bunch of places checks ->d_inode for being non-NULL,
    then checks ->d_flags for "is it a symlink".  Race with symlink(2)
    in case if our CPU sees ->d_inode update first - we see non-NULL
    there, but ->d_flags still contains DCACHE_MISS_TYPE instead of
    DCACHE_SYMLINK_TYPE.  Result: false negative on "should we follow
    link here?", with subsequent unpleasantness.
    
    Cc: stable@vger.kernel.org # 3.13 and 3.14 need that one
    Reported-and-tested-by: NLin Ming <minggr@gmail.com>
    Signed-off-by: NAl Viro <viro@zeniv.linux.org.uk>
    22213318
namei.c 110.6 KB