aboutsummaryrefslogtreecommitdiffstats
path: root/fs/sysfs/file.c
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2007-06-13 15:27:25 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-07-11 19:09:09 -0400
commit51225039f3cf9d250596d1344494b293274b9169 (patch)
tree4e646ab37043068824a146c7353c6242a4eb72df /fs/sysfs/file.c
parent53e0ae92690c52eceb997905d85fbb42de5fff63 (diff)
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.c134
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)
362 return POLLERR|POLLPRI; 362 return POLLERR|POLLPRI;
363} 363}
364 364
365 365void sysfs_notify(struct kobject *k, char *dir, char *attr)
366static struct dentry *step_down(struct dentry *dir, const char * name)
367{ 366{
368 struct dentry * de; 367 struct sysfs_dirent *sd = k->sd;
369
370 if (dir == NULL || dir->d_inode == NULL)
371 return NULL;
372
373 mutex_lock(&dir->d_inode->i_mutex);
374 de = lookup_one_len(name, dir, strlen(name));
375 mutex_unlock(&dir->d_inode->i_mutex);
376 dput(dir);
377 if (IS_ERR(de))
378 return NULL;
379 if (de->d_inode == NULL) {
380 dput(de);
381 return NULL;
382 }
383 return de;
384}
385 368
386void sysfs_notify(struct kobject * k, char *dir, char *attr) 369 mutex_lock(&sysfs_mutex);
387{ 370
388 struct dentry *de = k->sd->s_dentry; 371 if (sd && dir)
389 if (de) 372 sd = sysfs_find_dirent(sd, dir);
390 dget(de); 373 if (sd && attr)
391 if (de && dir) 374 sd = sysfs_find_dirent(sd, attr);
392 de = step_down(de, dir); 375 if (sd) {
393 if (de && attr) 376 atomic_inc(&sd->s_event);
394 de = step_down(de, attr);
395 if (de) {
396 struct sysfs_dirent * sd = de->d_fsdata;
397 if (sd)
398 atomic_inc(&sd->s_event);
399 wake_up_interruptible(&k->poll); 377 wake_up_interruptible(&k->poll);
400 dput(de);
401 } 378 }
379
380 mutex_unlock(&sysfs_mutex);
402} 381}
403EXPORT_SYMBOL_GPL(sysfs_notify); 382EXPORT_SYMBOL_GPL(sysfs_notify);
404 383
@@ -485,30 +464,31 @@ EXPORT_SYMBOL_GPL(sysfs_add_file_to_group);
485 */ 464 */
486int sysfs_update_file(struct kobject * kobj, const struct attribute * attr) 465int sysfs_update_file(struct kobject * kobj, const struct attribute * attr)
487{ 466{
488 struct dentry *dir = kobj->sd->s_dentry; 467 struct sysfs_dirent *victim_sd = NULL;
489 struct dentry * victim; 468 struct dentry *victim = NULL;
490 int res = -ENOENT; 469 int rc;
491 470
492 mutex_lock(&dir->d_inode->i_mutex); 471 rc = -ENOENT;
493 victim = lookup_one_len(attr->name, dir, strlen(attr->name)); 472 victim_sd = sysfs_get_dirent(kobj->sd, attr->name);
494 if (!IS_ERR(victim)) { 473 if (!victim_sd)
495 /* make sure dentry is really there */ 474 goto out;
496 if (victim->d_inode && 475
497 (victim->d_parent->d_inode == dir->d_inode)) { 476 victim = sysfs_get_dentry(victim_sd);
498 victim->d_inode->i_mtime = CURRENT_TIME; 477 if (IS_ERR(victim)) {
499 fsnotify_modify(victim); 478 rc = PTR_ERR(victim);
500 res = 0; 479 victim = NULL;
501 } else 480 goto out;
502 d_drop(victim);
503
504 /**
505 * Drop the reference acquired from lookup_one_len() above.
506 */
507 dput(victim);
508 } 481 }
509 mutex_unlock(&dir->d_inode->i_mutex);
510 482
511 return res; 483 mutex_lock(&victim->d_inode->i_mutex);
484 victim->d_inode->i_mtime = CURRENT_TIME;
485 fsnotify_modify(victim);
486 mutex_unlock(&victim->d_inode->i_mutex);
487 rc = 0;
488 out:
489 dput(victim);
490 sysfs_put(victim_sd);
491 return rc;
512} 492}
513 493
514 494
@@ -521,30 +501,34 @@ int sysfs_update_file(struct kobject * kobj, const struct attribute * attr)
521 */ 501 */
522int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode) 502int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode)
523{ 503{
524 struct dentry *dir = kobj->sd->s_dentry; 504 struct sysfs_dirent *victim_sd = NULL;
525 struct dentry *victim; 505 struct dentry *victim = NULL;
526 struct inode * inode; 506 struct inode * inode;
527 struct iattr newattrs; 507 struct iattr newattrs;
528 int res = -ENOENT; 508 int rc;
529 509
530 mutex_lock(&dir->d_inode->i_mutex); 510 rc = -ENOENT;
531 victim = lookup_one_len(attr->name, dir, strlen(attr->name)); 511 victim_sd = sysfs_get_dirent(kobj->sd, attr->name);
532 if (!IS_ERR(victim)) { 512 if (!victim_sd)
533 if (victim->d_inode && 513 goto out;
534 (victim->d_parent->d_inode == dir->d_inode)) { 514
535 inode = victim->d_inode; 515 victim = sysfs_get_dentry(victim_sd);
536 mutex_lock(&inode->i_mutex); 516 if (IS_ERR(victim)) {
537 newattrs.ia_mode = (mode & S_IALLUGO) | 517 rc = PTR_ERR(victim);
538 (inode->i_mode & ~S_IALLUGO); 518 victim = NULL;
539 newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; 519 goto out;
540 res = notify_change(victim, &newattrs);
541 mutex_unlock(&inode->i_mutex);
542 }
543 dput(victim);
544 } 520 }
545 mutex_unlock(&dir->d_inode->i_mutex);
546 521
547 return res; 522 inode = victim->d_inode;
523 mutex_lock(&inode->i_mutex);
524 newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
525 newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
526 rc = notify_change(victim, &newattrs);
527 mutex_unlock(&inode->i_mutex);
528 out:
529 dput(victim);
530 sysfs_put(victim_sd);
531 return rc;
548} 532}
549EXPORT_SYMBOL_GPL(sysfs_chmod_file); 533EXPORT_SYMBOL_GPL(sysfs_chmod_file);
550 534