[Ocfs2-commits] jlbec commits r2075 - trunk/fs/configfs

svn-commits at oss.oracle.com svn-commits at oss.oracle.com
Tue Mar 29 22:54:34 CST 2005


Author: jlbec
Signed-off-by: manish
Date: 2005-03-29 22:54:32 -0600 (Tue, 29 Mar 2005)
New Revision: 2075

Modified:
   trunk/fs/configfs/configfs_internal.h
   trunk/fs/configfs/dir.c
Log:

o Change the detach path to a two-stage path, allowing safe locking.

Signed-off-by: manish



Modified: trunk/fs/configfs/configfs_internal.h
===================================================================
--- trunk/fs/configfs/configfs_internal.h	2005-03-30 04:14:38 UTC (rev 2074)
+++ trunk/fs/configfs/configfs_internal.h	2005-03-30 04:54:32 UTC (rev 2075)
@@ -46,8 +46,9 @@
 #define CONFIGFS_DIR		0x0002
 #define CONFIGFS_UOBJ_ATTR 	0x0004
 #define CONFIGFS_UOBJ_LINK 	0x0020
-#define CONFIGFS_USET_DIR		0x0040
+#define CONFIGFS_USET_DIR	0x0040
 #define CONFIGFS_USET_DEFAULT	0x0080
+#define CONFIGFS_USET_DROPPING	0x0100
 #define CONFIGFS_NOT_PINNED	(CONFIGFS_UOBJ_ATTR)
 
 extern struct vfsmount * configfs_mount;

Modified: trunk/fs/configfs/dir.c
===================================================================
--- trunk/fs/configfs/dir.c	2005-03-30 04:14:38 UTC (rev 2074)
+++ trunk/fs/configfs/dir.c	2005-03-30 04:54:32 UTC (rev 2075)
@@ -291,9 +291,13 @@
 
 /*
  * Only subdirectories count here.  Files (CONFIGFS_NOT_PINNED) are
- * attributes and are removed by rmdir().
+ * attributes and are removed by rmdir().  We recurse, taking i_sem
+ * on all children that are candidates for default detach.  If the
+ * result is clean, then configfs_detach_set() will handle dropping
+ * i_sem.  If there is an error, the caller will clean up the i_sem
+ * holders via configfs_detach_rollback().
  */
-static int configfs_empty_dir(struct dentry *dentry)
+static int configfs_detach_prep(struct dentry *dentry)
 {
 	struct configfs_dirent *parent_sd = dentry->d_fsdata;
 	struct configfs_dirent *sd;
@@ -307,9 +311,12 @@
 	list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
 		if (sd->s_type & CONFIGFS_NOT_PINNED)
 			continue;
-		/* Eww, recursion */
 		if (sd->s_type & CONFIGFS_USET_DEFAULT) {
-			ret = configfs_empty_dir(sd->s_dentry);
+			down(&sd->s_dentry->d_inode->i_sem);
+			/* Mark that we've taken i_sem */
+			sd->s_type |= CONFIGFS_USET_DROPPING;
+
+			ret = configfs_detach_prep(sd->s_dentry);
 			if (!ret)
 			       	continue;
 		} else
@@ -322,6 +329,27 @@
 	return ret;
 }
 
+/*
+ * Walk the tree, dropping i_sem wherever CONFIGFS_USET_DROPPING is
+ * set.
+ */
+static void configfs_detach_rollback(struct dentry *dentry)
+{
+	struct configfs_dirent *parent_sd = dentry->d_fsdata;
+	struct configfs_dirent *sd;
+
+	list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
+		if (sd->s_type & CONFIGFS_USET_DEFAULT) {
+			configfs_detach_rollback(sd->s_dentry);
+
+			if (sd->s_type & CONFIGFS_USET_DROPPING) {
+				sd->s_type &= ~CONFIGFS_USET_DROPPING;
+				up(&sd->s_dentry->d_inode->i_sem);
+			}
+		}
+	}
+}
+
 static void detach_attrs(struct uobject * uobj)
 {
 	struct dentry * dentry = dget(uobj->dentry);
@@ -394,11 +422,16 @@
 
 		child = sd->s_dentry;
 
-		/* And now we're faking rmdir.  Viro must hate me */
-		down(&child->d_inode->i_sem);
 		configfs_detach_set(sd->s_element);
 		child->d_inode->i_flags |= S_DEAD;
-		up(&child->d_inode->i_sem);
+		
+		/*
+		 * From rmdir/unregister, a configfs_detach_prep() pass
+		 * has taken our i_sem for us.  Drop it.
+		 * From mkdir/register cleanup, there is no sem held.
+		 */
+		if (sd->s_type & CONFIGFS_USET_DROPPING)
+			up(&child->d_inode->i_sem);
 
 		d_delete(child);
 		dput(child);
@@ -538,10 +571,18 @@
 {
 	int i;
 	struct uset *new_set;
+	struct configfs_subsystem *subsys;
 
 	link_obj(&parent_uset->uobj, &uset->uobj);
-	uset->subsys = parent_uset->subsys;
 
+	if (parent_uset->subsys)
+		subsys = parent_uset->subsys;
+	else if (configfs_is_root(&parent_uset->uobj))
+		subsys = to_configfs_subsystem(uset);
+	else
+		BUG();
+	uset->subsys = subsys;
+
 	if (uset->default_sets) {
 		for (i = 0; uset->default_sets[i]; i++) {
 			new_set = uset->default_sets[i];
@@ -758,8 +799,9 @@
 		return -EINVAL;
 	}
 	
-	ret = configfs_empty_dir(dentry);
+	ret = configfs_detach_prep(dentry);
 	if (ret) {
+		configfs_detach_rollback(dentry);
 		uobject_put(parent_uobj);
 		return ret;
 	}
@@ -814,6 +856,7 @@
 #endif
 };
 
+#if 0
 int configfs_rename_dir(struct uobject * uobj, const char *new_name)
 {
 	int error = 0;
@@ -849,6 +892,7 @@
 
 	return error;
 }
+#endif
 
 static int configfs_dir_open(struct inode *inode, struct file *file)
 {
@@ -1007,7 +1051,6 @@
 
 	sd = configfs_sb->s_root->d_fsdata;
 	link_set(to_uset(sd->s_element), set);
-	set->subsys = subsys;
 
 	down(&configfs_sb->s_root->d_inode->i_sem);
 
@@ -1052,7 +1095,7 @@
 
 	down(&configfs_sb->s_root->d_inode->i_sem);
 	down(&dentry->d_inode->i_sem);
-	if (configfs_empty_dir(dentry)) {
+	if (configfs_detach_prep(dentry)) {
 		printk(KERN_ERR "configfs: Tried to unregister non-empty subsystem!\n");
 	}
 	configfs_detach_set(&set->uobj);



More information about the Ocfs2-commits mailing list