"Vincent Vanackere":
> Thank you very much ! Now I'm just waiting for a unionfs-1.1.6
> including your fixes :-)

Hello Vincent,

Thank you for your repeated tests.
Now Jeff is starting the next release. Before I commit this nfs patch,
could you test this patch again?
If it goes well, it will be included in 1.1.7 or later.

Junjiro Okajima


Index: branchman.c
===================================================================
RCS file: /home/cvs/unionfs/unionfs/branchman.c,v
retrieving revision 1.63
diff -u -p -r1.63 branchman.c
--- branchman.c 2 Jun 2006 03:29:26 -0000       1.63
+++ branchman.c 19 Jun 2006 03:11:54 -0000
@@ -212,6 +212,12 @@ int unionfs_ioctl_addbranch(struct inode
 
        print_entry_location();
 
+#ifdef UNIONFS_IMAP
+       err = -EPERM;
+       if (stopd(inode->i_sb)->usi_persistent)
+               goto out;
+#endif
+
        err = -ENOMEM;
        addargs = KMALLOC(sizeof(struct unionfs_addbranch_args), GFP_KERNEL);
        if (!addargs)
@@ -380,6 +386,12 @@ int unionfs_ioctl_delbranch(struct super
 
        print_entry("branch = %lu ", arg);
        lock_dentry(sb->s_root);
+
+#ifdef UNIONFS_IMAP
+       err = -EPERM;
+       if (stopd(sb)->usi_persistent)
+               goto out;
+#endif
 
        err = -EBUSY;
        if (sbmax(sb) == 1)
Index: persistent_inode.c
===================================================================
RCS file: /home/cvs/unionfs/unionfs/persistent_inode.c,v
retrieving revision 1.34
diff -u -p -r1.34 persistent_inode.c
--- persistent_inode.c  21 Feb 2006 08:36:24 -0000      1.34
+++ persistent_inode.c  19 Jun 2006 03:11:54 -0000
@@ -495,8 +495,8 @@ static int __write_uin(struct unionfs_sb
 
        fwd = sbi->usi_forwardmap;
        ent.fsnum = sbi->usi_bnum_table[bindex];
-       ent.inode = ino;
-       pos = fwdhdr + fwd_elmnt * hidden_ino;
+       ent.inode = hidden_ino;
+       pos = fwdhdr + fwd_elmnt * ino;
        sz = __fwrite(fwd, &ent, fwd_elmnt, &pos);
        err = sz;
        if (err < 0)
@@ -553,8 +553,8 @@ int read_uin(struct super_block *sb, uin
        /* If we haven't found an entry and we have the O_CREAT flag set we 
want to
         * create a new entry write it out to the file and return its index
         */
-       *uino = spd->usi_next_avail++;
        mutex_lock(&sb->s_lock);
+       *uino = spd->usi_next_avail++;
        err = __write_uin(spd, *uino, branchnum, inode_number);
        if (err)
                spd->usi_next_avail--;
@@ -600,14 +600,10 @@ int get_lin(struct super_block *sb, ino_
            (sizeof(struct fmapent) * inode_number);
        oldfs = get_fs();
        set_fs(KERNEL_DS);
-       bytesread =
-           forwardmap->f_op->read(forwardmap, (char __user *)entry,
-                                  sizeof(struct fmapent), &seek_size);
+       bytesread = __fread(forwardmap, entry, sizeof(*entry), &seek_size);
        set_fs(oldfs);
-       if (bytesread != sizeof(struct fmapent)) {
-               entry = ERR_PTR(-EINVAL);
-               goto out;
-       }
+       if (bytesread != sizeof(*entry))
+               err = -EINVAL;
 
       out:
        print_exit_location();
Index: super.c
===================================================================
RCS file: /home/cvs/unionfs/unionfs/super.c,v
retrieving revision 1.93
diff -u -p -r1.93 super.c
--- super.c     1 Jun 2006 21:25:18 -0000       1.93
+++ super.c     19 Jun 2006 03:11:55 -0000
@@ -488,24 +488,324 @@ static int unionfs_show_options(struct s
        return ret;
 }
 
-/**
- * The entry given by dentry here is always a directory.
- * We can't just do dentry->d_parent, because it may
- * not be there, since this dentry could have been
- * created by calling d_alloc_anon.
- */
+/* export operations. unionfs cannot handle disconnected dentry,
+ * since it has no hidden dentries. */
+/* un-tested 64 bit inode number */
+
+#define is_anon(d) ((d)->d_flags & DCACHE_DISCONNECTED)
+extern struct export_operations export_op_default;
+
+static void anon_dput(struct dentry *d)
+{
+       if (is_anon(d))
+               d_drop(d);
+       DPUT(d);
+}
+
+static void prepend_path(char **path, const char *name, int len)
+{
+       *path -= len;
+       memcpy(*path, name, len);
+       (*path)--;
+       **path = '/';
+}
+
+struct filldir_arg {
+       int found, called;
+       char *path;
+       ino_t ino, parent_ino;
+};
+
+static int filldir(void *arg, const char *name, int len, loff_t pos, ino_t ino,
+                  unsigned int d_type)
+{
+       struct filldir_arg *a = arg;
+
+       a->called++;
+       if (!strcmp(name, "..")) {
+               a->parent_ino = ino;
+               a->found++;
+       } else if (ino == a->ino) {
+               if (strcmp(name, "."))
+                       prepend_path(&a->path, name, len);
+               a->found++;
+       }
+       return (a->found == 2) ? 1 : 0;
+}
+
+static struct dentry *do_get_dentry(struct super_block *sb, ino_t ino,
+                                   __u32 gen, int bindex, ino_t hidden_ino,
+                                   ino_t hidden_parent_ino)
+{
+       struct dentry *dentry, *hidden_parent, *parent, *hidden_root;
+       char *path, *p;
+       struct filldir_arg arg = {
+               .ino = hidden_ino,
+               .parent_ino = hidden_parent_ino
+       };
+       int open_flags, err;
+       struct inode *hidden_dir;
+       struct file *hidden_file;
+       struct super_block *hidden_sb;
+       struct vfsmount *hidden_mnt;
+
+       print_entry("b%d, hi%lu, hpi%lu",
+                   bindex, hidden_ino, hidden_parent_ino);
+
+       dentry = ERR_PTR(-ENOMEM);
+       path = __getname();
+       if (!path)
+               goto out;
+       arg.path = path + PATH_MAX;
+       *arg.path-- = 0;
+
+       open_flags = O_RDONLY | O_DIRECTORY /* | O_NOATIME */ ;
+       if (force_o_largefile())
+               open_flags |= O_LARGEFILE;
+
+       dentry = ERR_PTR(-ESTALE);
+       unionfs_read_lock(sb);
+       lock_dentry(sb->s_root);
+       hidden_root = dtohd_index(sb->s_root, bindex);
+       unlock_dentry(sb->s_root);
+       hidden_sb = stohs_index(sb, bindex);
+       hidden_mnt = stohiddenmnt_index(sb, bindex);
+
+       while (1) {
+               dentry = ERR_PTR(-ENOMEM);
+               hidden_dir = iget(hidden_sb, hidden_parent_ino);
+               if (!hidden_dir)
+                       goto out_unlock;
+               dentry = (void *)hidden_dir;
+               if (IS_ERR(hidden_dir))
+                       goto out_unlock;
+               dentry = ERR_PTR(-ESTALE);
+               if (is_bad_inode(hidden_dir))
+                       goto out_unlock;
+
+               dentry = ERR_PTR(-ENOMEM);
+               hidden_parent = d_alloc_anon(hidden_dir);
+               if (!hidden_parent) {
+                       IPUT(hidden_dir);
+                       goto out_unlock;
+               }
+               if (IS_ERR(hidden_parent)) {
+                       dentry = hidden_parent;
+                       IPUT(hidden_dir);
+                       goto out_unlock;
+               }
+
+               hidden_file = DENTRY_OPEN(DGET(hidden_parent),
+                                         /* mntget(hidden_mnt) */ NULL,
+                                         open_flags);
+               if (IS_ERR(hidden_file)) {
+                       dentry = (void *)hidden_file;
+                       anon_dput(hidden_parent);
+                       goto out_unlock;
+               }
+
+               arg.found = 0;
+               while (arg.found != 2) {
+                       arg.called = 0;
+                       err = vfs_readdir(hidden_file, filldir, &arg);
+                       if (!arg.called || err < 0)
+                               break;
+               }
+               fput(hidden_file);
+               if (arg.found != 2) {
+                       dentry = ERR_PTR(-ESTALE);
+                       anon_dput(hidden_parent);
+                       goto out_unlock;
+               }
+#if 0
+               if (!is_anon(hidden_parent)) {
+                       struct dentry *hp = hidden_parent;
+                       while (hp != hidden_root) {
+                               struct qstr *p = &hp->d_name;
+                               prepend_path(&arg.path, p->name, p->len);
+                               hp = hp->d_parent;
+                               BUG_ON(is_anon(hp));
+                       }
+                       hidden_parent_ino = hp->d_inode->i_ino;
+               }
+#endif
+               anon_dput(hidden_parent);
+               if (hidden_parent_ino == hidden_root->d_inode->i_ino)
+                       break;
+               arg.ino = hidden_parent_ino;
+               hidden_parent_ino = arg.parent_ino;
+       };
+       BUG_ON(arg.path < path);
+
+       parent = DGET(sb->s_root);
+       p = strchr(++arg.path, '/');
+       while (p) {
+               mutex_lock(&parent->d_inode->i_mutex);
+               dentry = LOOKUP_ONE_LEN(arg.path, parent, p - arg.path);
+               mutex_unlock(&parent->d_inode->i_mutex);
+               DPUT(parent);
+               if (IS_ERR(dentry))
+                       goto out_unlock;
+               if (!dentry->d_inode || !S_ISDIR(dentry->d_inode->i_mode)) {
+                       DPUT(dentry);
+                       dentry = ERR_PTR(-ESTALE);
+                       goto out_unlock;
+               }
+               parent = dentry;
+               arg.path = p + 1;
+               p = strchr(arg.path, '/');
+       }
+       mutex_lock(&parent->d_inode->i_mutex);
+       dentry = LOOKUP_ONE_LEN(arg.path, parent, strlen(arg.path));
+       mutex_unlock(&parent->d_inode->i_mutex);
+       DPUT(parent);
+       if (!IS_ERR(dentry) && dentry->d_inode && dentry->d_inode->i_ino == ino
+           /* && dentry->d_inode->i_generation == gen */ ) {
+               if (dentry->d_inode->i_generation != gen)
+                       printk(KERN_DEBUG UNIONFS_NAME ": " "i_gen %u, %u\n",
+                              dentry->d_inode->i_generation, gen);
+               goto out_unlock;        /* success */
+       }
+
+       DPUT(dentry);
+       dentry = ERR_PTR(-ESTALE);
+
+      out_unlock:
+       unionfs_read_unlock(sb);
+       __putname(path);
+      out:
+       print_exit_pointer(dentry);
+       return dentry;
+}
+
+enum {
+       FhHead = 4, FhBindex = FhHead,
+       FhHIno1, FhHIno2, FhHPIno1, FhHPIno2,
+       FhTail
+};
+
+static void do_decode(__u32 * fh, ino_t * hidden_ino, ino_t * 
hidden_parent_ino)
+{
+       *hidden_ino = fh[FhHIno2];
+       *hidden_parent_ino = fh[FhHPIno2];
+#if BITS_PER_LONG == 64
+       *hidden_ino |= fh[FhHIno1] << 32;
+       *hidden_parent_ino |= fh[FhHPIno1] << 32;
+#elif BITS_PER_LONG == 32
+       /* ok */
+#else
+#error unknown size
+#endif
+}
+
+#if 1
+static struct dentry *unionfs_get_dentry(struct super_block *sb, void *vobjp)
+{
+       BUG();
+       return NULL;
+}
+
 static struct dentry *unionfs_get_parent(struct dentry *dentry)
 {
+       BUG();
+       return NULL;
+}
 
-       struct dentry *ret;
-       struct inode *childinode;
-       childinode = dentry->d_inode;
-       ret = d_find_alias(childinode);
-       return ret;
+static int unionfs_get_name(struct dentry *parent, char *name,
+                           struct dentry *child)
+{
+       BUG();
+       return -1;
+}
+#endif
+
+static int unionfs_encode_fh(struct dentry *dentry, __u32 * fh, int *max_len,
+                            int connectable)
+{
+       int type, len, bindex;
+       struct super_block *sb;
+       ino_t h_ino, hp_ino;
+       static int warn;
+
+       print_entry("dentry %p", dentry);
+       BUG_ON(is_anon(dentry) || is_anon(dentry->d_parent));
+
+#ifdef UNIONFS_IMAP
+       if (!warn && stopd(dentry->d_sb)->usi_persistent)
+               warn++;
+#endif
+       if (!warn) {
+               printk(KERN_WARNING "NFS exporting Unionfs without imap"
+                      " option may stop your server or client");
+               warn++;
+       }
+
+       sb = dentry->d_sb;
+       unionfs_read_lock(sb);
+       lock_dentry(dentry);
+
+       len = *max_len;
+       type = export_op_default.encode_fh(dentry, fh, max_len, connectable);
+       if (type == 255 || *max_len > FhHead || len < FhTail) {
+               type = 255;
+               goto out;
+       }
+
+       *max_len = FhTail;
+       fh[FhBindex] = bindex = dbstart(dentry);
+       h_ino = itohi_index(dentry->d_inode, bindex)->i_ino;
+       hp_ino = parent_ino(dtohd(dentry));
+       fh[FhHIno2] = h_ino;
+       fh[FhHPIno2] = hp_ino;
+#if BITS_PER_LONG == 64
+       fh[FhHIno1] = h_ino >> 32;
+       fh[FhHPIno1] = hp_ino >> 32;
+#elif BITS_PER_LONG == 32
+       /* ok */
+#else
+#error unknown size
+#endif
+
+      out:
+       unionfs_print(PRINT_MAIN_EXIT, "%d, fh{i%u, g%d, b%d, hi%u, hpi%u}\n",
+                     type, fh[0], fh[1], fh[FhBindex], fh[FhHIno2],
+                     fh[FhHPIno2]);
+       unlock_dentry(dentry);
+       unionfs_read_unlock(sb);
+       return type;
+}
+
+static struct dentry *unionfs_decode_fh(struct super_block *sb, __u32 * fh,
+                                       int fh_len, int fh_type,
+                                       int (*acceptable) (void *context,
+                                                          struct dentry * de),
+                                       void *context)
+{
+       struct dentry *dentry;
+       ino_t hidden_ino, hidden_parent_ino;
+
+       print_entry("%d, fh{i%uu, g%d, b%d, hi%u, hpi%u}\n",
+                   fh_type, fh[0], fh[1], fh[FhBindex], fh[FhHIno2],
+                   fh[FhHPIno2]);
+
+       do_decode(fh, &hidden_ino, &hidden_parent_ino);
+       dentry = do_get_dentry(sb, fh[0], fh[1], fh[FhBindex], hidden_ino,
+                              hidden_parent_ino);
+       if (!IS_ERR(dentry)) {
+               if (acceptable(context, dentry))
+                       return dentry;  /* success */
+               DPUT(dentry);
+               dentry = NULL;
+       }
+       return dentry;
 }
 
 struct export_operations unionfs_export_ops = {
-       .get_parent = unionfs_get_parent
+       .decode_fh = unionfs_decode_fh,
+       .encode_fh = unionfs_encode_fh,
+       .get_name = unionfs_get_name,
+       .get_parent = unionfs_get_parent,
+       .get_dentry = unionfs_get_dentry
 };
 
 struct super_operations unionfs_sops = {
_______________________________________________
unionfs mailing list
[email protected]
http://www.fsl.cs.sunysb.edu/mailman/listinfo/unionfs

Reply via email to