Make the read/write buffer size of proc text interface variable.
Unified · Split
| @@ -27,9 +27,9 @@ · 26 unmodified lines | ||
| 27 | 27 | /* buffer for information */ |
| 28 | 28 | struct snd_info_buffer { |
| 29 | 29 | char *buffer; /* pointer to begin of buffer */ |
| 30 | − char *curr; /* current position in buffer */ | |
| 31 | − unsigned long size; /* current size */ | |
| 32 | − unsigned long len; /* total length of buffer */ | |
| 30 | + unsigned int curr; /* current position in buffer */ | |
| 31 | + unsigned int size; /* current size */ | |
| 32 | + unsigned int len; /* total length of buffer */ | |
| 33 | 33 | int stop; /* stop flag */ |
| 34 | 34 | int error; /* error code */ |
| 35 | 35 | }; |
| @@ -21,7 +21,6 @@ · 20 unmodified lines | ||
| 21 | 21 | |
| 22 | 22 | #include <sound/driver.h> |
| 23 | 23 | #include <linux/init.h> |
| 24 | −#include <linux/vmalloc.h> | |
| 25 | 24 | #include <linux/time.h> |
| 26 | 25 | #include <linux/smp_lock.h> |
| 27 | 26 | #include <linux/string.h> |
| @@ -82,6 +81,24 @@ static int snd_info_version_init(void); · 54 unmodified lines | ||
| 82 | 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 | 103 | * snd_iprintf - printf on the procfs buffer |
| 87 | 104 | * @buffer: the procfs buffer |
| @@ -95,17 +112,25 @@ int snd_iprintf(struct snd_info_buffer *buffer, char *fmt,...) · 7 unmodified lines | ||
| 95 | 112 | { |
| 96 | 113 | va_list args; |
| 97 | 114 | int len, res; |
| 115 | + int err = 0; | |
| 98 | 116 | |
| 99 | 117 | if (buffer->stop || buffer->error) |
| 100 | 118 | return 0; |
| 101 | 119 | len = buffer->len - buffer->size; |
| 102 | 120 | va_start(args, fmt); |
| 103 | − res = vsnprintf(buffer->curr, len, fmt, args); | |
| 104 | − va_end(args); | |
| 105 | − if (res >= len) { | |
| 106 | − buffer->stop = 1; | |
| 107 | − return 0; | |
| 121 | + for (;;) { | |
| 122 | + res = vsnprintf(buffer->buffer + buffer->curr, len, fmt, args); | |
| 123 | + if (res < len) | |
| 124 | + break; | |
| 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 | 134 | buffer->curr += res; |
| 110 | 135 | buffer->size += res; |
| 111 | 136 | return res; |
| @@ -225,7 +250,7 @@ static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer · 113 unmodified lines | ||
| 225 | 250 | struct snd_info_private_data *data; |
| 226 | 251 | struct snd_info_entry *entry; |
| 227 | 252 | struct snd_info_buffer *buf; |
| 228 | − size_t size = 0; | |
| 253 | + ssize_t size = 0; | |
| 229 | 254 | loff_t pos; |
| 230 | 255 | |
| 231 | 256 | data = file->private_data; |
| @@ -241,14 +266,20 @@ static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer · 9 unmodified lines | ||
| 241 | 266 | buf = data->wbuffer; |
| 242 | 267 | if (buf == NULL) |
| 243 | 268 | return -EIO; |
| 244 | − if (pos >= buf->len) | |
| 245 | − return -ENOMEM; | |
| 246 | − size = buf->len - pos; | |
| 247 | − size = min(count, size); | |
| 248 | − if (copy_from_user(buf->buffer + pos, buffer, size)) | |
| 269 | + mutex_unlock(&entry->access); | |
| 270 | + if (pos + count >= buf->len) { | |
| 271 | + if (resize_info_buffer(buf, pos + count)) { | |
| 272 | + mutex_unlock(&entry->access); | |
| 273 | + return -ENOMEM; | |
| 274 | + } | |
| 275 | + } | |
| 276 | + if (copy_from_user(buf->buffer + pos, buffer, count)) { | |
| 277 | + mutex_unlock(&entry->access); | |
| 249 | 278 | return -EFAULT; |
| 250 | − if ((long)buf->size < pos + size) | |
| 251 | − buf->size = pos + size; | |
| 279 | + } | |
| 280 | + buf->size = pos + count; | |
| 281 | + mutex_unlock(&entry->access); | |
| 282 | + size = count; | |
| 252 | 283 | break; |
| 253 | 284 | case SNDRV_INFO_CONTENT_DATA: |
| 254 | 285 | if (entry->c.ops->write) |
| @@ -283,18 +314,14 @@ static int snd_info_entry_open(struct inode *inode, struct file *file) · 28 unmodified lines | ||
| 283 | 314 | } |
| 284 | 315 | mode = file->f_flags & O_ACCMODE; |
| 285 | 316 | if (mode == O_RDONLY || mode == O_RDWR) { |
| 286 | − if ((entry->content == SNDRV_INFO_CONTENT_TEXT && | |
| 287 | − !entry->c.text.read_size) || | |
| 288 | − (entry->content == SNDRV_INFO_CONTENT_DATA && | |
| 317 | + if ((entry->content == SNDRV_INFO_CONTENT_DATA && | |
| 289 | 318 | entry->c.ops->read == NULL)) { |
| 290 | 319 | err = -ENODEV; |
| 291 | 320 | goto __error; |
| 292 | 321 | } |
| 293 | 322 | } |
| 294 | 323 | if (mode == O_WRONLY || mode == O_RDWR) { |
| 295 | − if ((entry->content == SNDRV_INFO_CONTENT_TEXT && | |
| 296 | − !entry->c.text.write_size) || | |
| 297 | − (entry->content == SNDRV_INFO_CONTENT_DATA && | |
| 324 | + if ((entry->content == SNDRV_INFO_CONTENT_DATA && | |
| 298 | 325 | entry->c.ops->write == NULL)) { |
| 299 | 326 | err = -ENODEV; |
| 300 | 327 | goto __error; |
| @@ -310,49 +337,23 @@ static int snd_info_entry_open(struct inode *inode, struct file *file) · 9 unmodified lines | ||
| 310 | 337 | case SNDRV_INFO_CONTENT_TEXT: |
| 311 | 338 | if (mode == O_RDONLY || mode == O_RDWR) { |
| 312 | 339 | buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); |
| 313 | − if (buffer == NULL) { | |
| 314 | − kfree(data); | |
| 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; | |
| 340 | + if (buffer == NULL) | |
| 341 | + goto __nomem; | |
| 328 | 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 | 348 | if (mode == O_WRONLY || mode == O_RDWR) { |
| 331 | 349 | buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); |
| 332 | − if (buffer == NULL) { | |
| 333 | − if (mode == O_RDWR) { | |
| 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; | |
| 350 | + if (buffer == NULL) | |
| 351 | + goto __nomem; | |
| 355 | 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 | 358 | break; |
| 358 | 359 | case SNDRV_INFO_CONTENT_DATA: /* data */ |
| @@ -377,6 +378,17 @@ static int snd_info_entry_open(struct inode *inode, struct file *file) · 18 unmodified lines | ||
| 377 | 378 | } |
| 378 | 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 | 392 | __error: |
| 381 | 393 | module_put(entry->module); |
| 382 | 394 | __error1: |
| @@ -395,11 +407,11 @@ static int snd_info_entry_release(struct inode *inode, struct file *file) · 12 unmodified lines | ||
| 395 | 407 | entry = data->entry; |
| 396 | 408 | switch (entry->content) { |
| 397 | 409 | case SNDRV_INFO_CONTENT_TEXT: |
| 398 | − if (mode == O_RDONLY || mode == O_RDWR) { | |
| 399 | − vfree(data->rbuffer->buffer); | |
| 410 | + if (data->rbuffer) { | |
| 411 | + kfree(data->rbuffer->buffer); | |
| 400 | 412 | kfree(data->rbuffer); |
| 401 | 413 | } |
| 402 | − if (mode == O_WRONLY || mode == O_RDWR) { | |
| 414 | + if (data->wbuffer) { | |
| 403 | 415 | if (entry->c.text.write) { |
| 404 | 416 | entry->c.text.write(entry, data->wbuffer); |
| 405 | 417 | if (data->wbuffer->error) { |
| @@ -408,7 +420,7 @@ static int snd_info_entry_release(struct inode *inode, struct file *file) · 2 unmodified lines | ||
| 408 | 420 | data->wbuffer->error); |
| 409 | 421 | } |
| 410 | 422 | } |
| 411 | − vfree(data->wbuffer->buffer); | |
| 423 | + kfree(data->wbuffer->buffer); | |
| 412 | 424 | kfree(data->wbuffer); |
| 413 | 425 | } |
| 414 | 426 | break; |
| @@ -668,24 +680,22 @@ int snd_info_get_line(struct snd_info_buffer *buffer, char *line, int len) · 253 unmodified lines | ||
| 668 | 680 | if (len <= 0 || buffer->stop || buffer->error) |
| 669 | 681 | return 1; |
| 670 | 682 | while (--len > 0) { |
| 671 | − c = *buffer->curr++; | |
| 683 | + c = buffer->buffer[buffer->curr++]; | |
| 672 | 684 | if (c == '\n') { |
| 673 | − if ((buffer->curr - buffer->buffer) >= (long)buffer->size) { | |
| 685 | + if (buffer->curr >= buffer->size) | |
| 674 | 686 | buffer->stop = 1; |
| 675 | − } | |
| 676 | 687 | break; |
| 677 | 688 | } |
| 678 | 689 | *line++ = c; |
| 679 | − if ((buffer->curr - buffer->buffer) >= (long)buffer->size) { | |
| 690 | + if (buffer->curr >= buffer->size) { | |
| 680 | 691 | buffer->stop = 1; |
| 681 | 692 | break; |
| 682 | 693 | } |
| 683 | 694 | } |
| 684 | 695 | while (c != '\n' && !buffer->stop) { |
| 685 | − c = *buffer->curr++; | |
| 686 | − if ((buffer->curr - buffer->buffer) >= (long)buffer->size) { | |
| 696 | + c = buffer->buffer[buffer->curr++]; | |
| 697 | + if (buffer->curr >= buffer->size) | |
| 687 | 698 | buffer->stop = 1; |
| 688 | − } | |
| 689 | 699 | } |
| 690 | 700 | *line = '\0'; |
| 691 | 701 | return 0; |
| @@ -978,7 +988,6 @@ static int __init snd_info_version_init(void) · 286 unmodified lines | ||
| 978 | 988 | entry = snd_info_create_module_entry(THIS_MODULE, "version", NULL); |
| 979 | 989 | if (entry == NULL) |
| 980 | 990 | return -ENOMEM; |
| 981 | − entry->c.text.read_size = 256; | |
| 982 | 991 | entry->c.text.read = snd_info_version_read; |
| 983 | 992 | if (snd_info_register(entry) < 0) { |
| 984 | 993 | snd_info_free_entry(entry); |