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) atomic_inc(&sd->s_event);
de = step_down(de, attr);
if (de) {
struct sysfs_dirent * sd = de->d_fsdata;
if (sd)
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); rc = -ENOENT;
victim = lookup_one_len(attr->name, dir, strlen(attr->name)); victim_sd = sysfs_get_dirent(kobj->sd, attr->name);
if (!IS_ERR(victim)) { if (!victim_sd)
/* make sure dentry is really there */ goto out;
if (victim->d_inode &&
(victim->d_parent->d_inode == dir->d_inode)) { victim = sysfs_get_dentry(victim_sd);
victim->d_inode->i_mtime = CURRENT_TIME; if (IS_ERR(victim)) {
fsnotify_modify(victim); rc = PTR_ERR(victim);
res = 0; victim = NULL;
} else goto out;
d_drop(victim);
/**
* Drop the reference acquired from lookup_one_len() above.
*/
dput(victim);
} }
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;
mutex_lock(&dir->d_inode->i_mutex); rc = -ENOENT;
victim = lookup_one_len(attr->name, dir, strlen(attr->name)); victim_sd = sysfs_get_dirent(kobj->sd, attr->name);
if (!IS_ERR(victim)) { if (!victim_sd)
if (victim->d_inode && goto out;
(victim->d_parent->d_inode == dir->d_inode)) {
inode = victim->d_inode; victim = sysfs_get_dentry(victim_sd);
mutex_lock(&inode->i_mutex); if (IS_ERR(victim)) {
newattrs.ia_mode = (mode & S_IALLUGO) | rc = PTR_ERR(victim);
(inode->i_mode & ~S_IALLUGO); victim = NULL;
newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; goto out;
res = notify_change(victim, &newattrs);
mutex_unlock(&inode->i_mutex);
}
dput(victim);
} }
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); 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