diff options
author | Tejun Heo | 2007-06-13 21:27:24 +0200 |
---|---|---|
committer | Greg Kroah-Hartman | 2007-07-12 01:09:09 +0200 |
commit | fb6896da37f19be4b75154c14d1cd79231255b17 (patch) | |
tree | d1480206694a0642067dc7dc5b40bd63b038cac0 /fs/sysfs/file.c | |
parent | sysfs: use sysfs_mutex to protect the sysfs_dirent tree (diff) | |
download | kernel-qcow2-linux-fb6896da37f19be4b75154c14d1cd79231255b17.tar.gz kernel-qcow2-linux-fb6896da37f19be4b75154c14d1cd79231255b17.tar.xz kernel-qcow2-linux-fb6896da37f19be4b75154c14d1cd79231255b17.zip |
sysfs: restructure add/remove paths and fix inode update
The original add/remove code had the following problems.
* parent's timestamps are updated on dentry instantiation. this is
incorrect with reclaimable files.
* updating parent's timestamps isn't synchronized.
* parent nlink update assumes the inode is accessible which won't be
true once directory dentries are made reclaimable.
This patch restructures add/remove paths to resolve the above
problems. Add/removal are done in the following steps.
1. sysfs_addrm_start() : acquire locks including sysfs_mutex and other
resources.
2-a. sysfs_add_one() : add new sd. linking the new sd into the
children list is caller's responsibility.
2-b. sysfs_remove_one() : remove a sd. unlinking the sd from the
children list is caller's responsibility.
3. sysfs_addrm_finish() : release all resources and clean up.
Steps 2-a and/or 2-b can be repeated multiple times.
Parent's inode is looked up during sysfs_addrm_start(). If available
(always at the moment), it's pinned and nlink is updated as sd's are
added and removed. Timestamps are updated during finish if any sd has
been added or removed. If parent's inode is not available during
start, sysfs_mutex ensures that parent inode is not created till
add/remove is complete.
All the complexity is contained inside the helper functions.
Especially, dentry/inode handling is properly hidden from the rest of
sysfs which now mostly operate on sysfs_dirents. As an added bonus,
codes which use these helpers to add and remove sysfs_dirents are now
more structured and simpler.
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 | 17 |
1 files changed, 8 insertions, 9 deletions
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index d0deed3e60b5..69bacf1db596 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -416,6 +416,7 @@ int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr, int type) { umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG; + struct sysfs_addrm_cxt acxt; struct sysfs_dirent *sd; sd = sysfs_new_dirent(attr->name, mode, type); @@ -423,20 +424,18 @@ int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr, return -ENOMEM; sd->s_elem.attr.attr = (void *)attr; - mutex_lock(&sysfs_mutex); + sysfs_addrm_start(&acxt, dir_sd); if (!sysfs_find_dirent(dir_sd, attr->name)) { - sysfs_attach_dirent(sd, dir_sd, NULL); - sd = NULL; + sysfs_add_one(&acxt, sd); + sysfs_link_sibling(sd); } - mutex_unlock(&sysfs_mutex); + if (sysfs_addrm_finish(&acxt)) + return 0; - if (sd) { - sysfs_put(sd); - return -EEXIST; - } - return 0; + sysfs_put(sd); + return -EEXIST; } |