diff options
Diffstat (limited to 'fs/configfs/file.c')
| -rw-r--r-- | fs/configfs/file.c | 28 |
1 files changed, 18 insertions, 10 deletions
diff --git a/fs/configfs/file.c b/fs/configfs/file.c index 3527c7c6def8..a3658f9a082c 100644 --- a/fs/configfs/file.c +++ b/fs/configfs/file.c | |||
| @@ -27,19 +27,26 @@ | |||
| 27 | #include <linux/fs.h> | 27 | #include <linux/fs.h> |
| 28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
| 29 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
| 30 | #include <linux/mutex.h> | ||
| 30 | #include <asm/uaccess.h> | 31 | #include <asm/uaccess.h> |
| 31 | #include <asm/semaphore.h> | ||
| 32 | 32 | ||
| 33 | #include <linux/configfs.h> | 33 | #include <linux/configfs.h> |
| 34 | #include "configfs_internal.h" | 34 | #include "configfs_internal.h" |
| 35 | 35 | ||
| 36 | /* | ||
| 37 | * A simple attribute can only be 4096 characters. Why 4k? Because the | ||
| 38 | * original code limited it to PAGE_SIZE. That's a bad idea, though, | ||
| 39 | * because an attribute of 16k on ia64 won't work on x86. So we limit to | ||
| 40 | * 4k, our minimum common page size. | ||
| 41 | */ | ||
| 42 | #define SIMPLE_ATTR_SIZE 4096 | ||
| 36 | 43 | ||
| 37 | struct configfs_buffer { | 44 | struct configfs_buffer { |
| 38 | size_t count; | 45 | size_t count; |
| 39 | loff_t pos; | 46 | loff_t pos; |
| 40 | char * page; | 47 | char * page; |
| 41 | struct configfs_item_operations * ops; | 48 | struct configfs_item_operations * ops; |
| 42 | struct semaphore sem; | 49 | struct mutex mutex; |
| 43 | int needs_read_fill; | 50 | int needs_read_fill; |
| 44 | }; | 51 | }; |
| 45 | 52 | ||
| @@ -69,7 +76,7 @@ static int fill_read_buffer(struct dentry * dentry, struct configfs_buffer * buf | |||
| 69 | 76 | ||
| 70 | count = ops->show_attribute(item,attr,buffer->page); | 77 | count = ops->show_attribute(item,attr,buffer->page); |
| 71 | buffer->needs_read_fill = 0; | 78 | buffer->needs_read_fill = 0; |
| 72 | BUG_ON(count > (ssize_t)PAGE_SIZE); | 79 | BUG_ON(count > (ssize_t)SIMPLE_ATTR_SIZE); |
| 73 | if (count >= 0) | 80 | if (count >= 0) |
| 74 | buffer->count = count; | 81 | buffer->count = count; |
| 75 | else | 82 | else |
| @@ -102,7 +109,7 @@ configfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *pp | |||
| 102 | struct configfs_buffer * buffer = file->private_data; | 109 | struct configfs_buffer * buffer = file->private_data; |
| 103 | ssize_t retval = 0; | 110 | ssize_t retval = 0; |
| 104 | 111 | ||
| 105 | down(&buffer->sem); | 112 | mutex_lock(&buffer->mutex); |
| 106 | if (buffer->needs_read_fill) { | 113 | if (buffer->needs_read_fill) { |
| 107 | if ((retval = fill_read_buffer(file->f_path.dentry,buffer))) | 114 | if ((retval = fill_read_buffer(file->f_path.dentry,buffer))) |
| 108 | goto out; | 115 | goto out; |
| @@ -112,7 +119,7 @@ configfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *pp | |||
| 112 | retval = simple_read_from_buffer(buf, count, ppos, buffer->page, | 119 | retval = simple_read_from_buffer(buf, count, ppos, buffer->page, |
| 113 | buffer->count); | 120 | buffer->count); |
| 114 | out: | 121 | out: |
| 115 | up(&buffer->sem); | 122 | mutex_unlock(&buffer->mutex); |
| 116 | return retval; | 123 | return retval; |
| 117 | } | 124 | } |
| 118 | 125 | ||
| @@ -137,8 +144,8 @@ fill_write_buffer(struct configfs_buffer * buffer, const char __user * buf, size | |||
| 137 | if (!buffer->page) | 144 | if (!buffer->page) |
| 138 | return -ENOMEM; | 145 | return -ENOMEM; |
| 139 | 146 | ||
| 140 | if (count >= PAGE_SIZE) | 147 | if (count >= SIMPLE_ATTR_SIZE) |
| 141 | count = PAGE_SIZE - 1; | 148 | count = SIMPLE_ATTR_SIZE - 1; |
| 142 | error = copy_from_user(buffer->page,buf,count); | 149 | error = copy_from_user(buffer->page,buf,count); |
| 143 | buffer->needs_read_fill = 1; | 150 | buffer->needs_read_fill = 1; |
| 144 | /* if buf is assumed to contain a string, terminate it by \0, | 151 | /* if buf is assumed to contain a string, terminate it by \0, |
| @@ -193,13 +200,13 @@ configfs_write_file(struct file *file, const char __user *buf, size_t count, lof | |||
| 193 | struct configfs_buffer * buffer = file->private_data; | 200 | struct configfs_buffer * buffer = file->private_data; |
| 194 | ssize_t len; | 201 | ssize_t len; |
| 195 | 202 | ||
| 196 | down(&buffer->sem); | 203 | mutex_lock(&buffer->mutex); |
| 197 | len = fill_write_buffer(buffer, buf, count); | 204 | len = fill_write_buffer(buffer, buf, count); |
| 198 | if (len > 0) | 205 | if (len > 0) |
| 199 | len = flush_write_buffer(file->f_path.dentry, buffer, count); | 206 | len = flush_write_buffer(file->f_path.dentry, buffer, count); |
| 200 | if (len > 0) | 207 | if (len > 0) |
| 201 | *ppos += len; | 208 | *ppos += len; |
| 202 | up(&buffer->sem); | 209 | mutex_unlock(&buffer->mutex); |
| 203 | return len; | 210 | return len; |
| 204 | } | 211 | } |
| 205 | 212 | ||
| @@ -253,7 +260,7 @@ static int check_perm(struct inode * inode, struct file * file) | |||
| 253 | error = -ENOMEM; | 260 | error = -ENOMEM; |
| 254 | goto Enomem; | 261 | goto Enomem; |
| 255 | } | 262 | } |
| 256 | init_MUTEX(&buffer->sem); | 263 | mutex_init(&buffer->mutex); |
| 257 | buffer->needs_read_fill = 1; | 264 | buffer->needs_read_fill = 1; |
| 258 | buffer->ops = ops; | 265 | buffer->ops = ops; |
| 259 | file->private_data = buffer; | 266 | file->private_data = buffer; |
| @@ -292,6 +299,7 @@ static int configfs_release(struct inode * inode, struct file * filp) | |||
| 292 | if (buffer) { | 299 | if (buffer) { |
| 293 | if (buffer->page) | 300 | if (buffer->page) |
| 294 | free_page((unsigned long)buffer->page); | 301 | free_page((unsigned long)buffer->page); |
| 302 | mutex_destroy(&buffer->mutex); | ||
| 295 | kfree(buffer); | 303 | kfree(buffer); |
| 296 | } | 304 | } |
| 297 | return 0; | 305 | return 0; |
