diff options
Diffstat (limited to 'sound')
-rw-r--r-- | sound/core/info.c | 149 |
1 files changed, 79 insertions, 70 deletions
diff --git a/sound/core/info.c b/sound/core/info.c index 9c288539e99d..86366839c4bb 100644 --- a/sound/core/info.c +++ b/sound/core/info.c | |||
@@ -21,7 +21,6 @@ | |||
21 | 21 | ||
22 | #include <sound/driver.h> | 22 | #include <sound/driver.h> |
23 | #include <linux/init.h> | 23 | #include <linux/init.h> |
24 | #include <linux/vmalloc.h> | ||
25 | #include <linux/time.h> | 24 | #include <linux/time.h> |
26 | #include <linux/smp_lock.h> | 25 | #include <linux/smp_lock.h> |
27 | #include <linux/string.h> | 26 | #include <linux/string.h> |
@@ -82,6 +81,24 @@ static int snd_info_version_init(void); | |||
82 | static int snd_info_version_done(void); | 81 | static int snd_info_version_done(void); |
83 | 82 | ||
84 | 83 | ||
84 | /* resize the proc r/w buffer */ | ||
85 | static int resize_info_buffer(struct snd_info_buffer *buffer, | ||
86 | unsigned int nsize) | ||
87 | { | ||
88 | char *nbuf; | ||
89 | |||
90 | nsize = PAGE_ALIGN(nsize); | ||
91 | nbuf = kmalloc(nsize, GFP_KERNEL); | ||
92 | if (! nbuf) | ||
93 | return -ENOMEM; | ||
94 | |||
95 | memcpy(nbuf, buffer->buffer, buffer->len); | ||
96 | kfree(buffer->buffer); | ||
97 | buffer->buffer = nbuf; | ||
98 | buffer->len = nsize; | ||
99 | return 0; | ||
100 | } | ||
101 | |||
85 | /** | 102 | /** |
86 | * snd_iprintf - printf on the procfs buffer | 103 | * snd_iprintf - printf on the procfs buffer |
87 | * @buffer: the procfs buffer | 104 | * @buffer: the procfs buffer |
@@ -95,17 +112,25 @@ int snd_iprintf(struct snd_info_buffer *buffer, char *fmt,...) | |||
95 | { | 112 | { |
96 | va_list args; | 113 | va_list args; |
97 | int len, res; | 114 | int len, res; |
115 | int err = 0; | ||
98 | 116 | ||
99 | if (buffer->stop || buffer->error) | 117 | if (buffer->stop || buffer->error) |
100 | return 0; | 118 | return 0; |
101 | len = buffer->len - buffer->size; | 119 | len = buffer->len - buffer->size; |
102 | va_start(args, fmt); | 120 | va_start(args, fmt); |
103 | res = vsnprintf(buffer->curr, len, fmt, args); | 121 | for (;;) { |
104 | va_end(args); | 122 | res = vsnprintf(buffer->buffer + buffer->curr, len, fmt, args); |
105 | if (res >= len) { | 123 | if (res < len) |
106 | buffer->stop = 1; | 124 | break; |
107 | return 0; | 125 | err = resize_info_buffer(buffer, buffer->len + PAGE_SIZE); |
126 | if (err < 0) | ||
127 | break; | ||
128 | len = buffer->len - buffer->size; | ||
108 | } | 129 | } |
130 | va_end(args); | ||
131 | |||
132 | if (err < 0) | ||
133 | return err; | ||
109 | buffer->curr += res; | 134 | buffer->curr += res; |
110 | buffer->size += res; | 135 | buffer->size += res; |
111 | return res; | 136 | return res; |
@@ -225,7 +250,7 @@ static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer | |||
225 | struct snd_info_private_data *data; | 250 | struct snd_info_private_data *data; |
226 | struct snd_info_entry *entry; | 251 | struct snd_info_entry *entry; |
227 | struct snd_info_buffer *buf; | 252 | struct snd_info_buffer *buf; |
228 | size_t size = 0; | 253 | ssize_t size = 0; |
229 | loff_t pos; | 254 | loff_t pos; |
230 | 255 | ||
231 | data = file->private_data; | 256 | data = file->private_data; |
@@ -241,14 +266,20 @@ static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer | |||
241 | buf = data->wbuffer; | 266 | buf = data->wbuffer; |
242 | if (buf == NULL) | 267 | if (buf == NULL) |
243 | return -EIO; | 268 | return -EIO; |
244 | if (pos >= buf->len) | 269 | mutex_unlock(&entry->access); |
245 | return -ENOMEM; | 270 | if (pos + count >= buf->len) { |
246 | size = buf->len - pos; | 271 | if (resize_info_buffer(buf, pos + count)) { |
247 | size = min(count, size); | 272 | mutex_unlock(&entry->access); |
248 | if (copy_from_user(buf->buffer + pos, buffer, size)) | 273 | return -ENOMEM; |
274 | } | ||
275 | } | ||
276 | if (copy_from_user(buf->buffer + pos, buffer, count)) { | ||
277 | mutex_unlock(&entry->access); | ||
249 | return -EFAULT; | 278 | return -EFAULT; |
250 | if ((long)buf->size < pos + size) | 279 | } |
251 | buf->size = pos + size; | 280 | buf->size = pos + count; |
281 | mutex_unlock(&entry->access); | ||
282 | size = count; | ||
252 | break; | 283 | break; |
253 | case SNDRV_INFO_CONTENT_DATA: | 284 | case SNDRV_INFO_CONTENT_DATA: |
254 | if (entry->c.ops->write) | 285 | if (entry->c.ops->write) |
@@ -283,18 +314,14 @@ static int snd_info_entry_open(struct inode *inode, struct file *file) | |||
283 | } | 314 | } |
284 | mode = file->f_flags & O_ACCMODE; | 315 | mode = file->f_flags & O_ACCMODE; |
285 | if (mode == O_RDONLY || mode == O_RDWR) { | 316 | if (mode == O_RDONLY || mode == O_RDWR) { |
286 | if ((entry->content == SNDRV_INFO_CONTENT_TEXT && | 317 | if ((entry->content == SNDRV_INFO_CONTENT_DATA && |
287 | !entry->c.text.read_size) || | ||
288 | (entry->content == SNDRV_INFO_CONTENT_DATA && | ||
289 | entry->c.ops->read == NULL)) { | 318 | entry->c.ops->read == NULL)) { |
290 | err = -ENODEV; | 319 | err = -ENODEV; |
291 | goto __error; | 320 | goto __error; |
292 | } | 321 | } |
293 | } | 322 | } |
294 | if (mode == O_WRONLY || mode == O_RDWR) { | 323 | if (mode == O_WRONLY || mode == O_RDWR) { |
295 | if ((entry->content == SNDRV_INFO_CONTENT_TEXT && | 324 | if ((entry->content == SNDRV_INFO_CONTENT_DATA && |
296 | !entry->c.text.write_size) || | ||
297 | (entry->content == SNDRV_INFO_CONTENT_DATA && | ||
298 | entry->c.ops->write == NULL)) { | 325 | entry->c.ops->write == NULL)) { |
299 | err = -ENODEV; | 326 | err = -ENODEV; |
300 | goto __error; | 327 | goto __error; |
@@ -310,49 +337,23 @@ static int snd_info_entry_open(struct inode *inode, struct file *file) | |||
310 | case SNDRV_INFO_CONTENT_TEXT: | 337 | case SNDRV_INFO_CONTENT_TEXT: |
311 | if (mode == O_RDONLY || mode == O_RDWR) { | 338 | if (mode == O_RDONLY || mode == O_RDWR) { |
312 | buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); | 339 | buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); |
313 | if (buffer == NULL) { | 340 | if (buffer == NULL) |
314 | kfree(data); | 341 | goto __nomem; |
315 | err = -ENOMEM; | ||
316 | goto __error; | ||
317 | } | ||
318 | buffer->len = (entry->c.text.read_size + | ||
319 | (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); | ||
320 | buffer->buffer = vmalloc(buffer->len); | ||
321 | if (buffer->buffer == NULL) { | ||
322 | kfree(buffer); | ||
323 | kfree(data); | ||
324 | err = -ENOMEM; | ||
325 | goto __error; | ||
326 | } | ||
327 | buffer->curr = buffer->buffer; | ||
328 | data->rbuffer = buffer; | 342 | data->rbuffer = buffer; |
343 | buffer->len = PAGE_SIZE; | ||
344 | buffer->buffer = kmalloc(buffer->len, GFP_KERNEL); | ||
345 | if (buffer->buffer == NULL) | ||
346 | goto __nomem; | ||
329 | } | 347 | } |
330 | if (mode == O_WRONLY || mode == O_RDWR) { | 348 | if (mode == O_WRONLY || mode == O_RDWR) { |
331 | buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); | 349 | buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); |
332 | if (buffer == NULL) { | 350 | if (buffer == NULL) |
333 | if (mode == O_RDWR) { | 351 | goto __nomem; |
334 | vfree(data->rbuffer->buffer); | ||
335 | kfree(data->rbuffer); | ||
336 | } | ||
337 | kfree(data); | ||
338 | err = -ENOMEM; | ||
339 | goto __error; | ||
340 | } | ||
341 | buffer->len = (entry->c.text.write_size + | ||
342 | (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); | ||
343 | buffer->buffer = vmalloc(buffer->len); | ||
344 | if (buffer->buffer == NULL) { | ||
345 | if (mode == O_RDWR) { | ||
346 | vfree(data->rbuffer->buffer); | ||
347 | kfree(data->rbuffer); | ||
348 | } | ||
349 | kfree(buffer); | ||
350 | kfree(data); | ||
351 | err = -ENOMEM; | ||
352 | goto __error; | ||
353 | } | ||
354 | buffer->curr = buffer->buffer; | ||
355 | data->wbuffer = buffer; | 352 | data->wbuffer = buffer; |
353 | buffer->len = PAGE_SIZE; | ||
354 | buffer->buffer = kmalloc(buffer->len, GFP_KERNEL); | ||
355 | if (buffer->buffer == NULL) | ||
356 | goto __nomem; | ||
356 | } | 357 | } |
357 | break; | 358 | break; |
358 | case SNDRV_INFO_CONTENT_DATA: /* data */ | 359 | case SNDRV_INFO_CONTENT_DATA: /* data */ |
@@ -377,6 +378,17 @@ static int snd_info_entry_open(struct inode *inode, struct file *file) | |||
377 | } | 378 | } |
378 | return 0; | 379 | return 0; |
379 | 380 | ||
381 | __nomem: | ||
382 | if (data->rbuffer) { | ||
383 | kfree(data->rbuffer->buffer); | ||
384 | kfree(data->rbuffer); | ||
385 | } | ||
386 | if (data->wbuffer) { | ||
387 | kfree(data->wbuffer->buffer); | ||
388 | kfree(data->wbuffer); | ||
389 | } | ||
390 | kfree(data); | ||
391 | err = -ENOMEM; | ||
380 | __error: | 392 | __error: |
381 | module_put(entry->module); | 393 | module_put(entry->module); |
382 | __error1: | 394 | __error1: |
@@ -395,11 +407,11 @@ static int snd_info_entry_release(struct inode *inode, struct file *file) | |||
395 | entry = data->entry; | 407 | entry = data->entry; |
396 | switch (entry->content) { | 408 | switch (entry->content) { |
397 | case SNDRV_INFO_CONTENT_TEXT: | 409 | case SNDRV_INFO_CONTENT_TEXT: |
398 | if (mode == O_RDONLY || mode == O_RDWR) { | 410 | if (data->rbuffer) { |
399 | vfree(data->rbuffer->buffer); | 411 | kfree(data->rbuffer->buffer); |
400 | kfree(data->rbuffer); | 412 | kfree(data->rbuffer); |
401 | } | 413 | } |
402 | if (mode == O_WRONLY || mode == O_RDWR) { | 414 | if (data->wbuffer) { |
403 | if (entry->c.text.write) { | 415 | if (entry->c.text.write) { |
404 | entry->c.text.write(entry, data->wbuffer); | 416 | entry->c.text.write(entry, data->wbuffer); |
405 | if (data->wbuffer->error) { | 417 | if (data->wbuffer->error) { |
@@ -408,7 +420,7 @@ static int snd_info_entry_release(struct inode *inode, struct file *file) | |||
408 | data->wbuffer->error); | 420 | data->wbuffer->error); |
409 | } | 421 | } |
410 | } | 422 | } |
411 | vfree(data->wbuffer->buffer); | 423 | kfree(data->wbuffer->buffer); |
412 | kfree(data->wbuffer); | 424 | kfree(data->wbuffer); |
413 | } | 425 | } |
414 | break; | 426 | break; |
@@ -668,24 +680,22 @@ int snd_info_get_line(struct snd_info_buffer *buffer, char *line, int len) | |||
668 | if (len <= 0 || buffer->stop || buffer->error) | 680 | if (len <= 0 || buffer->stop || buffer->error) |
669 | return 1; | 681 | return 1; |
670 | while (--len > 0) { | 682 | while (--len > 0) { |
671 | c = *buffer->curr++; | 683 | c = buffer->buffer[buffer->curr++]; |
672 | if (c == '\n') { | 684 | if (c == '\n') { |
673 | if ((buffer->curr - buffer->buffer) >= (long)buffer->size) { | 685 | if (buffer->curr >= buffer->size) |
674 | buffer->stop = 1; | 686 | buffer->stop = 1; |
675 | } | ||
676 | break; | 687 | break; |
677 | } | 688 | } |
678 | *line++ = c; | 689 | *line++ = c; |
679 | if ((buffer->curr - buffer->buffer) >= (long)buffer->size) { | 690 | if (buffer->curr >= buffer->size) { |
680 | buffer->stop = 1; | 691 | buffer->stop = 1; |
681 | break; | 692 | break; |
682 | } | 693 | } |
683 | } | 694 | } |
684 | while (c != '\n' && !buffer->stop) { | 695 | while (c != '\n' && !buffer->stop) { |
685 | c = *buffer->curr++; | 696 | c = buffer->buffer[buffer->curr++]; |
686 | if ((buffer->curr - buffer->buffer) >= (long)buffer->size) { | 697 | if (buffer->curr >= buffer->size) |
687 | buffer->stop = 1; | 698 | buffer->stop = 1; |
688 | } | ||
689 | } | 699 | } |
690 | *line = '\0'; | 700 | *line = '\0'; |
691 | return 0; | 701 | return 0; |
@@ -978,7 +988,6 @@ static int __init snd_info_version_init(void) | |||
978 | entry = snd_info_create_module_entry(THIS_MODULE, "version", NULL); | 988 | entry = snd_info_create_module_entry(THIS_MODULE, "version", NULL); |
979 | if (entry == NULL) | 989 | if (entry == NULL) |
980 | return -ENOMEM; | 990 | return -ENOMEM; |
981 | entry->c.text.read_size = 256; | ||
982 | entry->c.text.read = snd_info_version_read; | 991 | entry->c.text.read = snd_info_version_read; |
983 | if (snd_info_register(entry) < 0) { | 992 | if (snd_info_register(entry) < 0) { |
984 | snd_info_free_entry(entry); | 993 | snd_info_free_entry(entry); |