lkml.org 
[lkml]   [1998]   [Apr]   [20]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
Date
From
SubjectRe: PATCH: smart symlink loop detection.
Ok, I spent the weekend kludging around with ways of doing flat
symlink resolution.

I took a look at how FreeBSD does it... apparently, when in their
equivalent of lookup_dentry(), when they discover a symlink component
in the pathname they overwrite it in-place with the symlink's "value",
then re-start the resolution process using the new name (w/o changing
"base"). If expanding a symlink would cause the buffer to overflow,
they return -ENAMETOOLONG. Simple, graceful, makes sense, and allows
"max-symlinks" to be implemented as a simple, flat counter/countdown.
So I coded up a new version of lookup_dentry() that does this
insatead, and it seems to work most of the time.

There's just one problem: I need to call inode->i_op->readlink() to
get the "value" of a symlink. ext2_readlink (among others I suspect)
uses copy_to_user(), which _sometimes_ returns -EFAULT when trying to
write the symlink's text to the buffers I'm using. (This happens w/
all sorts of buffers: static char[]'s in the fn, kmalloc(PATH_MAX+1,
GFP_{KERNEL,USER}), and get_free_page(GFP_{KERNEL,USER}).) My guess
is it doesn't like writing to kernel-space buffers. BSD handles this
using a flag in their "uio" structure. I'm sure this can be done in
Linux, there's just something obvious I'm missing.

Another nit-pick - since there's no way for me to know (w/o using
fs-specific code) the length of a symlink's value until I've copied it
(return of i_op->readlink), I need to use two buffers. If there were
a way to know beforehand, I could dispense with that second buffer (a
second page of memory) and do everything in-place. This would,
however, probably require a new i_op.

I also thought a little more about the linked list implementation, and
it seems to me now a lot kludgier than when I first imagined it.
Consider a list built from:
struct name_list_node {
struct qstr name;
struct dentry *dentry;
struct name_list *next;
struct name_list *prev;
}
Presumably we can have the char * in qstr point to the d_name value of
dentry, which saves a few kmalloc's, and reference counting should be
handled correctly as long as (when we're done) we walk the list, dput
the dentries and free the name_list_nodes. It also could be done w/
singly or doubly linked lists; doing inserts correctly with
single-links requires a few extra copies, though. Either way, it's
expensive compared with in-place string stuff, and still requires a
one-page buffer to be allocated for getting symlink values in addition
to the countless smaller kmalloc's for nodes.

Thoughts? Comments? Flames?

Adam
--
You crucify all honesty \\Adam D. Bradley artdodge@cs.bu.edu
No signs you see do you believe \\Boston University Computer Science
And all your words just twist and turn\\ Grad Student and Linux Hacker
Reviving just to crash and burn \\ <><
---------> Why can't you listen as love screams everywhere? <--------



-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu

\
 
 \ /
  Last update: 2005-03-22 13:42    [W:1.574 / U:0.352 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site