diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/char_dev.c | 17 | ||||
-rw-r--r-- | fs/debugfs/file.c | 46 | ||||
-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 |
7 files changed, 103 insertions, 22 deletions
diff --git a/fs/char_dev.c b/fs/char_dev.c index 21195c481637..5c36345c9bf7 100644 --- a/fs/char_dev.c +++ b/fs/char_dev.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/kobject.h> | 19 | #include <linux/kobject.h> |
20 | #include <linux/kobj_map.h> | 20 | #include <linux/kobj_map.h> |
21 | #include <linux/cdev.h> | 21 | #include <linux/cdev.h> |
22 | #include <linux/mutex.h> | ||
22 | 23 | ||
23 | #ifdef CONFIG_KMOD | 24 | #ifdef CONFIG_KMOD |
24 | #include <linux/kmod.h> | 25 | #include <linux/kmod.h> |
@@ -28,7 +29,7 @@ static struct kobj_map *cdev_map; | |||
28 | 29 | ||
29 | #define MAX_PROBE_HASH 255 /* random */ | 30 | #define MAX_PROBE_HASH 255 /* random */ |
30 | 31 | ||
31 | static DECLARE_MUTEX(chrdevs_lock); | 32 | static DEFINE_MUTEX(chrdevs_lock); |
32 | 33 | ||
33 | static struct char_device_struct { | 34 | static struct char_device_struct { |
34 | struct char_device_struct *next; | 35 | struct char_device_struct *next; |
@@ -88,13 +89,13 @@ out: | |||
88 | 89 | ||
89 | void *acquire_chrdev_list(void) | 90 | void *acquire_chrdev_list(void) |
90 | { | 91 | { |
91 | down(&chrdevs_lock); | 92 | mutex_lock(&chrdevs_lock); |
92 | return get_next_chrdev(NULL); | 93 | return get_next_chrdev(NULL); |
93 | } | 94 | } |
94 | 95 | ||
95 | void release_chrdev_list(void *dev) | 96 | void release_chrdev_list(void *dev) |
96 | { | 97 | { |
97 | up(&chrdevs_lock); | 98 | mutex_unlock(&chrdevs_lock); |
98 | kfree(dev); | 99 | kfree(dev); |
99 | } | 100 | } |
100 | 101 | ||
@@ -151,7 +152,7 @@ __register_chrdev_region(unsigned int major, unsigned int baseminor, | |||
151 | 152 | ||
152 | memset(cd, 0, sizeof(struct char_device_struct)); | 153 | memset(cd, 0, sizeof(struct char_device_struct)); |
153 | 154 | ||
154 | down(&chrdevs_lock); | 155 | mutex_lock(&chrdevs_lock); |
155 | 156 | ||
156 | /* temporary */ | 157 | /* temporary */ |
157 | if (major == 0) { | 158 | if (major == 0) { |
@@ -186,10 +187,10 @@ __register_chrdev_region(unsigned int major, unsigned int baseminor, | |||
186 | } | 187 | } |
187 | cd->next = *cp; | 188 | cd->next = *cp; |
188 | *cp = cd; | 189 | *cp = cd; |
189 | up(&chrdevs_lock); | 190 | mutex_unlock(&chrdevs_lock); |
190 | return cd; | 191 | return cd; |
191 | out: | 192 | out: |
192 | up(&chrdevs_lock); | 193 | mutex_unlock(&chrdevs_lock); |
193 | kfree(cd); | 194 | kfree(cd); |
194 | return ERR_PTR(ret); | 195 | return ERR_PTR(ret); |
195 | } | 196 | } |
@@ -200,7 +201,7 @@ __unregister_chrdev_region(unsigned major, unsigned baseminor, int minorct) | |||
200 | struct char_device_struct *cd = NULL, **cp; | 201 | struct char_device_struct *cd = NULL, **cp; |
201 | int i = major_to_index(major); | 202 | int i = major_to_index(major); |
202 | 203 | ||
203 | down(&chrdevs_lock); | 204 | mutex_lock(&chrdevs_lock); |
204 | for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next) | 205 | for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next) |
205 | if ((*cp)->major == major && | 206 | if ((*cp)->major == major && |
206 | (*cp)->baseminor == baseminor && | 207 | (*cp)->baseminor == baseminor && |
@@ -210,7 +211,7 @@ __unregister_chrdev_region(unsigned major, unsigned baseminor, int minorct) | |||
210 | cd = *cp; | 211 | cd = *cp; |
211 | *cp = cd->next; | 212 | *cp = cd->next; |
212 | } | 213 | } |
213 | up(&chrdevs_lock); | 214 | mutex_unlock(&chrdevs_lock); |
214 | return cd; | 215 | return cd; |
215 | } | 216 | } |
216 | 217 | ||
diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index d575452cd9f7..40c4fc973fad 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c | |||
@@ -251,3 +251,49 @@ struct dentry *debugfs_create_bool(const char *name, mode_t mode, | |||
251 | } | 251 | } |
252 | EXPORT_SYMBOL_GPL(debugfs_create_bool); | 252 | EXPORT_SYMBOL_GPL(debugfs_create_bool); |
253 | 253 | ||
254 | static ssize_t read_file_blob(struct file *file, char __user *user_buf, | ||
255 | size_t count, loff_t *ppos) | ||
256 | { | ||
257 | struct debugfs_blob_wrapper *blob = file->private_data; | ||
258 | return simple_read_from_buffer(user_buf, count, ppos, blob->data, | ||
259 | blob->size); | ||
260 | } | ||
261 | |||
262 | static struct file_operations fops_blob = { | ||
263 | .read = read_file_blob, | ||
264 | .open = default_open, | ||
265 | }; | ||
266 | |||
267 | /** | ||
268 | * debugfs_create_blob - create a file in the debugfs filesystem that is | ||
269 | * used to read and write a binary blob. | ||
270 | * | ||
271 | * @name: a pointer to a string containing the name of the file to create. | ||
272 | * @mode: the permission that the file should have | ||
273 | * @parent: a pointer to the parent dentry for this file. This should be a | ||
274 | * directory dentry if set. If this paramater is NULL, then the | ||
275 | * file will be created in the root of the debugfs filesystem. | ||
276 | * @blob: a pointer to a struct debugfs_blob_wrapper which contains a pointer | ||
277 | * to the blob data and the size of the data. | ||
278 | * | ||
279 | * This function creates a file in debugfs with the given name that exports | ||
280 | * @blob->data as a binary blob. If the @mode variable is so set it can be | ||
281 | * read from. Writing is not supported. | ||
282 | * | ||
283 | * This function will return a pointer to a dentry if it succeeds. This | ||
284 | * pointer must be passed to the debugfs_remove() function when the file is | ||
285 | * to be removed (no automatic cleanup happens if your module is unloaded, | ||
286 | * you are responsible here.) If an error occurs, NULL will be returned. | ||
287 | * | ||
288 | * If debugfs is not enabled in the kernel, the value -ENODEV will be | ||
289 | * returned. It is not wise to check for this value, but rather, check for | ||
290 | * NULL or !NULL instead as to eliminate the need for #ifdef in the calling | ||
291 | * code. | ||
292 | */ | ||
293 | struct dentry *debugfs_create_blob(const char *name, mode_t mode, | ||
294 | struct dentry *parent, | ||
295 | struct debugfs_blob_wrapper *blob) | ||
296 | { | ||
297 | return debugfs_create_file(name, mode, parent, blob, &fops_blob); | ||
298 | } | ||
299 | EXPORT_SYMBOL_GPL(debugfs_create_blob); | ||
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 | ||