[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