commit 1e2158403fa4de281efc5bda05e434e89a1b8d17
Author: Yiannis Pericleous <[EMAIL PROTECTED]>
Date:   Tue May 15 18:33:32 2007 -0400

    export: get_parent now can handle disconnected dentries returned from odf's 
get_parent
    
    In such cases, get_parent is called on the odf until we get to the odf_root

diff --git a/fs/unionfs/export.c b/fs/unionfs/export.c
index 5710a1a..49fb600 100644
--- a/fs/unionfs/export.c
+++ b/fs/unionfs/export.c
@@ -2,38 +2,109 @@
 
 #define is_anon(d) ((d)->d_flags & DCACHE_DISCONNECTED)
 
+extern struct export_operations export_op_default;
+
 static struct dentry *__get_parent(struct super_block *sb, struct dentry 
*odf_dentry)
 {
        struct dentry *odf_root = UNIONFS_SB(sb)->odf->odi_ns->dentry;
-       struct dentry *d, *parent, *child = NULL;
+       struct dentry *d, *d_parent, *parent, *child = NULL;
        struct dentry_stack stack;
+       char *name = NULL;
+       int res;
 
        if (odf_root == odf_dentry)
                return sb->s_root;
 
+       name = kmalloc(NAME_MAX+1, GFP_KERNEL);
+       if (!name)
+               return ERR_PTR(-ENOMEM);
+
+       /* unionfs_get_parent already checks for this */
+       BUG_ON(!odf_root->d_sb->s_export_op || 
!odf_root->d_sb->s_export_op->get_parent);
+
        __ds_init(&stack, 8);
        if (!stack.item)
                return ERR_PTR(-ENOMEM);
 
+       /* first we need to follow the odf_dentry back to the root (/odf/ns)
+        * and keep track of the dentries we need to go through
+        */
+       dget(odf_dentry);
        d = odf_dentry;
        do {
                BUG_ON(!d);
                __ds_push(&stack, d);
-               d = d->d_parent;
+               if (!is_anon(d)) {
+                       d = d->d_parent;
+                       if (d != odf_root)
+                               dget(d);
+               }
+               else {
+                       /* if the odf dentry is disconnected we get its
+                        * parent by calling get_parent on the odf fs
+                        */
+                       mutex_lock(&d->d_inode->i_mutex);
+                       d_parent = d->d_sb->s_export_op->get_parent(d);
+                       mutex_unlock(&d->d_inode->i_mutex);
+                       if (IS_ERR(d_parent)) {
+                               child = d_parent;
+                               goto out;
+                       }
+                       d = d_parent;
+               }
        } while (d != odf_root);
 
+       /* now we start from the root and lookup in the union using the names 
of the
+        * odf_dentries we have on our dentry_stack until we get to our target
+        */
        parent = sb->s_root;
        dget(parent);
        while (stack.n) {
                d = __ds_pop(&stack);
-               child = lookup_one_len(d->d_name.name, parent, d->d_name.len);
+
+               memset(name, 0, NAME_MAX + 1);
+               if (is_anon(d)) {
+                       /* If this dentry is disconnected, then it is 
anonymous, so we
+                        * have to get its name using get_name. However since 
it is
+                        * disconnected it doesn't know its parent. Thankfully 
since
+                        * we already looked up its parent in this loop we have 
its
+                        * parent in the union dentry's parent odf_info struct
+                        */
+
+                       /* our odf root can never be disconnected*/
+                       BUG_ON(d == odf_root);
+                       if (odf_root->d_sb->s_export_op->get_name)
+                               res = odf_root->d_sb->s_export_op->get_name(
+                                       UNIONFS_D(parent)->odf_info->dentry,
+                                       name, d);
+                       else
+                               res = export_op_default.get_name(
+                                       UNIONFS_D(parent)->odf_info->dentry,
+                                       name, d);
+               }
+               else
+                       strncpy(name, d->d_name.name, d->d_name.len);
+
+               dput(d);
+
+               if (res) {
+                       child = ERR_PTR(res);
+                       break;
+               }
+
+               child = lookup_one_len(name, parent, strlen(name));
                dput(parent);
                if (IS_ERR(child))
                        break;
                parent = child;
        }
 
+out:
+       BUG_ON(stack.n < 0);
+       while(stack.n)
+               dput(__ds_pop(&stack));
        kfree(stack.item);
+       kfree(name);
        return child;
 }
 
@@ -73,6 +144,7 @@ static struct dentry *unionfs_get_parent(struct dentry 
*child)
 
        dput(odf_child);
        dput(odf_parent);
+
 out:
        return res;
 }
@@ -91,11 +163,11 @@ static int unionfs_get_name(struct dentry *dentry, char 
*name, struct dentry *ch
        struct inode *dir = dentry->d_inode;
        struct odf_dentry_info *odi = NULL;
        struct file *file = NULL;
-        /* dirent */
-        u64 ino;
-        char *tmp_name = NULL;
-        int namelen;
-        unsigned int d_type;
+       /* dirent */
+       u64 ino;
+       char *tmp_name = NULL;
+       int namelen;
+       unsigned int d_type;
 
        err = -ENOTDIR;
        if (!dir || !S_ISDIR(dir->i_mode))
@@ -108,37 +180,37 @@ static int unionfs_get_name(struct dentry *dentry, char 
*name, struct dentry *ch
        if (!UNIONFS_D(dentry) || !UNIONFS_D(dentry)->odf_info)
                goto out;
 
-        odi = odf_ic_cache_dentry(dentry);
-        if (IS_ERR(odi)){
-                err = PTR_ERR(odi);
-                odi = NULL;
-                goto out;
-        }
+       odi = odf_ic_cache_dentry(dentry);
+       if (IS_ERR(odi)){
+               err = PTR_ERR(odi);
+               odi = NULL;
+               goto out;
+       }
 
        /* reconstruct the cached dir if necessary */
-        if (!odi->dentry->d_inode || !odi->dentry->d_inode->i_size) {
-                unionfs_lock_dentry(dentry);
-                err = odf_cache_dir(dentry, odi->dentry, 
&dentry->d_inode->i_mtime);
-                unionfs_unlock_dentry(dentry);
-                if (err)
-                        goto out;
-        }
-
-       dget(odi->dentry);
-       mntget(UNIONFS_SB(dentry->d_sb)->odf->mnt);
-       file = dentry_open(odi->dentry, UNIONFS_SB(dentry->d_sb)->odf->mnt, 
O_RDONLY);
-        if (IS_ERR(file)){
-                err = PTR_ERR(file);
-                mntput(UNIONFS_SB(dentry->d_sb)->odf->mnt);
-                dput(odi->dentry);
-                file = NULL;
-                goto out;
-        }
+       if (!odi->dentry->d_inode || !odi->dentry->d_inode->i_size) {
+               unionfs_lock_dentry(dentry);
+               err = odf_cache_dir(dentry, odi->dentry, 
&dentry->d_inode->i_mtime);
+               unionfs_unlock_dentry(dentry);
+               if (err)
+                       goto out;
+       }
+
+       dget(odi->dentry);
+       mntget(UNIONFS_SB(dentry->d_sb)->odf->mnt);
+       file = dentry_open(odi->dentry, UNIONFS_SB(dentry->d_sb)->odf->mnt, 
O_RDONLY);
+       if (IS_ERR(file)){
+               err = PTR_ERR(file);
+               mntput(UNIONFS_SB(dentry->d_sb)->odf->mnt);
+               dput(odi->dentry);
+               file = NULL;
+               goto out;
+       }
 
        /* search for the inode in the dir */
        file->f_pos = 0;
        while (file->f_pos < file->f_dentry->d_inode->i_size) {
-               err = odf_read_dirent(file, &tmp_name, &namelen, &ino, &d_type);
+               err = odf_read_dirent(file, &tmp_name, &namelen, &ino, &d_type);
                if (err)
                        break;
                if (ino == child->d_inode->i_ino) {
@@ -158,9 +230,9 @@ static int unionfs_get_name(struct dentry *dentry, char 
*name, struct dentry *ch
 out:
        kfree(tmp_name);
        tmp_name = NULL;
-       if (file)
-                filp_close(file, NULL);
-        odf_put_info(odi);
+       if (file)
+               filp_close(file, NULL);
+       odf_put_info(odi);
        return err;
 }
 
_______________________________________________
unionfs-cvs mailing list: http://unionfs.filesystems.org/
[email protected]
http://www.fsl.cs.sunysb.edu/mailman/listinfo/unionfs-cvs

Reply via email to