LWN.net Logo

Supporting deeper symbolic links

Linux has long limited filename lookups to a maximum of five chained symbolic links. The limit is a useful way of dealing with symbolic link loops, but that is not why it exists. Following symbolic links is an inherently recursive task; once a link has been resolved, the new destination can be another link, which starts the whole process from the beginning. In general, recursion is frowned on in the kernel; the tight limit on kernel stack space argues against allowing any sort of significant call depth at all. The five-link limit was set because, if the limit were higher, the kernel would risk overrunning the kernel stack when following long chains.

Users do occasionally run into the five-link limit, and, of course, they complain. The limit imposed by Linus is lower than that found on a number of other Unix-like systems. So there has long been some motivation to raise that limit somewhat.

Alexander Viro has finally done something about it. His approach was to change the behavior of the filesystem follow_link() method slightly. This method has traditionally been charged with finding the target of a symbolic link, then calling back into the virtual filesystem code (via vfs_follow_link()) to cause the next stage of resolution to happen. In the new scheme of things, the follow_link() method is still free to do the whole job, so unmodified filesystems still work. But the preferred technique is for the filesystem code to simply store the file name for the link target in a place where the VFS code can find it and return. The VFS can then make the vfs_follow_link() call itself.

This seems like a small change, but it has an important effect. The filesystem's follow_link() method's stack frame is now gone, since it has returned back to the core VFS code. And the core code can use an in-lined version of vfs_follow_link(), rather than calling it (with its own stack frame) from the outside. As a result, two fewer stack frames are required for every step in the resolution of the symbolic link.

Al figures that this change will enable raising the maximum link depth to eight, or even higher (though there is probably little reason to go beyond eight). That change has not yet happened - all of the filesystems will need to be updated and the patch proven stable first. But the initial set of patches has found its way into Linus's BitKeeper tree, so the process is coming near to its conclusion.


(Log in to post comments)

Supporting deeper symbolic links

Posted Jul 1, 2004 6:02 UTC (Thu) by mkerrisk (editor, #1978) [Link]

One reason that a limit of 8 is desirable is that this is the minimum that POSIX/SUSv3 requires: _POSIX_SYMLOOP_MAX is 8.

Supporting deeper symbolic links

Posted Jul 1, 2004 12:31 UTC (Thu) by nathan (subscriber, #3559) [Link]

Why can the recursion not be turned into iteration? There must be something
else going on that I'd like to know about.

Supporting deeper symbolic links

Posted Jul 1, 2004 14:40 UTC (Thu) by jeremiah (subscriber, #1221) [Link]

It does seem kinda strange, that the stack would grow at all. You only care about the start point and the end point, not the actual path you took to get there. Why wouldn't you just discard the most of the path as you went along?

Supporting deeper symbolic links

Posted Jul 1, 2004 19:22 UTC (Thu) by bronson (subscriber, #4806) [Link]

I agree. Applying a tail recursion optimization seems an obvious solution!

Does anybody know why this isn't an option?

adjusting the problem vs fixing it

Posted Jul 2, 2004 3:25 UTC (Fri) by giraffedata (subscriber, #1954) [Link]

Given that the lookup does not fail gracefully if you run out of stack (behavior is undefined), there really ought to be a more formal control on the amount of stack space used. Just saying, "About 5 should be safe" is not adequate, and lowering the stack usage and saying, "now 8 should probably be OK" is shamelessly perpetuating the problem.

Requiring the filesystem code and VFS code to be so intimately familiar with each other's use of stack space to avoid crashing the kernel is asking too much.

I too would expect an iteration to be the right fix. But if that's not practical, then the limit should be on the amount of stack space left, not the number of times a symbolic link has been followed. And it's actually cleaner to check how much stack space is left than to do the count. The code today doesn't do pure recursion; it has a special global (per-process) variable (current->link_count) it uses to determine when this particular recursion has hit its limit.

Supporting deeper symbolic links

Posted Jul 2, 2004 3:54 UTC (Fri) by khim (subscriber, #9252) [Link]

Think about /usr/bin/gcc where /usr is symlink to /mnt/somewhere/else and then ../bin/.. part is symlink as well and gcc too is symlink...

Now please about that tail recusion thingy again if you can. Heh.

Unfortunatelly you do care about path - just not path you though about...

As "track for stack usage" - it'll be nightmare to administer: sometimes you can compile this program but if b-tree in filesystem is changed somewhat you're suddenly can not do it. Gosh.

Supporting deeper symbolic links

Posted Jul 5, 2004 16:15 UTC (Mon) by jschrod (subscriber, #1646) [Link]

char real_name [path_max+1] = "";
char *s = link_name;
char *path_elem;
while ( path_elem = strstr(s, '/') ) {
    char r [path_max+1] = strcpy(real_name);
    int size;
    strcat(r, "/");
    strcat(r, path_elem);
    while ( (size = readlink(r, real_name)) != -1 ) {
        real_name[size] = NUL;
    }
    if ( size != EINVAL ) do_error_handling();
    s = NULL;
}
No recursion, mom. (Not tested either... :-) Add a few overflow checks, please. And exchange libc functions by kernel ones. But none of them need dynamic memory, so there is no stack issue.

Cheers, Joachim

Supporting deeper symbolic links

Posted Jul 2, 2004 9:59 UTC (Fri) by joern (subscriber, #22392) [Link]

Remember -ELOOP?

Copyright © 2004, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds