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