summaryrefslogtreecommitdiffstats
path: root/fs/sysfs/file.c
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2007-06-14 04:27:25 +0900
committerGreg Kroah-Hartman <gregkh@suse.de>2007-07-11 16:09:09 -0700
commit51225039f3cf9d250596d1344494b293274b9169 (patch)
tree4e646ab37043068824a146c7353c6242a4eb72df /fs/sysfs/file.c
parent53e0ae92690c52eceb997905d85fbb42de5fff63 (diff)
downloadlinux-51225039f3cf9d250596d1344494b293274b9169.tar.gz
linux-51225039f3cf9d250596d1344494b293274b9169.tar.bz2
linux-51225039f3cf9d250596d1344494b293274b9169.zip
sysfs: make directory dentries and inodes reclaimable
This patch makes dentries and inodes for sysfs directories reclaimable. * sysfs_notify() is modified to walk sysfs_dirent tree instead of dentry tree. * sysfs_update_file() and sysfs_chmod_file() use sysfs_get_dentry() to grab the victim dentry. * sysfs_rename_dir() and sysfs_move_dir() grab all dentries using sysfs_get_dentry() on startup. * Dentries for all shadowed directories are pinned in memory to serve as lookup start point. Signed-off-by: Tejun Heo <htejun@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'fs/sysfs/file.c')
-rw-r--r--fs/sysfs/file.c134
1 files changed, 59 insertions, 75 deletions
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index 69bacf1db596..cc497994b2a8 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -362,43 +362,22 @@ static unsigned int sysfs_poll(struct file *filp, poll_table *wait)
return POLLERR|POLLPRI;
}
-
-static struct dentry *step_down(struct dentry *dir, const char * name)
+void sysfs_notify(struct kobject *k, char *dir, char *attr)
{
- struct dentry * de;
-
- if (dir == NULL || dir->d_inode == NULL)
- return NULL;
-
- mutex_lock(&dir->d_inode->i_mutex);
- de = lookup_one_len(name, dir, strlen(name));
- mutex_unlock(&dir->d_inode->i_mutex);
- dput(dir);
- if (IS_ERR(de))
- return NULL;
- if (de->d_inode == NULL) {
- dput(de);
- return NULL;
- }
- return de;
-}
+ struct sysfs_dirent *sd = k->sd;
-void sysfs_notify(struct kobject * k, char *dir, char *attr)
-{
- struct dentry *de = k->sd->s_dentry;
- if (de)
- dget(de);
- if (de && dir)
- de = step_down(de, dir);
- if (de && attr)
- de = step_down(de, attr);
- if (de) {
- struct sysfs_dirent * sd = de->d_fsdata;
- if (sd)
- atomic_inc(&sd->s_event);
+ mutex_lock(&sysfs_mutex);
+
+ if (sd && dir)
+ sd = sysfs_find_dirent(sd, dir);
+ if (sd && attr)
+ sd = sysfs_find_dirent(sd, attr);
+ if (sd) {
+ atomic_inc(&sd->s_event);
wake_up_interruptible(&k->poll);
- dput(de);
}
+
+ mutex_unlock(&sysfs_mutex);
}
EXPORT_SYMBOL_GPL(sysfs_notify);
@@ -485,30 +464,31 @@ EXPORT_SYMBOL_GPL(sysfs_add_file_to_group);
*/
int sysfs_update_file(struct kobject * kobj, const struct attribute * attr)
{
- struct dentry *dir = kobj->sd->s_dentry;
- struct dentry * victim;
- int res = -ENOENT;
-
- mutex_lock(&dir->d_inode->i_mutex);
- victim = lookup_one_len(attr->name, dir, strlen(attr->name));
- if (!IS_ERR(victim)) {
- /* make sure dentry is really there */
- if (victim->d_inode &&
- (victim->d_parent->d_inode == dir->d_inode)) {
- victim->d_inode->i_mtime = CURRENT_TIME;
- fsnotify_modify(victim);
- res = 0;
- } else
- d_drop(victim);
-
- /**
- * Drop the reference acquired from lookup_one_len() above.
- */
- dput(victim);
+ struct sysfs_dirent *victim_sd = NULL;
+ struct dentry *victim = NULL;
+ int rc;
+
+ rc = -ENOENT;
+ victim_sd = sysfs_get_dirent(kobj->sd, attr->name);
+ if (!victim_sd)
+ goto out;
+
+ victim = sysfs_get_dentry(victim_sd);
+ if (IS_ERR(victim)) {
+ rc = PTR_ERR(victim);
+ victim = NULL;
+ goto out;
}
- mutex_unlock(&dir->d_inode->i_mutex);
- return res;
+ mutex_lock(&victim->d_inode->i_mutex);
+ victim->d_inode->i_mtime = CURRENT_TIME;
+ fsnotify_modify(victim);
+ mutex_unlock(&victim->d_inode->i_mutex);
+ rc = 0;
+ out:
+ dput(victim);
+ sysfs_put(victim_sd);
+ return rc;
}
@@ -521,30 +501,34 @@ int sysfs_update_file(struct kobject * kobj, const struct attribute * attr)
*/
int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode)
{
- struct dentry *dir = kobj->sd->s_dentry;
- struct dentry *victim;
+ struct sysfs_dirent *victim_sd = NULL;
+ struct dentry *victim = NULL;
struct inode * inode;
struct iattr newattrs;
- int res = -ENOENT;
-
- mutex_lock(&dir->d_inode->i_mutex);
- victim = lookup_one_len(attr->name, dir, strlen(attr->name));
- if (!IS_ERR(victim)) {
- if (victim->d_inode &&
- (victim->d_parent->d_inode == dir->d_inode)) {
- inode = victim->d_inode;
- mutex_lock(&inode->i_mutex);
- newattrs.ia_mode = (mode & S_IALLUGO) |
- (inode->i_mode & ~S_IALLUGO);
- newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
- res = notify_change(victim, &newattrs);
- mutex_unlock(&inode->i_mutex);
- }
- dput(victim);
+ int rc;
+
+ rc = -ENOENT;
+ victim_sd = sysfs_get_dirent(kobj->sd, attr->name);
+ if (!victim_sd)
+ goto out;
+
+ victim = sysfs_get_dentry(victim_sd);
+ if (IS_ERR(victim)) {
+ rc = PTR_ERR(victim);
+ victim = NULL;
+ goto out;
}
- mutex_unlock(&dir->d_inode->i_mutex);
- return res;
+ inode = victim->d_inode;
+ mutex_lock(&inode->i_mutex);
+ newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
+ newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
+ rc = notify_change(victim, &newattrs);
+ mutex_unlock(&inode->i_mutex);
+ out:
+ dput(victim);
+ sysfs_put(victim_sd);
+ return rc;
}
EXPORT_SYMBOL_GPL(sysfs_chmod_file);