[PATCH 17/22] sysfs: s/sysfs_rename_mutex/sysfs_op_mutex/ and protect all tree modifying ops

Tejun Heo
2007-09-20T08:15:13Z

Rename sysfs_rename_mutex to sysfs_op_mutex and protect operations
which modify tree with it. ie.

sysfs_op_mutex : above i_mutexes in the lock hierarchy and
guarantees exclusion against all tree
modifications.

sysfs_mutex : under i_mutexes in the lock hierarchy and protects
vfs tree walking from actual tree modification.

So, when one wants to modify tree structure, it should first grab
sysfs_op_mutex mutex, at which point tree structure is guaranteed to
not change beneath it, and then sysfs_mutex when it actually modifies
the tree.

This widened op mutex will be used to make using symlinks easier and
the extended mutex coverage won't add any noticeable contention (only
one extra locking and unlocking around sysfs_mutex in add/remove
paths), not that it would matter even if it actually does.

Signed-off-by: Tejun Heo <htejun@gmail.com>
---
fs/sysfs/dir.c | 38 +++++++++++++++++++++++++-------------
fs/sysfs/sysfs.h | 2 +-
2 files changed, 26 insertions(+), 14 deletions(-)

diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index a20beff..986718c 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -18,8 +18,18 @@
#error SYSFS mode flags out of S_IFMT
#endif

+/* sysfs_op_mutex is above i_mutexes in the lock hierarchy and
+ * guarantees exclusion against operations which might change tree
+ * structure (add, remove and rename). sysfs_mutex provide exclusion
+ * between tree modifying operations and vfs tree walking and is below
+ * i_mutexes in the lock hierarchy.
+ *
+ * If a thread is holding sysfs_op_mutex, no one else will change the
+ * tree structure beneath it. When the thread actually wants to
+ * change the tree structure, it needs to grab sysfs_mutex too.
+ */
+DEFINE_MUTEX(sysfs_op_mutex);
DEFINE_MUTEX(sysfs_mutex);
-DEFINE_MUTEX(sysfs_rename_mutex);
spinlock_t sysfs_assoc_lock = SPIN_LOCK_UNLOCKED;

static spinlock_t sysfs_ino_lock = SPIN_LOCK_UNLOCKED;
@@ -87,7 +97,7 @@ static void sysfs_unlink_sibling(struct sysfs_dirent *sd)
* dentry for each step.
*
* LOCKING:
- * mutex_lock(sysfs_rename_mutex)
+ * mutex_lock(sysfs_op_mutex)
*
* RETURNS:
* Pointer to found dentry on success, ERR_PTR() value on error.
@@ -380,18 +390,19 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)
*
* This function is called when the caller is about to add or
* remove sysfs_dirents. This function initializes @acxt and
- * acquires sysfs_mutex. @acxt is used to keep and pass context
- * to other addrm functions.
+ * acquires sysfs_op_mutex and sysfs_mutex. @acxt is used to
+ * keep and pass context to other addrm functions.
*
* LOCKING:
- * Kernel thread context (may sleep). sysfs_mutex is locked on
- * return.
+ * Kernel thread context (may sleep). sysfs_op_mutex and
+ * sysfs_mutex are locked on return.
*/
void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt)
{
memset(acxt, 0, sizeof(*acxt));
acxt->removed_tail = &acxt->removed;

+ mutex_lock(&sysfs_op_mutex);
mutex_lock(&sysfs_mutex);
}

@@ -621,6 +632,7 @@ void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt)
*/
sysfs_addrm_get_parent_inode(acxt, NULL);
mutex_unlock(&sysfs_mutex);
+ mutex_unlock(&sysfs_op_mutex);

/* kill removed sysfs_dirents */
while (acxt->removed) {
@@ -679,7 +691,7 @@ struct sysfs_dirent *sysfs_insert_one(struct sysfs_dirent *parent,
* Look for sysfs_dirent with name @name under @parent_sd.
*
* LOCKING:
- * mutex_lock(sysfs_mutex)
+ * mutex_lock(sysfs_op_mutex) and/or mutex_lock(sysfs_mutex)
*
* RETURNS:
* Pointer to sysfs_dirent if found, NULL if not.
@@ -944,7 +956,7 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name)
const char *dup_name = NULL;
int error;

- mutex_lock(&sysfs_rename_mutex);
+ mutex_lock(&sysfs_op_mutex);

error = 0;
if (strcmp(sd->s_name, new_name) == 0)
@@ -997,7 +1009,7 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name)
dput(old_dentry);
dput(new_dentry);
out:
- mutex_unlock(&sysfs_rename_mutex);
+ mutex_unlock(&sysfs_op_mutex);
return error;
}

@@ -1009,7 +1021,7 @@ int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj)
struct dentry *old_dentry = NULL, *new_dentry = NULL;
int error;

- mutex_lock(&sysfs_rename_mutex);
+ mutex_lock(&sysfs_op_mutex);
BUG_ON(!sd->s_parent);
new_parent_sd = new_parent_kobj->sd ? new_parent_kobj->sd : sysfs_root;

@@ -1068,7 +1080,7 @@ again:
dput(new_parent);
dput(old_dentry);
dput(new_dentry);
- mutex_unlock(&sysfs_rename_mutex);
+ mutex_unlock(&sysfs_op_mutex);
return error;
}

@@ -1151,9 +1163,9 @@ int sysfs_chmod(struct sysfs_dirent *sd, mode_t mode)
struct iattr newattrs;
int rc;

- mutex_lock(&sysfs_rename_mutex);
+ mutex_lock(&sysfs_op_mutex);
dentry = sysfs_get_dentry(sd);
- mutex_unlock(&sysfs_rename_mutex);
+ mutex_unlock(&sysfs_op_mutex);
if (IS_ERR(dentry))
return PTR_ERR(dentry);

diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index c5593f9..16ecd6a 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -87,8 +87,8 @@ extern struct kmem_cache *sysfs_dir_cachep;
/*
* dir.c
*/
+extern struct mutex sysfs_op_mutex;
extern struct mutex sysfs_mutex;
-extern struct mutex sysfs_rename_mutex;
extern spinlock_t sysfs_assoc_lock;

extern const struct file_operations sysfs_dir_operations;
--
1.5.0.3