diff options
Diffstat (limited to 'fs/sysfs')
| -rw-r--r-- | fs/sysfs/dir.c | 37 | ||||
| -rw-r--r-- | fs/sysfs/file.c | 9 | ||||
| -rw-r--r-- | fs/sysfs/inode.c | 9 | ||||
| -rw-r--r-- | fs/sysfs/symlink.c | 6 | ||||
| -rw-r--r-- | fs/sysfs/sysfs.h | 1 |
5 files changed, 48 insertions, 14 deletions
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 49bd219275db..9ee956864445 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c | |||
| @@ -50,6 +50,32 @@ static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent * parent_sd, | |||
| 50 | return sd; | 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 | int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry, | 79 | int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry, |
| 54 | void * element, umode_t mode, int type) | 80 | void * element, umode_t mode, int type) |
| 55 | { | 81 | { |
| @@ -102,7 +128,11 @@ static int create_dir(struct kobject * k, struct dentry * p, | |||
| 102 | mutex_lock(&p->d_inode->i_mutex); | 128 | mutex_lock(&p->d_inode->i_mutex); |
| 103 | *d = lookup_one_len(n, p, strlen(n)); | 129 | *d = lookup_one_len(n, p, strlen(n)); |
| 104 | if (!IS_ERR(*d)) { | 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 | if (!error) { | 136 | if (!error) { |
| 107 | error = sysfs_create(*d, mode, init_dir); | 137 | error = sysfs_create(*d, mode, init_dir); |
| 108 | if (!error) { | 138 | if (!error) { |
| @@ -302,6 +332,7 @@ void sysfs_remove_dir(struct kobject * kobj) | |||
| 302 | * Drop reference from dget() on entrance. | 332 | * Drop reference from dget() on entrance. |
| 303 | */ | 333 | */ |
| 304 | dput(dentry); | 334 | dput(dentry); |
| 335 | kobj->dentry = NULL; | ||
| 305 | } | 336 | } |
| 306 | 337 | ||
| 307 | int sysfs_rename_dir(struct kobject * kobj, const char *new_name) | 338 | int sysfs_rename_dir(struct kobject * kobj, const char *new_name) |
| @@ -479,7 +510,3 @@ struct file_operations sysfs_dir_operations = { | |||
| 479 | .read = generic_read_dir, | 510 | .read = generic_read_dir, |
| 480 | .readdir = sysfs_readdir, | 511 | .readdir = sysfs_readdir, |
| 481 | }; | 512 | }; |
| 482 | |||
| 483 | EXPORT_SYMBOL_GPL(sysfs_create_dir); | ||
| 484 | EXPORT_SYMBOL_GPL(sysfs_remove_dir); | ||
| 485 | EXPORT_SYMBOL_GPL(sysfs_rename_dir); | ||
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index d0e3d8495165..5e83e7246788 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c | |||
| @@ -301,9 +301,8 @@ static int check_perm(struct inode * inode, struct file * file) | |||
| 301 | /* No error? Great, allocate a buffer for the file, and store it | 301 | /* No error? Great, allocate a buffer for the file, and store it |
| 302 | * it in file->private_data for easy access. | 302 | * it in file->private_data for easy access. |
| 303 | */ | 303 | */ |
| 304 | buffer = kmalloc(sizeof(struct sysfs_buffer),GFP_KERNEL); | 304 | buffer = kzalloc(sizeof(struct sysfs_buffer), GFP_KERNEL); |
| 305 | if (buffer) { | 305 | if (buffer) { |
| 306 | memset(buffer,0,sizeof(struct sysfs_buffer)); | ||
| 307 | init_MUTEX(&buffer->sem); | 306 | init_MUTEX(&buffer->sem); |
| 308 | buffer->needs_read_fill = 1; | 307 | buffer->needs_read_fill = 1; |
| 309 | buffer->ops = ops; | 308 | buffer->ops = ops; |
| @@ -362,10 +361,12 @@ int sysfs_add_file(struct dentry * dir, const struct attribute * attr, int type) | |||
| 362 | { | 361 | { |
| 363 | struct sysfs_dirent * parent_sd = dir->d_fsdata; | 362 | struct sysfs_dirent * parent_sd = dir->d_fsdata; |
| 364 | umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG; | 363 | umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG; |
| 365 | int error = 0; | 364 | int error = -EEXIST; |
| 366 | 365 | ||
| 367 | mutex_lock(&dir->d_inode->i_mutex); | 366 | mutex_lock(&dir->d_inode->i_mutex); |
| 368 | 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); | ||
| 369 | mutex_unlock(&dir->d_inode->i_mutex); | 370 | mutex_unlock(&dir->d_inode->i_mutex); |
| 370 | 371 | ||
| 371 | return error; | 372 | return error; |
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 689f7bcfaf30..4c29ac41ac3e 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c | |||
| @@ -54,11 +54,10 @@ int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) | |||
| 54 | 54 | ||
| 55 | if (!sd_iattr) { | 55 | if (!sd_iattr) { |
| 56 | /* setting attributes for the first time, allocate now */ | 56 | /* setting attributes for the first time, allocate now */ |
| 57 | sd_iattr = kmalloc(sizeof(struct iattr), GFP_KERNEL); | 57 | sd_iattr = kzalloc(sizeof(struct iattr), GFP_KERNEL); |
| 58 | if (!sd_iattr) | 58 | if (!sd_iattr) |
| 59 | return -ENOMEM; | 59 | return -ENOMEM; |
| 60 | /* assign default attributes */ | 60 | /* assign default attributes */ |
| 61 | memset(sd_iattr, 0, sizeof(struct iattr)); | ||
| 62 | sd_iattr->ia_mode = sd->s_mode; | 61 | sd_iattr->ia_mode = sd->s_mode; |
| 63 | sd_iattr->ia_uid = 0; | 62 | sd_iattr->ia_uid = 0; |
| 64 | sd_iattr->ia_gid = 0; | 63 | sd_iattr->ia_gid = 0; |
| @@ -227,12 +226,16 @@ void sysfs_drop_dentry(struct sysfs_dirent * sd, struct dentry * parent) | |||
| 227 | void sysfs_hash_and_remove(struct dentry * dir, const char * name) | 226 | void sysfs_hash_and_remove(struct dentry * dir, const char * name) |
| 228 | { | 227 | { |
| 229 | struct sysfs_dirent * sd; | 228 | struct sysfs_dirent * sd; |
| 230 | struct sysfs_dirent * parent_sd = dir->d_fsdata; | 229 | struct sysfs_dirent * parent_sd; |
| 230 | |||
| 231 | if (!dir) | ||
| 232 | return; | ||
| 231 | 233 | ||
| 232 | if (dir->d_inode == NULL) | 234 | if (dir->d_inode == NULL) |
| 233 | /* no inode means this hasn't been made visible yet */ | 235 | /* no inode means this hasn't been made visible yet */ |
| 234 | return; | 236 | return; |
| 235 | 237 | ||
| 238 | parent_sd = dir->d_fsdata; | ||
| 236 | mutex_lock(&dir->d_inode->i_mutex); | 239 | mutex_lock(&dir->d_inode->i_mutex); |
| 237 | list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { | 240 | list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { |
| 238 | if (!sd->s_element) | 241 | if (!sd->s_element) |
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index e38d6338a20d..d2eac3ceed5f 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c | |||
| @@ -66,6 +66,7 @@ static int sysfs_add_link(struct dentry * parent, const char * name, struct kobj | |||
| 66 | if (!error) | 66 | if (!error) |
| 67 | return 0; | 67 | return 0; |
| 68 | 68 | ||
| 69 | kobject_put(target); | ||
| 69 | kfree(sl->link_name); | 70 | kfree(sl->link_name); |
| 70 | exit2: | 71 | exit2: |
| 71 | kfree(sl); | 72 | kfree(sl); |
| @@ -82,12 +83,13 @@ exit1: | |||
| 82 | int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char * name) | 83 | int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char * name) |
| 83 | { | 84 | { |
| 84 | struct dentry * dentry = kobj->dentry; | 85 | struct dentry * dentry = kobj->dentry; |
| 85 | int error = 0; | 86 | int error = -EEXIST; |
| 86 | 87 | ||
| 87 | BUG_ON(!kobj || !kobj->dentry || !name); | 88 | BUG_ON(!kobj || !kobj->dentry || !name); |
| 88 | 89 | ||
| 89 | mutex_lock(&dentry->d_inode->i_mutex); | 90 | mutex_lock(&dentry->d_inode->i_mutex); |
| 90 | error = sysfs_add_link(dentry, name, target); | 91 | if (!sysfs_dirent_exist(dentry->d_fsdata, name)) |
| 92 | error = sysfs_add_link(dentry, name, target); | ||
| 91 | mutex_unlock(&dentry->d_inode->i_mutex); | 93 | mutex_unlock(&dentry->d_inode->i_mutex); |
| 92 | return error; | 94 | return error; |
| 93 | } | 95 | } |
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 3f8953e0e5d0..cf11d5b789d9 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h | |||
| @@ -5,6 +5,7 @@ extern kmem_cache_t *sysfs_dir_cachep; | |||
| 5 | extern struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent *); | 5 | extern struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent *); |
| 6 | extern int sysfs_create(struct dentry *, int mode, int (*init)(struct inode *)); | 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 | extern int sysfs_make_dirent(struct sysfs_dirent *, struct dentry *, void *, | 9 | extern int sysfs_make_dirent(struct sysfs_dirent *, struct dentry *, void *, |
| 9 | umode_t, int); | 10 | umode_t, int); |
| 10 | 11 | ||
