From: Jan Blunck This patch lets adds support for union-directory lookup to lookups from dentry cache and real lookups. On union-directories a lookup must continue on overlayed directories of the union. The lookup continues until the first no-negative dentry is found. Otherwise the topmost negative dentry is returned. Signed-off-by: Jan Blunck Signed-off-by: Miklos Szeredi --- fs/namei.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) Index: linux-2.6/fs/namei.c =================================================================== --- linux-2.6.orig/fs/namei.c 2009-05-20 15:05:15.000000000 +0200 +++ linux-2.6/fs/namei.c 2009-05-20 15:10:09.000000000 +0200 @@ -34,6 +34,7 @@ #include #include #include +#include "union.h" #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE]) @@ -778,6 +779,49 @@ static __always_inline void follow_dotdo follow_mount(&nd->path.mnt, &nd->path.dentry); } +static int do_lookup_union(struct nameidata *nd, struct qstr *name, + struct path *path) +{ + int err; + struct path save; + + save = nd->path; + path_get(&save); + while (follow_union_up(&nd->path)) { + struct dentry *dentry; + + dentry = d_hash_and_lookup(nd->path.dentry, name); + if (dentry && dentry->d_op && dentry->d_op->d_revalidate) { + dentry = do_revalidate(dentry, nd); + err = PTR_ERR(dentry); + if (IS_ERR(dentry)) + goto out; + } + if (!dentry) { + dentry = real_lookup(nd->path.dentry, name, nd); + err = PTR_ERR(dentry); + if (IS_ERR(dentry)) + goto out; + } + if (dentry->d_inode) { + dput(path->dentry); + path->dentry = dentry; + path->mnt = mntget(nd->path.mnt); + follow_mount(&path->mnt, &path->dentry); + err = 0; + goto out; + } + dput(dentry); + } + __follow_mount(path); + err = 0; +out: + path_put(&nd->path); + nd->path = save; + + return err; +} + /* * It's more convoluted than I'd like it to be, but... it's still fairly * small and for now I'd prefer to have fast path as straight as possible. @@ -796,6 +840,11 @@ static int do_lookup(struct nameidata *n done: path->mnt = mnt; path->dentry = dentry; + if (IS_MNT_UNION(mnt) && !dentry->d_inode && + nd->path.dentry == nd->path.mnt->mnt_root) { + return do_lookup_union(nd, name, path); + } + __follow_mount(path); return 0; -- -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/