Commit c516865cfbac0d862d4888df91793ad1e74ffd58
Committed by
Greg Kroah-Hartman
1 parent
22f98c0cd7
Exists in
master
and in
7 other branches
[PATCH] sysfs: fix problem with duplicate sysfs directories and files
The following patch checks for existing sysfs_dirent before preparing new one while creating sysfs directories and files. Signed-off-by: Maneesh Soni <maneesh@in.ibm.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Showing 4 changed files with 39 additions and 5 deletions Side-by-side Diff
fs/sysfs/dir.c
| ... | ... | @@ -50,6 +50,32 @@ |
| 50 | 50 | return sd; |
| 51 | 51 | } |
| 52 | 52 | |
| 53 | +/** | |
| 54 | + * | |
| 55 | + * Return -EEXIST if there is already a sysfs element with the same name for | |
| 56 | + * the same parent. | |
| 57 | + * | |
| 58 | + * called with parent inode's i_mutex held | |
| 59 | + */ | |
| 60 | +int sysfs_dirent_exist(struct sysfs_dirent *parent_sd, | |
| 61 | + const unsigned char *new) | |
| 62 | +{ | |
| 63 | + struct sysfs_dirent * sd; | |
| 64 | + | |
| 65 | + list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { | |
| 66 | + if (sd->s_element) { | |
| 67 | + const unsigned char *existing = sysfs_get_name(sd); | |
| 68 | + if (strcmp(existing, new)) | |
| 69 | + continue; | |
| 70 | + else | |
| 71 | + return -EEXIST; | |
| 72 | + } | |
| 73 | + } | |
| 74 | + | |
| 75 | + return 0; | |
| 76 | +} | |
| 77 | + | |
| 78 | + | |
| 53 | 79 | int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry, |
| 54 | 80 | void * element, umode_t mode, int type) |
| 55 | 81 | { |
| ... | ... | @@ -102,7 +128,11 @@ |
| 102 | 128 | mutex_lock(&p->d_inode->i_mutex); |
| 103 | 129 | *d = lookup_one_len(n, p, strlen(n)); |
| 104 | 130 | if (!IS_ERR(*d)) { |
| 105 | - error = sysfs_make_dirent(p->d_fsdata, *d, k, mode, SYSFS_DIR); | |
| 131 | + if (sysfs_dirent_exist(p->d_fsdata, n)) | |
| 132 | + error = -EEXIST; | |
| 133 | + else | |
| 134 | + error = sysfs_make_dirent(p->d_fsdata, *d, k, mode, | |
| 135 | + SYSFS_DIR); | |
| 106 | 136 | if (!error) { |
| 107 | 137 | error = sysfs_create(*d, mode, init_dir); |
| 108 | 138 | if (!error) { |
fs/sysfs/file.c
| ... | ... | @@ -361,10 +361,12 @@ |
| 361 | 361 | { |
| 362 | 362 | struct sysfs_dirent * parent_sd = dir->d_fsdata; |
| 363 | 363 | umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG; |
| 364 | - int error = 0; | |
| 364 | + int error = -EEXIST; | |
| 365 | 365 | |
| 366 | 366 | mutex_lock(&dir->d_inode->i_mutex); |
| 367 | - error = sysfs_make_dirent(parent_sd, NULL, (void *) attr, mode, type); | |
| 367 | + if (!sysfs_dirent_exist(parent_sd, attr->name)) | |
| 368 | + error = sysfs_make_dirent(parent_sd, NULL, (void *)attr, | |
| 369 | + mode, type); | |
| 368 | 370 | mutex_unlock(&dir->d_inode->i_mutex); |
| 369 | 371 | |
| 370 | 372 | return error; |
fs/sysfs/symlink.c
| ... | ... | @@ -82,12 +82,13 @@ |
| 82 | 82 | int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char * name) |
| 83 | 83 | { |
| 84 | 84 | struct dentry * dentry = kobj->dentry; |
| 85 | - int error = 0; | |
| 85 | + int error = -EEXIST; | |
| 86 | 86 | |
| 87 | 87 | BUG_ON(!kobj || !kobj->dentry || !name); |
| 88 | 88 | |
| 89 | 89 | mutex_lock(&dentry->d_inode->i_mutex); |
| 90 | - error = sysfs_add_link(dentry, name, target); | |
| 90 | + if (!sysfs_dirent_exist(dentry->d_fsdata, name)) | |
| 91 | + error = sysfs_add_link(dentry, name, target); | |
| 91 | 92 | mutex_unlock(&dentry->d_inode->i_mutex); |
| 92 | 93 | return error; |
| 93 | 94 | } |
fs/sysfs/sysfs.h
| ... | ... | @@ -5,6 +5,7 @@ |
| 5 | 5 | extern struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent *); |
| 6 | 6 | extern int sysfs_create(struct dentry *, int mode, int (*init)(struct inode *)); |
| 7 | 7 | |
| 8 | +extern int sysfs_dirent_exist(struct sysfs_dirent *, const unsigned char *); | |
| 8 | 9 | extern int sysfs_make_dirent(struct sysfs_dirent *, struct dentry *, void *, |
| 9 | 10 | umode_t, int); |
| 10 | 11 |