Subject: [PATCH] Rewrite proc_root_follow_link so it is transparent to the user From: Eric W. Biederman Date: 1129570923 -0600 By using a vfsmnt structure I completely make name of the intermediate dentry disappear. And allows me to use whatever name works best for d_lookup and debugging. --- fs/proc/root.c | 60 ++++++++++++++++++++++++++++++++++---------------------- 1 files changed, 36 insertions(+), 24 deletions(-) e8cbde5d8941a2352702980cb2a9cb11f2378f49 diff --git a/fs/proc/root.c b/fs/proc/root.c index 1e51a7c..f725980 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -83,43 +83,55 @@ void __init proc_root_init(void) proc_bus = proc_mkdir("bus", NULL); } -static void *proc_root_follow_link(struct vfsmount *mnt, struct dentry *dentry, struct nameidata *nd) +static void *proc_root_follow_link(struct vfsmount *mnt, struct dentry *parent, struct nameidata *nd) { - /* Follow the pseudo link to the per pspace root of the /proc filesystem */ - struct inode *root = dentry->d_inode; + /* Follow the pseudo link to the per pspace root of the /proc + * filesystem + */ + struct inode *root = parent->d_inode; + struct dentry *dentry; struct qstr str; - /* Install the mount and drop the dentry */ - mntget(mnt); - dput(nd->dentry); - mntput(nd->mnt); - nd->mnt = mnt; - - /* Use a name of length 0 so it is not visible to user space. - * This relies on all of the information needed to be mached - * being placed in str.hash. + /* Each pspace root is stored in the main /proc directory + * it's name is the pointer to it's pspace. * - * FIXME: We are safe with 32bit pointers there is a remote - * possibility of a hash collision with 64bit pointers. + * To keep user space from detecting the redirection an + * additional vfsmount is added, which allows me to skip + * the dentry name when building the d_path name. */ - str.name = "\0"; - str.len = 0; - str.hash = ((unsigned long)(current->pspace))/sizeof(struct pspace); + str.name = (const unsigned char *)¤t->pspace; + str.len = sizeof(current->pspace); + str.hash = full_name_hash(str.name, str.len); /* See if I already have the pspace dentry and if not create it */ down(&root->i_sem); - nd->dentry = d_lookup(dentry, &str); - if (!nd->dentry) { - nd->dentry = d_alloc(dentry, &str); - if (nd->dentry) { - nd->dentry->d_fsdata = current->pspace; - d_add(nd->dentry, root); + dentry = d_lookup(parent, &str); + if (!dentry) { + dentry = d_alloc(parent, &str); + if (dentry) { + dentry->d_fsdata = current->pspace; + d_add(dentry, root); __iget(root); } else { - nd->dentry = ERR_PTR(-ENOMEM); + dentry = ERR_PTR(-ENOMEM); } } up(&root->i_sem); + if (!IS_ERR(dentry)) { + struct vfsmount *cover; + cover = alloc_vfsmnt(NULL); + cover->mnt_sb = dentry->d_sb; + cover->mnt_root = dget(dentry); + cover->mnt_mountpoint = parent; + cover->mnt_parent = mnt; + mntget(mnt); + mntput(nd->mnt); + nd->mnt = cover; + atomic_inc(&dentry->d_sb->s_active); + } + /* Forget nd->dentry */ + dput(nd->dentry); + nd->dentry = dentry; return NULL; } -- 1.0.GIT