• Alexander Viro's avatar
    [PATCH] symlink 1/9: infrastructure and explanation · e6a9fb1e
    Alexander Viro authored
    This patch-kit gets past the limit on nested symlinks, without
    incompatible API changes _and_ with killing code duplication in most of
    the readlink/follow_link pairs.  And no, it's not the old ->getlink()
    crap - procfs et.al.  are not special-cased there. 
    
    Here's how it works:
     * ->follow_link() still does what it used to do - replaces
       vfsmount/dentry in the nameidata it got from caller.  However, it can
       also leave a pathname to be resolved by caller. 
     * we add an array of char * into nameidata; we always work with
       nd->saved_names[current->link_count].  nd_set_link() sets it,
       nd_get_link() returns it.
     * callers of ->follow_link() (all two of them) check if ->follow_link()
       had left us something to do.  If it had (return value was zero and
       nd_get_link() is non-NULL), they do __vfs_follow_link() on that name.
       Then they call a new method (->put_link()) that frees whatever has to
       be freed, etc. 
    
    Note that absolute majority of symlinks have "resolve a pathname" as
    part of their ->follow_link(); they can do something else and some don't
    do that at all, but having that pathname resolution is very, very
    common. 
    
    With that change we allow them to shift pathname resolution part to
    caller.  They don't have to - it's perfectly OK to do all work in
    ->follow_link().  However, leaving the pathname resolution to caller
    will
       a) exclude foo_follow_link() stack frame from the picture
       b) kill 2 stack frames - all callers are in fs/namei.c
    and they can use inlined variant of vfs_follow_link().
    
    That reduction of stack use is enough to push the limit on nested
    symlinks from 5 to 8 (actually, even beyond that, but since 8 is common
    for other Unices it will do fine). 
    
    For those who have "pure" ->follow_link() (i.e.  "find a string that
    would be symlink contents and say nd_set_link(nd, string)") we also get
    a common helper implementing ->readlink() - it just calls
    ->follow_link() on a dummy nameidata, calls vfs_readlink() on result of
    nd_get_link() and does ->put_link().  Using (or not using) it is up to
    filesystem; it's a helper that can be used as a ->readlink() for many
    filesystems, not a reimplementation of sys_readlink().  However, that's
    _MANY_ filesystems - practically all of them. 
    
    Note that we don't put any crap like "if this is a normal symlink, do
    this; otherwise call ->follow_link() and let it do its magic" into
    callers - all symlinks are handled the same way.  Which was the main
    problem with getlink proposal back then. 
    
    That covers almost everything; the only cases left are nfs, ncpfs and
    cifs.  Those will go later - we are backwards compatible, so it's not a
    problem. 
    
    First patch: infrastructure - helpers allowing ->follow_link() to leave
    a pathname to be traversed by caller + corresponding code in callers. 
    e6a9fb1e
namei.c 56.8 KB