Commit 51225039 authored by Tejun Heo's avatar Tejun Heo Committed by Greg Kroah-Hartman

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: default avatarTejun Heo <htejun@gmail.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 53e0ae92
This diff is collapsed.
...@@ -362,43 +362,22 @@ static unsigned int sysfs_poll(struct file *filp, poll_table *wait) ...@@ -362,43 +362,22 @@ static unsigned int sysfs_poll(struct file *filp, poll_table *wait)
return POLLERR|POLLPRI; return POLLERR|POLLPRI;
} }
void sysfs_notify(struct kobject *k, char *dir, char *attr)
static struct dentry *step_down(struct dentry *dir, const char * name)
{ {
struct dentry * de; struct sysfs_dirent *sd = k->sd;
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;
}
void sysfs_notify(struct kobject * k, char *dir, char *attr) mutex_lock(&sysfs_mutex);
{
struct dentry *de = k->sd->s_dentry; if (sd && dir)
if (de) sd = sysfs_find_dirent(sd, dir);
dget(de); if (sd && attr)
if (de && dir) sd = sysfs_find_dirent(sd, attr);
de = step_down(de, dir); if (sd) {
if (de && attr)
de = step_down(de, attr);
if (de) {
struct sysfs_dirent * sd = de->d_fsdata;
if (sd)
atomic_inc(&sd->s_event); atomic_inc(&sd->s_event);
wake_up_interruptible(&k->poll); wake_up_interruptible(&k->poll);
dput(de);
} }
mutex_unlock(&sysfs_mutex);
} }
EXPORT_SYMBOL_GPL(sysfs_notify); EXPORT_SYMBOL_GPL(sysfs_notify);
...@@ -485,30 +464,31 @@ EXPORT_SYMBOL_GPL(sysfs_add_file_to_group); ...@@ -485,30 +464,31 @@ EXPORT_SYMBOL_GPL(sysfs_add_file_to_group);
*/ */
int sysfs_update_file(struct kobject * kobj, const struct attribute * attr) int sysfs_update_file(struct kobject * kobj, const struct attribute * attr)
{ {
struct dentry *dir = kobj->sd->s_dentry; struct sysfs_dirent *victim_sd = NULL;
struct dentry * victim; struct dentry *victim = NULL;
int res = -ENOENT; int rc;
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);
/** rc = -ENOENT;
* Drop the reference acquired from lookup_one_len() above. victim_sd = sysfs_get_dirent(kobj->sd, attr->name);
*/ if (!victim_sd)
dput(victim); 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) ...@@ -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) int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode)
{ {
struct dentry *dir = kobj->sd->s_dentry; struct sysfs_dirent *victim_sd = NULL;
struct dentry *victim; struct dentry *victim = NULL;
struct inode * inode; struct inode * inode;
struct iattr newattrs; struct iattr newattrs;
int res = -ENOENT; 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_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; inode = victim->d_inode;
mutex_lock(&inode->i_mutex); mutex_lock(&inode->i_mutex);
newattrs.ia_mode = (mode & S_IALLUGO) | newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
(inode->i_mode & ~S_IALLUGO);
newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
res = notify_change(victim, &newattrs); rc = notify_change(victim, &newattrs);
mutex_unlock(&inode->i_mutex); mutex_unlock(&inode->i_mutex);
} out:
dput(victim); dput(victim);
} sysfs_put(victim_sd);
mutex_unlock(&dir->d_inode->i_mutex); return rc;
return res;
} }
EXPORT_SYMBOL_GPL(sysfs_chmod_file); EXPORT_SYMBOL_GPL(sysfs_chmod_file);
......
...@@ -24,7 +24,7 @@ static const struct super_operations sysfs_ops = { ...@@ -24,7 +24,7 @@ static const struct super_operations sysfs_ops = {
.drop_inode = sysfs_delete_inode, .drop_inode = sysfs_delete_inode,
}; };
static struct sysfs_dirent sysfs_root = { struct sysfs_dirent sysfs_root = {
.s_count = ATOMIC_INIT(1), .s_count = ATOMIC_INIT(1),
.s_flags = SYSFS_ROOT, .s_flags = SYSFS_ROOT,
.s_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO, .s_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
......
...@@ -52,6 +52,7 @@ struct sysfs_addrm_cxt { ...@@ -52,6 +52,7 @@ struct sysfs_addrm_cxt {
}; };
extern struct vfsmount * sysfs_mount; extern struct vfsmount * sysfs_mount;
extern struct sysfs_dirent sysfs_root;
extern struct kmem_cache *sysfs_dir_cachep; extern struct kmem_cache *sysfs_dir_cachep;
extern struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd); extern struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd);
......
...@@ -81,7 +81,6 @@ struct sysfs_ops { ...@@ -81,7 +81,6 @@ struct sysfs_ops {
#define SYSFS_KOBJ_ATTR 0x0004 #define SYSFS_KOBJ_ATTR 0x0004
#define SYSFS_KOBJ_BIN_ATTR 0x0008 #define SYSFS_KOBJ_BIN_ATTR 0x0008
#define SYSFS_KOBJ_LINK 0x0020 #define SYSFS_KOBJ_LINK 0x0020
#define SYSFS_NOT_PINNED (SYSFS_KOBJ_ATTR | SYSFS_KOBJ_BIN_ATTR | SYSFS_KOBJ_LINK)
#define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK) #define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK)
#define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK #define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment