On 6/21/06, I wrote:
This time, I'll wait a few more hours before claiming victory ;-)

After a few more hours and more than 160 GB of nfs traffic from the
server to the diskless nodes (by running my torture tests during the
whole night), I am now reasonably confident that the problem is fixed.

Thank you very much again !

On a sidenote : I'm not trying the same setup from an experimental smp
server (2 Dual-Core cpus => 4 Cpus seen by linux) with RedHat's kernel
2.6.9-34.ELsmp) and it also seems to work without any problem.
I thought unionfs was not yet SMP-safe... is it or not ?

Best regards,

Vincent

P.S.: I'm attaching my fully working backported patch against unionfs
1.1.5 for those who might be interested. I had to comment out the call
to unionfs_print because this function is not available in unionfs
1.1.x but aside from that I think that the backport is clean...
diff -uNr ../unionfs-1.1.5.orig/branchman.c ./branchman.c
--- ../unionfs-1.1.5.orig/branchman.c	2006-06-12 04:03:36.000000000 +0200
+++ ./branchman.c	2006-06-20 14:37:00.000000000 +0200
@@ -211,6 +211,12 @@
 
 	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 @@
 	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)
 		goto out;
diff -uNr ../unionfs-1.1.5.orig/main.c ./main.c
--- ../unionfs-1.1.5.orig/main.c	2006-06-12 04:03:36.000000000 +0200
+++ ./main.c	2006-06-20 14:42:03.000000000 +0200
@@ -539,6 +539,14 @@
 		err = -EINVAL;
 		goto out_error;
 	}
+#ifdef UNIONFS_IMAP_BOGUS_CHECK
+	if (imapfound
+	    && hidden_root_info->udi_bend + 1 != stopd(sb)->usi_num_bmapents) {
+		printk(KERN_WARNING "unionfs: unmatched imap option\n");
+		err = -EINVAL;
+		goto out_error;
+	}
+#endif
 	goto out;
 
       out_error:
diff -uNr ../unionfs-1.1.5.orig/persistent_inode.c ./persistent_inode.c
--- ../unionfs-1.1.5.orig/persistent_inode.c	2006-06-20 14:35:13.000000000 +0200
+++ ./persistent_inode.c	2006-06-20 14:37:45.000000000 +0200
@@ -499,8 +499,8 @@
 
 	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)
@@ -557,8 +557,8 @@
 	/* 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++;
 	down(&sb->s_lock);
+	*uino = spd->usi_next_avail++;
 	err = __write_uin(spd, *uino, branchnum, inode_number);
 	if (err)
 		spd->usi_next_avail--;
@@ -604,14 +604,10 @@
 	    (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();
diff -uNr ../unionfs-1.1.5.orig/super.c ./super.c
--- ../unionfs-1.1.5.orig/super.c	2006-06-12 04:03:36.000000000 +0200
+++ ./super.c	2006-06-20 14:41:02.000000000 +0200
@@ -471,24 +471,326 @@
 	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.
  */
-static struct dentry *unionfs_get_parent(struct dentry *dentry)
+/* un-tested 64 bit environment (pointer and inode number) */
+
+#define is_anon(d) ((d)->d_flags & DCACHE_DISCONNECTED)
+extern struct export_operations export_op_default;
+
+static void prepend_path(char **path, const char *name, int len)
 {
+	*path -= len;
+	memcpy(*path, name, len);
+	(*path)--;
+	**path = '/';
+}
 
