aboutsummaryrefslogtreecommitdiffstats
path: root/fs
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
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')
-rw-r--r--fs/sysfs/dir.c231
-rw-r--r--fs/sysfs/file.c134
-rw-r--r--fs/sysfs/mount.c2
-rw-r--r--fs/sysfs/sysfs.h1
4 files changed, 187 insertions, 181 deletions
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 987211296106..aee966c44aac 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -568,10 +568,10 @@ static void sysfs_drop_dentry(struct sysfs_dirent *sd)
568 spin_unlock(&dcache_lock); 568 spin_unlock(&dcache_lock);
569 spin_unlock(&sysfs_assoc_lock); 569 spin_unlock(&sysfs_assoc_lock);
570 570
571 dput(dentry); 571 /* dentries for shadowed inodes are pinned, unpin */
572 /* XXX: unpin if directory, this will go away soon */ 572 if (dentry && sysfs_is_shadowed_inode(dentry->d_inode))
573 if (sysfs_type(sd) == SYSFS_DIR)
574 dput(dentry); 573 dput(dentry);
574 dput(dentry);
575 575
576 /* adjust nlink and update timestamp */ 576 /* adjust nlink and update timestamp */
577 inode = ilookup(sysfs_sb, sd->s_ino); 577 inode = ilookup(sysfs_sb, sd->s_ino);
@@ -686,69 +686,29 @@ struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd,
686static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, 686static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
687 const char *name, struct sysfs_dirent **p_sd) 687 const char *name, struct sysfs_dirent **p_sd)
688{ 688{
689 struct dentry *parent = parent_sd->s_dentry;
690 struct sysfs_addrm_cxt acxt;
691 int error;
692 umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO; 689 umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
693 struct dentry *dentry; 690 struct sysfs_addrm_cxt acxt;
694 struct inode *inode;
695 struct sysfs_dirent *sd; 691 struct sysfs_dirent *sd;
696 692
697 sysfs_addrm_start(&acxt, parent_sd);
698
699 /* allocate */ 693 /* allocate */
700 dentry = lookup_one_len(name, parent, strlen(name));
701 if (IS_ERR(dentry)) {
702 error = PTR_ERR(dentry);
703 goto out_finish;
704 }
705
706 error = -EEXIST;
707 if (dentry->d_inode)
708 goto out_dput;
709
710 error = -ENOMEM;
711 sd = sysfs_new_dirent(name, mode, SYSFS_DIR); 694 sd = sysfs_new_dirent(name, mode, SYSFS_DIR);
712 if (!sd) 695 if (!sd)
713 goto out_drop; 696 return -ENOMEM;
714 sd->s_elem.dir.kobj = kobj; 697 sd->s_elem.dir.kobj = kobj;
715 698
716 inode = sysfs_get_inode(sd);
717 if (!inode)
718 goto out_sput;
719
720 if (inode->i_state & I_NEW) {
721 inode->i_op = &sysfs_dir_inode_operations;
722 inode->i_fop = &sysfs_dir_operations;
723 /* directory inodes start off with i_nlink == 2 (for ".") */
724 inc_nlink(inode);
725 }
726
727 /* link in */ 699 /* link in */
728 error = -EEXIST; 700 sysfs_addrm_start(&acxt, parent_sd);
729 if (sysfs_find_dirent(parent_sd, name)) 701 if (!sysfs_find_dirent(parent_sd, name)) {
730 goto out_iput; 702 sysfs_add_one(&acxt, sd);
731 703 sysfs_link_sibling(sd);
732 sysfs_add_one(&acxt, sd); 704 }
733 sysfs_link_sibling(sd); 705 if (sysfs_addrm_finish(&acxt)) {
734 sysfs_instantiate(dentry, inode); 706 *p_sd = sd;
735 sysfs_attach_dentry(sd, dentry); 707 return 0;
736 708 }
737 *p_sd = sd;
738 error = 0;
739 goto out_finish; /* pin directory dentry in core */
740 709
741 out_iput:
742 iput(inode);
743 out_sput:
744 sysfs_put(sd); 710 sysfs_put(sd);
745 out_drop: 711 return -EEXIST;
746 d_drop(dentry);
747 out_dput:
748 dput(dentry);
749 out_finish:
750 sysfs_addrm_finish(&acxt);
751 return error;
752} 712}
753 713
754int sysfs_create_subdir(struct kobject *kobj, const char *name, 714int sysfs_create_subdir(struct kobject *kobj, const char *name,
@@ -785,6 +745,17 @@ int sysfs_create_dir(struct kobject *kobj,
785 return error; 745 return error;
786} 746}
787 747
748static int sysfs_count_nlink(struct sysfs_dirent *sd)
749{
750 struct sysfs_dirent *child;
751 int nr = 0;
752
753 for (child = sd->s_children; child; child = child->s_sibling)
754 if (sysfs_type(child) == SYSFS_DIR)
755 nr++;
756 return nr + 2;
757}
758
788static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, 759static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
789 struct nameidata *nd) 760 struct nameidata *nd)
790{ 761{
@@ -795,7 +766,7 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
795 int found = 0; 766 int found = 0;
796 767
797 for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) { 768 for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) {
798 if ((sysfs_type(sd) & SYSFS_NOT_PINNED) && 769 if (sysfs_type(sd) &&
799 !strcmp(sd->s_name, dentry->d_name.name)) { 770 !strcmp(sd->s_name, dentry->d_name.name)) {
800 found = 1; 771 found = 1;
801 break; 772 break;
@@ -816,6 +787,11 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
816 if (inode->i_state & I_NEW) { 787 if (inode->i_state & I_NEW) {
817 /* initialize inode according to type */ 788 /* initialize inode according to type */
818 switch (sysfs_type(sd)) { 789 switch (sysfs_type(sd)) {
790 case SYSFS_DIR:
791 inode->i_op = &sysfs_dir_inode_operations;
792 inode->i_fop = &sysfs_dir_operations;
793 inode->i_nlink = sysfs_count_nlink(sd);
794 break;
819 case SYSFS_KOBJ_ATTR: 795 case SYSFS_KOBJ_ATTR:
820 inode->i_size = PAGE_SIZE; 796 inode->i_size = PAGE_SIZE;
821 inode->i_fop = &sysfs_file_operations; 797 inode->i_fop = &sysfs_file_operations;
@@ -876,7 +852,7 @@ static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd)
876 while (*pos) { 852 while (*pos) {
877 struct sysfs_dirent *sd = *pos; 853 struct sysfs_dirent *sd = *pos;
878 854
879 if (sysfs_type(sd) && (sysfs_type(sd) & SYSFS_NOT_PINNED)) { 855 if (sysfs_type(sd) && sysfs_type(sd) != SYSFS_DIR) {
880 *pos = sd->s_sibling; 856 *pos = sd->s_sibling;
881 sd->s_sibling = NULL; 857 sd->s_sibling = NULL;
882 sysfs_remove_one(&acxt, sd); 858 sysfs_remove_one(&acxt, sd);
@@ -912,14 +888,25 @@ int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd,
912 const char *new_name) 888 const char *new_name)
913{ 889{
914 struct sysfs_dirent *sd = kobj->sd; 890 struct sysfs_dirent *sd = kobj->sd;
915 struct dentry *new_parent = new_parent_sd->s_dentry; 891 struct dentry *new_parent = NULL;
916 struct dentry *new_dentry; 892 struct dentry *old_dentry = NULL, *new_dentry = NULL;
917 char *dup_name; 893 const char *dup_name = NULL;
918 int error; 894 int error;
919 895
920 if (!new_parent_sd) 896 /* get dentries */
921 return -EFAULT; 897 old_dentry = sysfs_get_dentry(sd);
898 if (IS_ERR(old_dentry)) {
899 error = PTR_ERR(old_dentry);
900 goto out_dput;
901 }
902
903 new_parent = sysfs_get_dentry(new_parent_sd);
904 if (IS_ERR(new_parent)) {
905 error = PTR_ERR(new_parent);
906 goto out_dput;
907 }
922 908
909 /* lock new_parent and get dentry for new name */
923 mutex_lock(&new_parent->d_inode->i_mutex); 910 mutex_lock(&new_parent->d_inode->i_mutex);
924 911
925 new_dentry = lookup_one_len(new_name, new_parent, strlen(new_name)); 912 new_dentry = lookup_one_len(new_name, new_parent, strlen(new_name));
@@ -933,14 +920,14 @@ int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd,
933 * shadows of the same directory 920 * shadows of the same directory
934 */ 921 */
935 error = -EINVAL; 922 error = -EINVAL;
936 if (sd->s_parent->s_dentry->d_inode != new_parent->d_inode || 923 if (old_dentry->d_parent->d_inode != new_parent->d_inode ||
937 new_dentry->d_parent->d_inode != new_parent->d_inode || 924 new_dentry->d_parent->d_inode != new_parent->d_inode ||
938 new_dentry == sd->s_dentry) 925 old_dentry == new_dentry)
939 goto out_dput; 926 goto out_unlock;
940 927
941 error = -EEXIST; 928 error = -EEXIST;
942 if (new_dentry->d_inode) 929 if (new_dentry->d_inode)
943 goto out_dput; 930 goto out_unlock;
944 931
945 /* rename kobject and sysfs_dirent */ 932 /* rename kobject and sysfs_dirent */
946 error = -ENOMEM; 933 error = -ENOMEM;
@@ -950,9 +937,9 @@ int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd,
950 937
951 error = kobject_set_name(kobj, "%s", new_name); 938 error = kobject_set_name(kobj, "%s", new_name);
952 if (error) 939 if (error)
953 goto out_free; 940 goto out_drop;
954 941
955 kfree(sd->s_name); 942 dup_name = sd->s_name;
956 sd->s_name = new_name; 943 sd->s_name = new_name;
957 944
958 /* move under the new parent */ 945 /* move under the new parent */
@@ -972,45 +959,58 @@ int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd,
972 error = 0; 959 error = 0;
973 goto out_unlock; 960 goto out_unlock;
974 961
975 out_free:
976 kfree(dup_name);
977 out_drop: 962 out_drop:
978 d_drop(new_dentry); 963 d_drop(new_dentry);
979 out_dput:
980 dput(new_dentry);
981 out_unlock: 964 out_unlock:
982 mutex_unlock(&new_parent->d_inode->i_mutex); 965 mutex_unlock(&new_parent->d_inode->i_mutex);
966 out_dput:
967 kfree(dup_name);
968 dput(new_parent);
969 dput(old_dentry);
970 dput(new_dentry);
983 return error; 971 return error;
984} 972}
985 973
986int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent) 974int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj)
987{ 975{
988 struct dentry *old_parent_dentry, *new_parent_dentry, *new_dentry; 976 struct sysfs_dirent *sd = kobj->sd;
989 struct sysfs_dirent *new_parent_sd, *sd; 977 struct sysfs_dirent *new_parent_sd;
978 struct dentry *old_parent, *new_parent = NULL;
979 struct dentry *old_dentry = NULL, *new_dentry = NULL;
990 int error; 980 int error;
991 981
992 old_parent_dentry = kobj->parent ? 982 BUG_ON(!sd->s_parent);
993 kobj->parent->sd->s_dentry : sysfs_mount->mnt_sb->s_root; 983 new_parent_sd = new_parent_kobj->sd ? new_parent_kobj->sd : &sysfs_root;
994 new_parent_dentry = new_parent ? 984
995 new_parent->sd->s_dentry : sysfs_mount->mnt_sb->s_root; 985 /* get dentries */
986 old_dentry = sysfs_get_dentry(sd);
987 if (IS_ERR(old_dentry)) {
988 error = PTR_ERR(old_dentry);
989 goto out_dput;
990 }
991 old_parent = sd->s_parent->s_dentry;
992
993 new_parent = sysfs_get_dentry(new_parent_sd);
994 if (IS_ERR(new_parent)) {
995 error = PTR_ERR(new_parent);
996 goto out_dput;
997 }
996 998
997 if (old_parent_dentry->d_inode == new_parent_dentry->d_inode) 999 if (old_parent->d_inode == new_parent->d_inode) {
998 return 0; /* nothing to move */ 1000 error = 0;
1001 goto out_dput; /* nothing to move */
1002 }
999again: 1003again:
1000 mutex_lock(&old_parent_dentry->d_inode->i_mutex); 1004 mutex_lock(&old_parent->d_inode->i_mutex);
1001 if (!mutex_trylock(&new_parent_dentry->d_inode->i_mutex)) { 1005 if (!mutex_trylock(&new_parent->d_inode->i_mutex)) {
1002 mutex_unlock(&old_parent_dentry->d_inode->i_mutex); 1006 mutex_unlock(&old_parent->d_inode->i_mutex);
1003 goto again; 1007 goto again;
1004 } 1008 }
1005 1009
1006 new_parent_sd = new_parent_dentry->d_fsdata; 1010 new_dentry = lookup_one_len(kobj->name, new_parent, strlen(kobj->name));
1007 sd = kobj->sd;
1008
1009 new_dentry = lookup_one_len(kobj->name, new_parent_dentry,
1010 strlen(kobj->name));
1011 if (IS_ERR(new_dentry)) { 1011 if (IS_ERR(new_dentry)) {
1012 error = PTR_ERR(new_dentry); 1012 error = PTR_ERR(new_dentry);
1013 goto out; 1013 goto out_unlock;
1014 } else 1014 } else
1015 error = 0; 1015 error = 0;
1016 d_add(new_dentry, NULL); 1016 d_add(new_dentry, NULL);
@@ -1027,10 +1027,14 @@ again:
1027 sysfs_link_sibling(sd); 1027 sysfs_link_sibling(sd);
1028 1028
1029 mutex_unlock(&sysfs_mutex); 1029 mutex_unlock(&sysfs_mutex);
1030out:
1031 mutex_unlock(&new_parent_dentry->d_inode->i_mutex);
1032 mutex_unlock(&old_parent_dentry->d_inode->i_mutex);
1033 1030
1031 out_unlock:
1032 mutex_unlock(&new_parent->d_inode->i_mutex);
1033 mutex_unlock(&old_parent->d_inode->i_mutex);
1034 out_dput:
1035 dput(new_parent);
1036 dput(old_dentry);
1037 dput(new_dentry);
1034 return error; 1038 return error;
1035} 1039}
1036 1040
@@ -1191,12 +1195,20 @@ static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin)
1191int sysfs_make_shadowed_dir(struct kobject *kobj, 1195int sysfs_make_shadowed_dir(struct kobject *kobj,
1192 void * (*follow_link)(struct dentry *, struct nameidata *)) 1196 void * (*follow_link)(struct dentry *, struct nameidata *))
1193{ 1197{
1198 struct dentry *dentry;
1194 struct inode *inode; 1199 struct inode *inode;
1195 struct inode_operations *i_op; 1200 struct inode_operations *i_op;
1196 1201
1197 inode = kobj->sd->s_dentry->d_inode; 1202 /* get dentry for @kobj->sd, dentry of a shadowed dir is pinned */
1198 if (inode->i_op != &sysfs_dir_inode_operations) 1203 dentry = sysfs_get_dentry(kobj->sd);
1204 if (IS_ERR(dentry))
1205 return PTR_ERR(dentry);
1206
1207 inode = dentry->d_inode;
1208 if (inode->i_op != &sysfs_dir_inode_operations) {
1209 dput(dentry);
1199 return -EINVAL; 1210 return -EINVAL;
1211 }
1200 1212
1201 i_op = kmalloc(sizeof(*i_op), GFP_KERNEL); 1213 i_op = kmalloc(sizeof(*i_op), GFP_KERNEL);
1202 if (!i_op) 1214 if (!i_op)
@@ -1223,17 +1235,23 @@ int sysfs_make_shadowed_dir(struct kobject *kobj,
1223 1235
1224struct sysfs_dirent *sysfs_create_shadow_dir(struct kobject *kobj) 1236struct sysfs_dirent *sysfs_create_shadow_dir(struct kobject *kobj)
1225{ 1237{
1226 struct dentry *dir = kobj->sd->s_dentry; 1238 struct sysfs_dirent *parent_sd = kobj->sd->s_parent;
1227 struct inode *inode = dir->d_inode; 1239 struct dentry *dir, *parent, *shadow;
1228 struct dentry *parent = dir->d_parent; 1240 struct inode *inode;
1229 struct sysfs_dirent *parent_sd = parent->d_fsdata;
1230 struct dentry *shadow;
1231 struct sysfs_dirent *sd; 1241 struct sysfs_dirent *sd;
1232 struct sysfs_addrm_cxt acxt; 1242 struct sysfs_addrm_cxt acxt;
1233 1243
1244 dir = sysfs_get_dentry(kobj->sd);
1245 if (IS_ERR(dir)) {
1246 sd = (void *)dir;
1247 goto out;
1248 }
1249 parent = dir->d_parent;
1250
1251 inode = dir->d_inode;
1234 sd = ERR_PTR(-EINVAL); 1252 sd = ERR_PTR(-EINVAL);
1235 if (!sysfs_is_shadowed_inode(inode)) 1253 if (!sysfs_is_shadowed_inode(inode))
1236 goto out; 1254 goto out_dput;
1237 1255
1238 shadow = d_alloc(parent, &dir->d_name); 1256 shadow = d_alloc(parent, &dir->d_name);
1239 if (!shadow) 1257 if (!shadow)
@@ -1258,12 +1276,15 @@ struct sysfs_dirent *sysfs_create_shadow_dir(struct kobject *kobj)
1258 1276
1259 dget(shadow); /* Extra count - pin the dentry in core */ 1277 dget(shadow); /* Extra count - pin the dentry in core */
1260 1278
1261out: 1279 goto out_dput;
1262 return sd; 1280
1263nomem: 1281 nomem:
1264 dput(shadow); 1282 dput(shadow);
1265 sd = ERR_PTR(-ENOMEM); 1283 sd = ERR_PTR(-ENOMEM);
1266 goto out; 1284 out_dput:
1285 dput(dir);
1286 out:
1287 return sd;
1267} 1288}
1268 1289
1269/** 1290/**
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
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
index 078537e5d696..402cc356203c 100644
--- a/fs/sysfs/mount.c
+++ b/fs/sysfs/mount.c
@@ -24,7 +24,7 @@ static const struct super_operations sysfs_ops = {
24 .drop_inode = sysfs_delete_inode, 24 .drop_inode = sysfs_delete_inode,
25}; 25};
26 26
27static struct sysfs_dirent sysfs_root = { 27struct sysfs_dirent sysfs_root = {
28 .s_count = ATOMIC_INIT(1), 28 .s_count = ATOMIC_INIT(1),
29 .s_flags = SYSFS_ROOT, 29 .s_flags = SYSFS_ROOT,
30 .s_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO, 30 .s_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index 72530dc666fd..6a37f2386a8d 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -52,6 +52,7 @@ struct sysfs_addrm_cxt {
52}; 52};
53 53
54extern struct vfsmount * sysfs_mount; 54extern struct vfsmount * sysfs_mount;
55extern struct sysfs_dirent sysfs_root;
55extern struct kmem_cache *sysfs_dir_cachep; 56extern struct kmem_cache *sysfs_dir_cachep;
56 57
57extern struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd); 58extern struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd);