aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/char_dev.c17
-rw-r--r--fs/debugfs/file.c46
-rw-r--r--fs/sysfs/dir.c37
-rw-r--r--fs/sysfs/file.c9
-rw-r--r--fs/sysfs/inode.c9
-rw-r--r--fs/sysfs/symlink.c6
-rw-r--r--fs/sysfs/sysfs.h1
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
31static DECLARE_MUTEX(chrdevs_lock); 32static DEFINE_MUTEX(chrdevs_lock);
32 33
33static struct char_device_struct { 34static struct char_device_struct {
34 struct char_device_struct *next; 35 struct char_device_struct *next;
@@ -88,13 +89,13 @@ out:
88 89
89void *acquire_chrdev_list(void) 90void *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
95void release_chrdev_list(void *dev) 96void 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;
191out: 192out:
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}
252EXPORT_SYMBOL_GPL(debugfs_create_bool); 252EXPORT_SYMBOL_GPL(debugfs_create_bool);
253 253
254static 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
262static 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 */
293struct 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}
299EXPORT_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 */
60int 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
53int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry, 79int 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
307int sysfs_rename_dir(struct kobject * kobj, const char *new_name) 338int 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
483EXPORT_SYMBOL_GPL(sysfs_create_dir);
484EXPORT_SYMBOL_GPL(sysfs_remove_dir);
485EXPORT_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)
227void sysfs_hash_and_remove(struct dentry * dir, const char * name) 226void 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);
70exit2: 71exit2:
71 kfree(sl); 72 kfree(sl);
@@ -82,12 +83,13 @@ exit1:
82int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char * name) 83int 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;
5extern struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent *); 5extern struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent *);
6extern int sysfs_create(struct dentry *, int mode, int (*init)(struct inode *)); 6extern int sysfs_create(struct dentry *, int mode, int (*init)(struct inode *));
7 7
8extern int sysfs_dirent_exist(struct sysfs_dirent *, const unsigned char *);
8extern int sysfs_make_dirent(struct sysfs_dirent *, struct dentry *, void *, 9extern int sysfs_make_dirent(struct sysfs_dirent *, struct dentry *, void *,
9 umode_t, int); 10 umode_t, int);
10 11