aboutsummaryrefslogtreecommitdiff
path: root/fs/sysfs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/sysfs')
-rw-r--r--fs/sysfs/dir.c91
1 files changed, 16 insertions, 75 deletions
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 9fe83d23dc2..1c3dc5d01cc 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -78,9 +78,8 @@ static void sysfs_unlink_sibling(struct sysfs_dirent *sd)
* @sd: sysfs_dirent of interest
*
* Get dentry for @sd. Dentry is looked up if currently not
- * present. This function climbs sysfs_dirent tree till it
- * reaches a sysfs_dirent with valid dentry attached and descends
- * down from there looking up dentry for each step.
+ * present. This function descends from the root looking up
+ * dentry for each step.
*
* LOCKING:
* mutex_lock(sysfs_rename_mutex)
@@ -90,86 +89,28 @@ static void sysfs_unlink_sibling(struct sysfs_dirent *sd)
*/
struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd)
{
- struct sysfs_dirent *cur;
- struct dentry *parent_dentry, *dentry;
- int i, depth;
+ struct dentry *dentry = dget(sysfs_sb->s_root);
- /* Find the first parent which has valid s_dentry and get the
- * dentry.
- */
- mutex_lock(&sysfs_mutex);
- restart0:
- spin_lock(&sysfs_assoc_lock);
- restart1:
- spin_lock(&dcache_lock);
-
- dentry = NULL;
- depth = 0;
- cur = sd;
- while (!cur->s_dentry || !cur->s_dentry->d_inode) {
- if (cur->s_flags & SYSFS_FLAG_REMOVED) {
- dentry = ERR_PTR(-ENOENT);
- depth = 0;
- break;
- }
- cur = cur->s_parent;
- depth++;
- }
- if (!IS_ERR(dentry))
- dentry = dget_locked(cur->s_dentry);
+ while (dentry->d_fsdata != sd) {
+ struct sysfs_dirent *cur;
+ struct dentry *parent;
- spin_unlock(&dcache_lock);
- spin_unlock(&sysfs_assoc_lock);
-
- /* from the found dentry, look up depth times */
- while (depth--) {
- /* find and get depth'th ancestor */
- for (cur = sd, i = 0; cur && i < depth; i++)
+ /* find the first ancestor which hasn't been looked up */
+ cur = sd;
+ while (cur->s_parent != dentry->d_fsdata)
cur = cur->s_parent;
- /* This can happen if tree structure was modified due
- * to move/rename. Restart.
- */
- if (i != depth) {
- dput(dentry);
- goto restart0;
- }
-
- sysfs_get(cur);
-
- mutex_unlock(&sysfs_mutex);
-
/* look it up */
- parent_dentry = dentry;
- mutex_lock(&parent_dentry->d_inode->i_mutex);
- dentry = lookup_one_len_kern(cur->s_name, parent_dentry,
+ parent = dentry;
+ mutex_lock(&parent->d_inode->i_mutex);
+ dentry = lookup_one_len_kern(cur->s_name, parent,
strlen(cur->s_name));
- mutex_unlock(&parent_dentry->d_inode->i_mutex);
- dput(parent_dentry);
-
- if (IS_ERR(dentry)) {
- sysfs_put(cur);
- return dentry;
- }
+ mutex_unlock(&parent->d_inode->i_mutex);
+ dput(parent);
- mutex_lock(&sysfs_mutex);
- spin_lock(&sysfs_assoc_lock);
-
- /* This, again, can happen if tree structure has
- * changed and we looked up the wrong thing. Restart.
- */
- if (cur->s_dentry != dentry) {
- dput(dentry);
- sysfs_put(cur);
- goto restart1;
- }
-
- spin_unlock(&sysfs_assoc_lock);
-
- sysfs_put(cur);
+ if (IS_ERR(dentry))
+ break;
}
-
- mutex_unlock(&sysfs_mutex);
return dentry;
}