aboutsummaryrefslogtreecommitdiffstats
path: root/fs/sysfs/file.c
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2007-06-13 15:27:24 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-07-11 19:09:09 -0400
commitfb6896da37f19be4b75154c14d1cd79231255b17 (patch)
treed1480206694a0642067dc7dc5b40bd63b038cac0 /fs/sysfs/file.c
parent3007e997de91ec59af39a3f9c91595b31ae6e08b (diff)
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.c17
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,
416 int type) 416 int type)
417{ 417{
418 umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG; 418 umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG;
419 struct sysfs_addrm_cxt acxt;
419 struct sysfs_dirent *sd; 420 struct sysfs_dirent *sd;
420 421
421 sd = sysfs_new_dirent(attr->name, mode, type); 422 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,
423 return -ENOMEM; 424 return -ENOMEM;
424 sd->s_elem.attr.attr = (void *)attr; 425 sd->s_elem.attr.attr = (void *)attr;
425 426
426 mutex_lock(&sysfs_mutex); 427 sysfs_addrm_start(&acxt, dir_sd);
427 428
428 if (!sysfs_find_dirent(dir_sd, attr->name)) { 429 if (!sysfs_find_dirent(dir_sd, attr->name)) {
429 sysfs_attach_dirent(sd, dir_sd, NULL); 430 sysfs_add_one(&acxt, sd);
430 sd = NULL; 431 sysfs_link_sibling(sd);
431 } 432 }
432 433
433 mutex_unlock(&sysfs_mutex); 434 if (sysfs_addrm_finish(&acxt))
435 return 0;
434 436
435 if (sd) { 437 sysfs_put(sd);
436 sysfs_put(sd); 438 return -EEXIST;
437 return -EEXIST;
438 }
439 return 0;
440} 439}
441 440
442 441