diff options
author | Tejun Heo <htejun@gmail.com> | 2007-06-13 21:27:25 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-07-12 01:09:09 +0200 |
commit | 51225039f3cf9d250596d1344494b293274b9169 (patch) | |
tree | 4e646ab37043068824a146c7353c6242a4eb72df /fs/sysfs/file.c | |
parent | sysfs: implement sysfs_get_dentry() (diff) | |
download | linux-51225039f3cf9d250596d1344494b293274b9169.tar.xz 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.c | 134 |
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); |