-	struct dentry *ret;
-	struct inode *childinode;
-	childinode = dentry->d_inode;
-	ret = d_find_alias(childinode);
-	return ret;
+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 (len == 2 && !strncmp(name, "..", 2)) {
+		a->parent_ino = ino;
+		a->found++;
+	} else if (ino == a->ino) {
+		if (len != 1 || strncmp(name, ".", 1))
+			prepend_path(&a->path, name, len);
+		a->found++;
+	}
+	return (a->found == 2) ? 1 : 0;
+}
+
+static struct dentry *get_hidden_parent(struct super_block *hidden_sb,
+					ino_t hidden_parent_ino)
+{
+	struct dentry *hidden_parent, *d;
+	struct inode *hidden_dir;
+
+	if (hidden_sb->s_root->d_inode->i_ino == hidden_parent_ino)
+		return DGET(hidden_sb->s_root);
+
+	hidden_parent = ERR_PTR(-ENOMEM);
+	hidden_dir = iget(hidden_sb, hidden_parent_ino);
+	if (!hidden_dir)
+		goto out;
+	hidden_parent = (void *)hidden_dir;
+	if (IS_ERR(hidden_dir))
+		goto out_iput;
+	hidden_parent = ERR_PTR(-ESTALE);
+	if (is_bad_inode(hidden_dir))
+		goto out_iput;
+
+	hidden_parent = ERR_PTR(-ENOMEM);
+	d = d_alloc_anon(hidden_dir);
+	if (!d)
+		goto out_iput;
+	hidden_parent = d;
+	if (!IS_ERR(d))
+		goto out;	/* success */
+
+      out_iput:
+	IPUT(hidden_dir);
+      out:
+	return hidden_parent;
+}
+
+static struct dentry *do_get_dentry(struct super_block *sb, ino_t ino,
+				    __u32 gen, struct dentry *hidden_root,
+				    ino_t hidden_ino, ino_t hidden_parent_ino)
+{
+	struct dentry *dentry, *hidden_parent, *parent;
+	char *path, *p;
+	struct filldir_arg arg = {
+		.ino = hidden_ino,
+		.parent_ino = hidden_parent_ino
+	};
+	int open_flags, err, bindex, bend, found;
+	struct file *hidden_file;
+	struct super_block *hidden_sb;
+
+	print_entry("hr%p, hi%lu, hpi%lu",
+		    hidden_root, hidden_ino, hidden_parent_ino);
+
+	dentry = ERR_PTR(-ENOMEM);
+	path = __getname();
+	if (!path)
+		goto out;
+	arg.path = path + PATH_MAX - 1;
+	*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);
+	bend = dbend(sb->s_root);
+	found = -1;
+	for (bindex = 0; found == -1 && bindex <= bend; bindex++)
+		if (hidden_root == dtohd_index(sb->s_root, bindex))
+			found = bindex;
+	unlock_dentry(sb->s_root);
+	if (found == -1)
+		goto out_unlock;
+
+	bindex = found;
+	hidden_sb = stohs_index(sb, bindex);
+	while (1) {
+		hidden_parent = get_hidden_parent(hidden_sb, hidden_parent_ino);
+		dentry = hidden_parent;
+		if (IS_ERR(hidden_parent))
+			goto out_unlock;
+
+		branchget(sb, bindex);
+		hidden_file = DENTRY_OPEN(DGET(hidden_parent), NULL,
+					  open_flags);
+		if (IS_ERR(hidden_file)) {
+			dentry = (void *)hidden_file;
+			DPUT(hidden_parent);
+			branchput(sb, bindex);
+			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);
+		branchput(sb, bindex);
+		if (arg.found != 2) {
+			dentry = ERR_PTR(-ESTALE);
+			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
+
+		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) {
+		down(&parent->d_inode->i_sem);
+		dentry = LOOKUP_ONE_LEN(arg.path, parent, p - arg.path);
+		up(&parent->d_inode->i_sem);
+		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);
+		}
+		parent = dentry;
+		arg.path = p + 1;
+		p = strchr(arg.path, '/');
+	}
+	down(&parent->d_inode->i_sem);
+	dentry = LOOKUP_ONE_LEN(arg.path, parent, strlen(arg.path));
+	up(&parent->d_inode->i_sem);
+	DPUT(parent);
+	if (!IS_ERR(dentry)
+	    && (!dentry->d_inode
+		|| dentry->d_inode->i_ino != ino
+		|| dentry->d_inode->i_generation != gen)) {
+		DPUT(dentry);
+		dentry = ERR_PTR(-ESTALE);
+	}
+
+      out_unlock:
+	unionfs_read_unlock(sb);
+	__putname(path);
+      out:
+	print_exit_pointer(dentry);
+	return dentry;
+}
+
+enum {
+	FhHead = 4, FhHRoot1 = FhHead, FhHRoot2,
+	FhHIno1, FhHIno2, FhHPIno1, FhHPIno2,
+	FhTail
+};
+
+static void do_decode(__u32 * fh, struct dentry **hidden_root,
+		      ino_t * hidden_ino, ino_t * hidden_parent_ino)
+{
+	*hidden_root = (void *)fh[FhHRoot2];
+	*hidden_ino = fh[FhHIno2];
+	*hidden_parent_ino = fh[FhHPIno2];
+#if BITS_PER_LONG == 64
+	*hidden_root |= fh[FhHRoot1] << 32;
+	*hidden_ino |= fh[FhHIno1] << 32;
+	*hidden_parent_ino |= fh[FhHPIno1] << 32;
+#elif BITS_PER_LONG == 32
+	/* ok */
+#else
+#error unknown size
+#endif
+}
+
+static int unionfs_encode_fh(struct dentry *dentry, __u32 * fh, int *max_len,
+			     int connectable)
+{
+	int type, len, bindex;
+	struct super_block *sb;
+	struct dentry *h_root;
+	ino_t h_ino, hp_ino;
+	static int warn;
+
+	print_entry("dentry %p", dentry);
+	BUG_ON(is_anon(dentry) || !dentry->d_inode
+	       || is_anon(dentry->d_parent));
+
+#ifdef UNIONFS_IMAP
+	if (!warn && stopd(dentry->d_sb)->usi_persistent)
+		warn++;
+#endif
+	if (!warn) {
+		printk(KERN_WARNING "Exporting Unionfs without imap"
+		       " option may stop your NFS 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;
+	bindex = dbstart(dentry);
+	lock_dentry(sb->s_root);
+	h_root = dtohd_index(sb->s_root, bindex);
+	unlock_dentry(sb->s_root);
+	h_ino = itohi_index(dentry->d_inode, bindex)->i_ino;
+	hp_ino = parent_ino(dtohd(dentry));
+	fh[FhHRoot2] = (__u32) h_root;
+	fh[FhHIno2] = h_ino;
+	fh[FhHPIno2] = hp_ino;
+#if BITS_PER_LONG == 64
+	fh[FhHRoot1] = h_root >> 32;
+	fh[FhHIno1] = h_ino >> 32;
+	fh[FhHPIno1] = hp_ino >> 32;
+#endif
+
+      out:
+//unionfs_print(PRINT_MAIN_EXIT, "%d, fh{i%u, g%d, hr%x, hi%u, hpi%u}\n",
+//	      type, fh[0], fh[1], fh[FhHRoot2], 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, *hidden_root;
+	ino_t hidden_ino, hidden_parent_ino;
+
+	print_entry("%d, fh{i%u, g%d, hr%x, hi%u, hpi%u}",
+		    fh_type, fh[0], fh[1], fh[FhHRoot2], fh[FhHIno2],
+		    fh[FhHPIno2]);
+
+	dentry = export_op_default.get_dentry(sb, fh);
+	if (!dentry || IS_ERR(dentry) || (dentry->d_inode && !is_anon(dentry)))
+		return dentry;
+
+	d_drop(dentry);
+	DPUT(dentry);
+	do_decode(fh, &hidden_root, &hidden_ino, &hidden_parent_ino);
+	dentry = do_get_dentry(sb, fh[0], fh[1], hidden_root, 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
 };
 
 struct super_operations unionfs_sops = {


_______________________________________________
unionfs mailing list
[email protected]
http://www.fsl.cs.sunysb.edu/mailman/listinfo/unionfs

Reply via email to