diff options
| author | Stefani Seibold <stefani@seibold.net> | 2009-12-21 17:37:32 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-22 17:17:56 -0500 |
| commit | 86d4880313603810901f639ccb5c88ff13d4ad3c (patch) | |
| tree | c182d890b5c96a1143b70b00b93e3fc4a9263555 | |
| parent | a121f24accac1600bf5b6fb1e12eeabdfed7cb1a (diff) | |
kfifo: add record handling functions
Add kfifo_in_rec() - puts some record data into the FIFO
Add kfifo_out_rec() - gets some record data from the FIFO
Add kfifo_from_user_rec() - puts some data from user space into the FIFO
Add kfifo_to_user_rec() - gets data from the FIFO and write it to user space
Add kfifo_peek_rec() - gets the size of the next FIFO record field
Add kfifo_skip_rec() - skip the next fifo out record
Add kfifo_avail_rec() - determinate the number of bytes available in a record FIFO
Signed-off-by: Stefani Seibold <stefani@seibold.net>
Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
Acked-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Acked-by: Andi Kleen <ak@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
| -rw-r--r-- | include/linux/kfifo.h | 330 | ||||
| -rw-r--r-- | kernel/kfifo.c | 286 |
2 files changed, 523 insertions, 93 deletions
diff --git a/include/linux/kfifo.h b/include/linux/kfifo.h index d3230fb08bc7..486e8ad3bb50 100644 --- a/include/linux/kfifo.h +++ b/include/linux/kfifo.h | |||
| @@ -278,4 +278,334 @@ static inline unsigned int __kfifo_off(struct kfifo *fifo, unsigned int off) | |||
| 278 | return off & (fifo->size - 1); | 278 | return off & (fifo->size - 1); |
| 279 | } | 279 | } |
| 280 | 280 | ||
| 281 | /** | ||
| 282 | * __kfifo_peek_n internal helper function for determinate the length of | ||
| 283 | * the next record in the fifo | ||
| 284 | */ | ||
| 285 | static inline unsigned int __kfifo_peek_n(struct kfifo *fifo, | ||
| 286 | unsigned int recsize) | ||
| 287 | { | ||
| 288 | #define __KFIFO_GET(fifo, off, shift) \ | ||
| 289 | ((fifo)->buffer[__kfifo_off((fifo), (fifo)->out+(off))] << (shift)) | ||
| 290 | |||
| 291 | unsigned int l; | ||
| 292 | |||
| 293 | l = __KFIFO_GET(fifo, 0, 0); | ||
| 294 | |||
| 295 | if (--recsize) | ||
| 296 | l |= __KFIFO_GET(fifo, 1, 8); | ||
| 297 | |||
| 298 | return l; | ||
| 299 | #undef __KFIFO_GET | ||
| 300 | } | ||
| 301 | |||
| 302 | /** | ||
| 303 | * __kfifo_poke_n internal helper function for storing the length of | ||
| 304 | * the next record into the fifo | ||
| 305 | */ | ||
| 306 | static inline void __kfifo_poke_n(struct kfifo *fifo, | ||
| 307 | unsigned int recsize, unsigned int n) | ||
| 308 | { | ||
| 309 | #define __KFIFO_PUT(fifo, off, val, shift) \ | ||
| 310 | ( \ | ||
| 311 | (fifo)->buffer[__kfifo_off((fifo), (fifo)->in+(off))] = \ | ||
| 312 | (unsigned char)((val) >> (shift)) \ | ||
| 313 | ) | ||
| 314 | |||
| 315 | __KFIFO_PUT(fifo, 0, n, 0); | ||
| 316 | |||
| 317 | if (--recsize) | ||
| 318 | __KFIFO_PUT(fifo, 1, n, 8); | ||
| 319 | #undef __KFIFO_PUT | ||
| 320 | } | ||
| 321 | |||
| 322 | /** | ||
| 323 | * __kfifo_in_... internal functions for put date into the fifo | ||
| 324 | * do not call it directly, use kfifo_in_rec() instead | ||
| 325 | */ | ||
| 326 | extern unsigned int __kfifo_in_n(struct kfifo *fifo, | ||
| 327 | const void *from, unsigned int n, unsigned int recsize); | ||
| 328 | |||
| 329 | extern unsigned int __kfifo_in_generic(struct kfifo *fifo, | ||
| 330 | const void *from, unsigned int n, unsigned int recsize); | ||
| 331 | |||
| 332 | static inline unsigned int __kfifo_in_rec(struct kfifo *fifo, | ||
| 333 | const void *from, unsigned int n, unsigned int recsize) | ||
| 334 | { | ||
| 335 | unsigned int ret; | ||
| 336 | |||
| 337 | ret = __kfifo_in_n(fifo, from, n, recsize); | ||
| 338 | |||
| 339 | if (likely(ret == 0)) { | ||
| 340 | if (recsize) | ||
| 341 | __kfifo_poke_n(fifo, recsize, n); | ||
| 342 | __kfifo_add_in(fifo, n + recsize); | ||
| 343 | } | ||
| 344 | return ret; | ||
| 345 | } | ||
| 346 | |||
| 347 | /** | ||
| 348 | * kfifo_in_rec - puts some record data into the FIFO | ||
| 349 | * @fifo: the fifo to be used. | ||
| 350 | * @from: the data to be added. | ||
| 351 | * @n: the length of the data to be added. | ||
| 352 | * @recsize: size of record field | ||
| 353 | * | ||
| 354 | * This function copies @n bytes from the @from into the FIFO and returns | ||
| 355 | * the number of bytes which cannot be copied. | ||
| 356 | * A returned value greater than the @n value means that the record doesn't | ||
| 357 | * fit into the buffer. | ||
| 358 | * | ||
| 359 | * Note that with only one concurrent reader and one concurrent | ||
| 360 | * writer, you don't need extra locking to use these functions. | ||
| 361 | */ | ||
| 362 | static inline __must_check unsigned int kfifo_in_rec(struct kfifo *fifo, | ||
| 363 | void *from, unsigned int n, unsigned int recsize) | ||
| 364 | { | ||
| 365 | if (!__builtin_constant_p(recsize)) | ||
| 366 | return __kfifo_in_generic(fifo, from, n, recsize); | ||
| 367 | return __kfifo_in_rec(fifo, from, n, recsize); | ||
| 368 | } | ||
| 369 | |||
| 370 | /** | ||
| 371 | * __kfifo_out_... internal functions for get date from the fifo | ||
| 372 | * do not call it directly, use kfifo_out_rec() instead | ||
| 373 | */ | ||
| 374 | extern unsigned int __kfifo_out_n(struct kfifo *fifo, | ||
| 375 | void *to, unsigned int reclen, unsigned int recsize); | ||
| 376 | |||
| 377 | extern unsigned int __kfifo_out_generic(struct kfifo *fifo, | ||
| 378 | void *to, unsigned int n, | ||
| 379 | unsigned int recsize, unsigned int *total); | ||
| 380 | |||
| 381 | static inline unsigned int __kfifo_out_rec(struct kfifo *fifo, | ||
| 382 | void *to, unsigned int n, unsigned int recsize, | ||
| 383 | unsigned int *total) | ||
| 384 | { | ||
| 385 | unsigned int l; | ||
| 386 | |||
| 387 | if (!recsize) { | ||
| 388 | l = n; | ||
| 389 | if (total) | ||
| 390 | *total = l; | ||
| 391 | } else { | ||
| 392 | l = __kfifo_peek_n(fifo, recsize); | ||
| 393 | if (total) | ||
| 394 | *total = l; | ||
| 395 | if (n < l) | ||
| 396 | return l; | ||
| 397 | } | ||
| 398 | |||
| 399 | return __kfifo_out_n(fifo, to, l, recsize); | ||
| 400 | } | ||
| 401 | |||
| 402 | /** | ||
| 403 | * kfifo_out_rec - gets some record data from the FIFO | ||
| 404 | * @fifo: the fifo to be used. | ||
| 405 | * @to: where the data must be copied. | ||
| 406 | * @n: the size of the destination buffer. | ||
| 407 | * @recsize: size of record field | ||
| 408 | * @total: pointer where the total number of to copied bytes should stored | ||
| 409 | * | ||
| 410 | * This function copies at most @n bytes from the FIFO to @to and returns the | ||
| 411 | * number of bytes which cannot be copied. | ||
| 412 | * A returned value greater than the @n value means that the record doesn't | ||
| 413 | * fit into the @to buffer. | ||
| 414 | * | ||
| 415 | * Note that with only one concurrent reader and one concurrent | ||
| 416 | * writer, you don't need extra locking to use these functions. | ||
| 417 | */ | ||
| 418 | static inline __must_check unsigned int kfifo_out_rec(struct kfifo *fifo, | ||
| 419 | void *to, unsigned int n, unsigned int recsize, | ||
| 420 | unsigned int *total) | ||
| 421 | |||
| 422 | { | ||
| 423 | if (!__builtin_constant_p(recsize)) | ||
| 424 | return __kfifo_out_generic(fifo, to, n, recsize, total); | ||
| 425 | return __kfifo_out_rec(fifo, to, n, recsize, total); | ||
| 426 | } | ||
| 427 | |||
| 428 | /** | ||
| 429 | * __kfifo_from_user_... internal functions for transfer from user space into | ||
| 430 | * the fifo. do not call it directly, use kfifo_from_user_rec() instead | ||
| 431 | */ | ||
| 432 | extern unsigned int __kfifo_from_user_n(struct kfifo *fifo, | ||
| 433 | const void __user *from, unsigned int n, unsigned int recsize); | ||
| 434 | |||
| 435 | extern unsigned int __kfifo_from_user_generic(struct kfifo *fifo, | ||
| 436 | const void __user *from, unsigned int n, unsigned int recsize); | ||
| 437 | |||
| 438 | static inline unsigned int __kfifo_from_user_rec(struct kfifo *fifo, | ||
| 439 | const void __user *from, unsigned int n, unsigned int recsize) | ||
| 440 | { | ||
| 441 | unsigned int ret; | ||
| 442 | |||
| 443 | ret = __kfifo_from_user_n(fifo, from, n, recsize); | ||
| 444 | |||
| 445 | if (likely(ret == 0)) { | ||
| 446 | if (recsize) | ||
| 447 | __kfifo_poke_n(fifo, recsize, n); | ||
| 448 | __kfifo_add_in(fifo, n + recsize); | ||
| 449 | } | ||
| 450 | return ret; | ||
| 451 | } | ||
| 452 | |||
| 453 | /** | ||
| 454 | * kfifo_from_user_rec - puts some data from user space into the FIFO | ||
| 455 | * @fifo: the fifo to be used. | ||
| 456 | * @from: pointer to the data to be added. | ||
| 457 | * @n: the length of the data to be added. | ||
| 458 | * @recsize: size of record field | ||
| 459 | * | ||
| 460 | * This function copies @n bytes from the @from into the | ||
| 461 | * FIFO and returns the number of bytes which cannot be copied. | ||
| 462 | * | ||
| 463 | * If the returned value is equal or less the @n value, the copy_from_user() | ||
| 464 | * functions has failed. Otherwise the record doesn't fit into the buffer. | ||
| 465 | * | ||
| 466 | * Note that with only one concurrent reader and one concurrent | ||
| 467 | * writer, you don't need extra locking to use these functions. | ||
| 468 | */ | ||
| 469 | static inline __must_check unsigned int kfifo_from_user_rec(struct kfifo *fifo, | ||
| 470 | const void __user *from, unsigned int n, unsigned int recsize) | ||
| 471 | { | ||
| 472 | if (!__builtin_constant_p(recsize)) | ||
| 473 | return __kfifo_from_user_generic(fifo, from, n, recsize); | ||
| 474 | return __kfifo_from_user_rec(fifo, from, n, recsize); | ||
| 475 | } | ||
| 476 | |||
| 477 | /** | ||
| 478 | * __kfifo_to_user_... internal functions for transfer fifo data into user space | ||
| 479 | * do not call it directly, use kfifo_to_user_rec() instead | ||
| 480 | */ | ||
| 481 | extern unsigned int __kfifo_to_user_n(struct kfifo *fifo, | ||
| 482 | void __user *to, unsigned int n, unsigned int reclen, | ||
| 483 | unsigned int recsize); | ||
| 484 | |||
| 485 | extern unsigned int __kfifo_to_user_generic(struct kfifo *fifo, | ||
| 486 | void __user *to, unsigned int n, unsigned int recsize, | ||
| 487 | unsigned int *total); | ||
| 488 | |||
| 489 | static inline unsigned int __kfifo_to_user_rec(struct kfifo *fifo, | ||
| 490 | void __user *to, unsigned int n, | ||
| 491 | unsigned int recsize, unsigned int *total) | ||
| 492 | { | ||
| 493 | unsigned int l; | ||
| 494 | |||
| 495 | if (!recsize) { | ||
| 496 | l = n; | ||
| 497 | if (total) | ||
| 498 | *total = l; | ||
| 499 | } else { | ||
| 500 | l = __kfifo_peek_n(fifo, recsize); | ||
| 501 | if (total) | ||
| 502 | *total = l; | ||
| 503 | if (n < l) | ||
| 504 | return l; | ||
| 505 | } | ||
| 506 | |||
| 507 | return __kfifo_to_user_n(fifo, to, n, l, recsize); | ||
| 508 | } | ||
| 509 | |||
| 510 | /** | ||
| 511 | * kfifo_to_user_rec - gets data from the FIFO and write it to user space | ||
| 512 | * @fifo: the fifo to be used. | ||
| 513 | * @to: where the data must be copied. | ||
| 514 | * @n: the size of the destination buffer. | ||
| 515 | * @recsize: size of record field | ||
| 516 | * @total: pointer where the total number of to copied bytes should stored | ||
| 517 | * | ||
| 518 | * This function copies at most @n bytes from the FIFO to the @to. | ||
| 519 | * In case of an error, the function returns the number of bytes which cannot | ||
| 520 | * be copied. | ||
| 521 | * If the returned value is equal or less the @n value, the copy_to_user() | ||
| 522 | * functions has failed. Otherwise the record doesn't fit into the @to buffer. | ||
| 523 | * | ||
| 524 | * Note that with only one concurrent reader and one concurrent | ||
| 525 | * writer, you don't need extra locking to use these functions. | ||
| 526 | */ | ||
| 527 | static inline __must_check unsigned int kfifo_to_user_rec(struct kfifo *fifo, | ||
| 528 | void __user *to, unsigned int n, unsigned int recsize, | ||
| 529 | unsigned int *total) | ||
| 530 | { | ||
| 531 | if (!__builtin_constant_p(recsize)) | ||
| 532 | return __kfifo_to_user_generic(fifo, to, n, recsize, total); | ||
| 533 | return __kfifo_to_user_rec(fifo, to, n, recsize, total); | ||
| 534 | } | ||
| 535 | |||
| 536 | /** | ||
| 537 | * __kfifo_peek_... internal functions for peek into the next fifo record | ||
| 538 | * do not call it directly, use kfifo_peek_rec() instead | ||
| 539 | */ | ||
| 540 | extern unsigned int __kfifo_peek_generic(struct kfifo *fifo, | ||
| 541 | unsigned int recsize); | ||
| 542 | |||
| 543 | /** | ||
| 544 | * kfifo_peek_rec - gets the size of the next FIFO record data | ||
| 545 | * @fifo: the fifo to be used. | ||
| 546 | * @recsize: size of record field | ||
| 547 | * | ||
| 548 | * This function returns the size of the next FIFO record in number of bytes | ||
| 549 | */ | ||
| 550 | static inline __must_check unsigned int kfifo_peek_rec(struct kfifo *fifo, | ||
| 551 | unsigned int recsize) | ||
| 552 | { | ||
| 553 | if (!__builtin_constant_p(recsize)) | ||
| 554 | return __kfifo_peek_generic(fifo, recsize); | ||
| 555 | if (!recsize) | ||
| 556 | return kfifo_len(fifo); | ||
| 557 | return __kfifo_peek_n(fifo, recsize); | ||
| 558 | } | ||
| 559 | |||
| 560 | /** | ||
| 561 | * __kfifo_skip_... internal functions for skip the next fifo record | ||
| 562 | * do not call it directly, use kfifo_skip_rec() instead | ||
| 563 | */ | ||
| 564 | extern void __kfifo_skip_generic(struct kfifo *fifo, unsigned int recsize); | ||
| 565 | |||
| 566 | static inline void __kfifo_skip_rec(struct kfifo *fifo, | ||
| 567 | unsigned int recsize) | ||
| 568 | { | ||
| 569 | unsigned int l; | ||
| 570 | |||
| 571 | if (recsize) { | ||
| 572 | l = __kfifo_peek_n(fifo, recsize); | ||
| 573 | |||
| 574 | if (l + recsize <= kfifo_len(fifo)) { | ||
| 575 | __kfifo_add_out(fifo, l + recsize); | ||
| 576 | return; | ||
| 577 | } | ||
| 578 | } | ||
| 579 | kfifo_reset_out(fifo); | ||
| 580 | } | ||
| 581 | |||
| 582 | /** | ||
| 583 | * kfifo_skip_rec - skip the next fifo out record | ||
| 584 | * @fifo: the fifo to be used. | ||
| 585 | * @recsize: size of record field | ||
| 586 | * | ||
| 587 | * This function skips the next FIFO record | ||
| 588 | */ | ||
| 589 | static inline void kfifo_skip_rec(struct kfifo *fifo, | ||
| 590 | unsigned int recsize) | ||
| 591 | { | ||
| 592 | if (!__builtin_constant_p(recsize)) | ||
| 593 | __kfifo_skip_generic(fifo, recsize); | ||
| 594 | else | ||
| 595 | __kfifo_skip_rec(fifo, recsize); | ||
| 596 | } | ||
| 597 | |||
| 598 | /** | ||
| 599 | * kfifo_avail_rec - returns the number of bytes available in a record FIFO | ||
| 600 | * @fifo: the fifo to be used. | ||
| 601 | * @recsize: size of record field | ||
| 602 | */ | ||
| 603 | static inline __must_check unsigned int kfifo_avail_rec(struct kfifo *fifo, | ||
| 604 | unsigned int recsize) | ||
| 605 | { | ||
| 606 | unsigned int l = kfifo_size(fifo) - kfifo_len(fifo); | ||
| 607 | |||
| 608 | return (l > recsize) ? l - recsize : 0; | ||
| 609 | } | ||
| 610 | |||
| 281 | #endif | 611 | #endif |
diff --git a/kernel/kfifo.c b/kernel/kfifo.c index 2a78425ef67f..e92d519f93b1 100644 --- a/kernel/kfifo.c +++ b/kernel/kfifo.c | |||
| @@ -115,27 +115,11 @@ void kfifo_skip(struct kfifo *fifo, unsigned int len) | |||
| 115 | } | 115 | } |
| 116 | EXPORT_SYMBOL(kfifo_skip); | 116 | EXPORT_SYMBOL(kfifo_skip); |
| 117 | 117 | ||
| 118 | /** | 118 | static inline void __kfifo_in_data(struct kfifo *fifo, |
| 119 | * kfifo_in - puts some data into the FIFO | 119 | const void *from, unsigned int len, unsigned int off) |
| 120 | * @fifo: the fifo to be used. | ||
| 121 | * @from: the data to be added. | ||
| 122 | * @len: the length of the data to be added. | ||
| 123 | * | ||
| 124 | * This function copies at most @len bytes from the @from buffer into | ||
| 125 | * the FIFO depending on the free space, and returns the number of | ||
| 126 | * bytes copied. | ||
| 127 | * | ||
| 128 | * Note that with only one concurrent reader and one concurrent | ||
| 129 | * writer, you don't need extra locking to use these functions. | ||
| 130 | */ | ||
| 131 | unsigned int kfifo_in(struct kfifo *fifo, | ||
| 132 | const unsigned char *from, unsigned int len) | ||
| 133 | { | 120 | { |
| 134 | unsigned int off; | ||
| 135 | unsigned int l; | 121 | unsigned int l; |
| 136 | 122 | ||
| 137 | len = min(len, fifo->size - fifo->in + fifo->out); | ||
| 138 | |||
| 139 | /* | 123 | /* |
| 140 | * Ensure that we sample the fifo->out index -before- we | 124 | * Ensure that we sample the fifo->out index -before- we |
| 141 | * start putting bytes into the kfifo. | 125 | * start putting bytes into the kfifo. |
| @@ -143,7 +127,7 @@ unsigned int kfifo_in(struct kfifo *fifo, | |||
| 143 | 127 | ||
| 144 | smp_mb(); | 128 | smp_mb(); |
| 145 | 129 | ||
| 146 | off = __kfifo_off(fifo, fifo->in); | 130 | off = __kfifo_off(fifo, fifo->in + off); |
| 147 | 131 | ||
| 148 | /* first put the data starting from fifo->in to buffer end */ | 132 | /* first put the data starting from fifo->in to buffer end */ |
| 149 | l = min(len, fifo->size - off); | 133 | l = min(len, fifo->size - off); |
| @@ -151,33 +135,13 @@ unsigned int kfifo_in(struct kfifo *fifo, | |||
| 151 | 135 | ||
| 152 | /* then put the rest (if any) at the beginning of the buffer */ | 136 | /* then put the rest (if any) at the beginning of the buffer */ |
| 153 | memcpy(fifo->buffer, from + l, len - l); | 137 | memcpy(fifo->buffer, from + l, len - l); |
| 154 | |||
| 155 | __kfifo_add_in(fifo, len); | ||
| 156 | |||
| 157 | return len; | ||
| 158 | } | 138 | } |
| 159 | EXPORT_SYMBOL(kfifo_in); | ||
| 160 | 139 | ||
| 161 | /** | 140 | static inline void __kfifo_out_data(struct kfifo *fifo, |
| 162 | * kfifo_out - gets some data from the FIFO | 141 | void *to, unsigned int len, unsigned int off) |
| 163 | * @fifo: the fifo to be used. | ||
| 164 | * @to: where the data must be copied. | ||
| 165 | * @len: the size of the destination buffer. | ||
| 166 | * | ||
| 167 | * This function copies at most @len bytes from the FIFO into the | ||
| 168 | * @to buffer and returns the number of copied bytes. | ||
| 169 | * | ||
| 170 | * Note that with only one concurrent reader and one concurrent | ||
| 171 | * writer, you don't need extra locking to use these functions. | ||
| 172 | */ | ||
| 173 | unsigned int kfifo_out(struct kfifo *fifo, | ||
| 174 | unsigned char *to, unsigned int len) | ||
| 175 | { | 142 | { |
| 176 | unsigned int off; | ||
| 177 | unsigned int l; | 143 | unsigned int l; |
| 178 | 144 | ||
| 179 | len = min(len, fifo->in - fifo->out); | ||
| 180 | |||
| 181 | /* | 145 | /* |
| 182 | * Ensure that we sample the fifo->in index -before- we | 146 | * Ensure that we sample the fifo->in index -before- we |
| 183 | * start removing bytes from the kfifo. | 147 | * start removing bytes from the kfifo. |
| @@ -185,7 +149,7 @@ unsigned int kfifo_out(struct kfifo *fifo, | |||
| 185 | 149 | ||
| 186 | smp_rmb(); | 150 | smp_rmb(); |
| 187 | 151 | ||
| 188 | off = __kfifo_off(fifo, fifo->out); | 152 | off = __kfifo_off(fifo, fifo->out + off); |
| 189 | 153 | ||
| 190 | /* first get the data from fifo->out until the end of the buffer */ | 154 | /* first get the data from fifo->out until the end of the buffer */ |
| 191 | l = min(len, fifo->size - off); | 155 | l = min(len, fifo->size - off); |
| @@ -193,34 +157,14 @@ unsigned int kfifo_out(struct kfifo *fifo, | |||
| 193 | 157 | ||
| 194 | /* then get the rest (if any) from the beginning of the buffer */ | 158 | /* then get the rest (if any) from the beginning of the buffer */ |
| 195 | memcpy(to + l, fifo->buffer, len - l); | 159 | memcpy(to + l, fifo->buffer, len - l); |
| 196 | |||
| 197 | __kfifo_add_out(fifo, len); | ||
| 198 | |||
| 199 | return len; | ||
| 200 | } | 160 | } |
| 201 | EXPORT_SYMBOL(kfifo_out); | ||
| 202 | 161 | ||
| 203 | /** | 162 | static inline unsigned int __kfifo_from_user_data(struct kfifo *fifo, |
| 204 | * kfifo_from_user - puts some data from user space into the FIFO | 163 | const void __user *from, unsigned int len, unsigned int off) |
| 205 | * @fifo: the fifo to be used. | ||
| 206 | * @from: pointer to the data to be added. | ||
| 207 | * @len: the length of the data to be added. | ||
| 208 | * | ||
| 209 | * This function copies at most @len bytes from the @from into the | ||
| 210 | * FIFO depending and returns the number of copied bytes. | ||
| 211 | * | ||
| 212 | * Note that with only one concurrent reader and one concurrent | ||
| 213 | * writer, you don't need extra locking to use these functions. | ||
| 214 | */ | ||
| 215 | unsigned int kfifo_from_user(struct kfifo *fifo, | ||
| 216 | const void __user *from, unsigned int len) | ||
| 217 | { | 164 | { |
| 218 | unsigned int off; | ||
| 219 | unsigned int l; | 165 | unsigned int l; |
| 220 | int ret; | 166 | int ret; |
| 221 | 167 | ||
| 222 | len = min(len, fifo->size - fifo->in + fifo->out); | ||
| 223 | |||
| 224 | /* | 168 | /* |
| 225 | * Ensure that we sample the fifo->out index -before- we | 169 | * Ensure that we sample the fifo->out index -before- we |
| 226 | * start putting bytes into the kfifo. | 170 | * start putting bytes into the kfifo. |
| @@ -228,29 +172,101 @@ unsigned int kfifo_from_user(struct kfifo *fifo, | |||
| 228 | 172 | ||
| 229 | smp_mb(); | 173 | smp_mb(); |
| 230 | 174 | ||
| 231 | off = __kfifo_off(fifo, fifo->in); | 175 | off = __kfifo_off(fifo, fifo->in + off); |
| 232 | 176 | ||
| 233 | /* first put the data starting from fifo->in to buffer end */ | 177 | /* first put the data starting from fifo->in to buffer end */ |
| 234 | l = min(len, fifo->size - off); | 178 | l = min(len, fifo->size - off); |
| 235 | ret = copy_from_user(fifo->buffer + off, from, l); | 179 | ret = copy_from_user(fifo->buffer + off, from, l); |
| 236 | 180 | ||
| 237 | if (unlikely(ret)) | 181 | if (unlikely(ret)) |
| 238 | return l - ret; | 182 | return ret + len - l; |
| 239 | 183 | ||
| 240 | /* then put the rest (if any) at the beginning of the buffer */ | 184 | /* then put the rest (if any) at the beginning of the buffer */ |
| 241 | ret = copy_from_user(fifo->buffer, from + l, len - l); | 185 | return copy_from_user(fifo->buffer, from + l, len - l); |
| 186 | } | ||
| 187 | |||
| 188 | static inline unsigned int __kfifo_to_user_data(struct kfifo *fifo, | ||
| 189 | void __user *to, unsigned int len, unsigned int off) | ||
| 190 | { | ||
| 191 | unsigned int l; | ||
| 192 | int ret; | ||
| 193 | |||
| 194 | /* | ||
| 195 | * Ensure that we sample the fifo->in index -before- we | ||
| 196 | * start removing bytes from the kfifo. | ||
| 197 | */ | ||
| 198 | |||
| 199 | smp_rmb(); | ||
| 200 | |||
| 201 | off = __kfifo_off(fifo, fifo->out + off); | ||
| 202 | |||
| 203 | /* first get the data from fifo->out until the end of the buffer */ | ||
| 204 | l = min(len, fifo->size - off); | ||
| 205 | ret = copy_to_user(to, fifo->buffer + off, l); | ||
| 242 | 206 | ||
| 243 | if (unlikely(ret)) | 207 | if (unlikely(ret)) |
| 244 | return len - ret; | 208 | return ret + len - l; |
| 245 | 209 | ||
| 246 | __kfifo_add_in(fifo, len); | 210 | /* then get the rest (if any) from the beginning of the buffer */ |
| 211 | return copy_to_user(to + l, fifo->buffer, len - l); | ||
| 212 | } | ||
| 247 | 213 | ||
| 214 | unsigned int __kfifo_in_n(struct kfifo *fifo, | ||
| 215 | const void *from, unsigned int len, unsigned int recsize) | ||
| 216 | { | ||
| 217 | if (kfifo_avail(fifo) < len + recsize) | ||
| 218 | return len + 1; | ||
| 219 | |||
| 220 | __kfifo_in_data(fifo, from, len, recsize); | ||
| 221 | return 0; | ||
| 222 | } | ||
| 223 | EXPORT_SYMBOL(__kfifo_in_n); | ||
| 224 | |||
| 225 | /** | ||
| 226 | * kfifo_in - puts some data into the FIFO | ||
| 227 | * @fifo: the fifo to be used. | ||
| 228 | * @from: the data to be added. | ||
| 229 | * @len: the length of the data to be added. | ||
| 230 | * | ||
| 231 | * This function copies at most @len bytes from the @from buffer into | ||
| 232 | * the FIFO depending on the free space, and returns the number of | ||
| 233 | * bytes copied. | ||
| 234 | * | ||
| 235 | * Note that with only one concurrent reader and one concurrent | ||
| 236 | * writer, you don't need extra locking to use these functions. | ||
| 237 | */ | ||
| 238 | unsigned int kfifo_in(struct kfifo *fifo, const unsigned char *from, | ||
| 239 | unsigned int len) | ||
| 240 | { | ||
| 241 | len = min(kfifo_avail(fifo), len); | ||
| 242 | |||
| 243 | __kfifo_in_data(fifo, from, len, 0); | ||
| 244 | __kfifo_add_in(fifo, len); | ||
| 248 | return len; | 245 | return len; |
| 249 | } | 246 | } |
| 250 | EXPORT_SYMBOL(kfifo_from_user); | 247 | EXPORT_SYMBOL(kfifo_in); |
| 248 | |||
| 249 | unsigned int __kfifo_in_generic(struct kfifo *fifo, | ||
| 250 | const void *from, unsigned int len, unsigned int recsize) | ||
| 251 | { | ||
| 252 | return __kfifo_in_rec(fifo, from, len, recsize); | ||
| 253 | } | ||
| 254 | EXPORT_SYMBOL(__kfifo_in_generic); | ||
| 255 | |||
| 256 | unsigned int __kfifo_out_n(struct kfifo *fifo, | ||
| 257 | void *to, unsigned int len, unsigned int recsize) | ||
| 258 | { | ||
| 259 | if (kfifo_len(fifo) < len + recsize) | ||
| 260 | return len; | ||
| 261 | |||
| 262 | __kfifo_out_data(fifo, to, len, recsize); | ||
| 263 | __kfifo_add_out(fifo, len + recsize); | ||
| 264 | return 0; | ||
| 265 | } | ||
| 266 | EXPORT_SYMBOL(__kfifo_out_n); | ||
| 251 | 267 | ||
| 252 | /** | 268 | /** |
| 253 | * kfifo_to_user - gets data from the FIFO and write it to user space | 269 | * kfifo_out - gets some data from the FIFO |
| 254 | * @fifo: the fifo to be used. | 270 | * @fifo: the fifo to be used. |
| 255 | * @to: where the data must be copied. | 271 | * @to: where the data must be copied. |
| 256 | * @len: the size of the destination buffer. | 272 | * @len: the size of the destination buffer. |
| @@ -261,40 +277,124 @@ EXPORT_SYMBOL(kfifo_from_user); | |||
| 261 | * Note that with only one concurrent reader and one concurrent | 277 | * Note that with only one concurrent reader and one concurrent |
| 262 | * writer, you don't need extra locking to use these functions. | 278 | * writer, you don't need extra locking to use these functions. |
| 263 | */ | 279 | */ |
| 264 | unsigned int kfifo_to_user(struct kfifo *fifo, | 280 | unsigned int kfifo_out(struct kfifo *fifo, unsigned char *to, unsigned int len) |
| 265 | void __user *to, unsigned int len) | ||
| 266 | { | 281 | { |
| 267 | unsigned int off; | 282 | len = min(kfifo_len(fifo), len); |
| 268 | unsigned int l; | ||
| 269 | int ret; | ||
| 270 | 283 | ||
| 271 | len = min(len, fifo->in - fifo->out); | 284 | __kfifo_out_data(fifo, to, len, 0); |
| 285 | __kfifo_add_out(fifo, len); | ||
| 272 | 286 | ||
| 273 | /* | 287 | return len; |
| 274 | * Ensure that we sample the fifo->in index -before- we | 288 | } |
| 275 | * start removing bytes from the kfifo. | 289 | EXPORT_SYMBOL(kfifo_out); |
| 276 | */ | ||
| 277 | 290 | ||
| 278 | smp_rmb(); | 291 | unsigned int __kfifo_out_generic(struct kfifo *fifo, |
| 292 | void *to, unsigned int len, unsigned int recsize, | ||
| 293 | unsigned int *total) | ||
| 294 | { | ||
| 295 | return __kfifo_out_rec(fifo, to, len, recsize, total); | ||
| 296 | } | ||
| 297 | EXPORT_SYMBOL(__kfifo_out_generic); | ||
| 279 | 298 | ||
| 280 | off = __kfifo_off(fifo, fifo->out); | 299 | unsigned int __kfifo_from_user_n(struct kfifo *fifo, |
| 300 | const void __user *from, unsigned int len, unsigned int recsize) | ||
| 301 | { | ||
| 302 | if (kfifo_avail(fifo) < len + recsize) | ||
| 303 | return len + 1; | ||
| 281 | 304 | ||
| 282 | /* first get the data from fifo->out until the end of the buffer */ | 305 | return __kfifo_from_user_data(fifo, from, len, recsize); |
| 283 | l = min(len, fifo->size - off); | 306 | } |
| 284 | ret = copy_to_user(to, fifo->buffer + off, l); | 307 | EXPORT_SYMBOL(__kfifo_from_user_n); |
| 285 | 308 | ||
| 286 | if (unlikely(ret)) | 309 | /** |
| 287 | return l - ret; | 310 | * kfifo_from_user - puts some data from user space into the FIFO |
| 311 | * @fifo: the fifo to be used. | ||
| 312 | * @from: pointer to the data to be added. | ||
| 313 | * @len: the length of the data to be added. | ||
| 314 | * | ||
| 315 | * This function copies at most @len bytes from the @from into the | ||
| 316 | * FIFO depending and returns the number of copied bytes. | ||
| 317 | * | ||
| 318 | * Note that with only one concurrent reader and one concurrent | ||
| 319 | * writer, you don't need extra locking to use these functions. | ||
| 320 | */ | ||
| 321 | unsigned int kfifo_from_user(struct kfifo *fifo, | ||
| 322 | const void __user *from, unsigned int len) | ||
| 323 | { | ||
| 324 | len = min(kfifo_avail(fifo), len); | ||
| 325 | len -= __kfifo_from_user_data(fifo, from, len, 0); | ||
| 326 | __kfifo_add_in(fifo, len); | ||
| 327 | return len; | ||
| 328 | } | ||
| 329 | EXPORT_SYMBOL(kfifo_from_user); | ||
| 288 | 330 | ||
| 289 | /* then get the rest (if any) from the beginning of the buffer */ | 331 | unsigned int __kfifo_from_user_generic(struct kfifo *fifo, |
| 290 | ret = copy_to_user(to + l, fifo->buffer, len - l); | 332 | const void __user *from, unsigned int len, unsigned int recsize) |
| 333 | { | ||
| 334 | return __kfifo_from_user_rec(fifo, from, len, recsize); | ||
| 335 | } | ||
| 336 | EXPORT_SYMBOL(__kfifo_from_user_generic); | ||
| 291 | 337 | ||
| 292 | if (unlikely(ret)) | 338 | unsigned int __kfifo_to_user_n(struct kfifo *fifo, |
| 293 | return len - ret; | 339 | void __user *to, unsigned int len, unsigned int reclen, |
| 340 | unsigned int recsize) | ||
| 341 | { | ||
| 342 | unsigned int ret; | ||
| 294 | 343 | ||
| 295 | __kfifo_add_out(fifo, len); | 344 | if (kfifo_len(fifo) < reclen + recsize) |
| 345 | return len; | ||
| 296 | 346 | ||
| 347 | ret = __kfifo_to_user_data(fifo, to, reclen, recsize); | ||
| 348 | |||
| 349 | if (likely(ret == 0)) | ||
| 350 | __kfifo_add_out(fifo, reclen + recsize); | ||
| 351 | |||
| 352 | return ret; | ||
| 353 | } | ||
| 354 | EXPORT_SYMBOL(__kfifo_to_user_n); | ||
| 355 | |||
| 356 | /** | ||
| 357 | * kfifo_to_user - gets data from the FIFO and write it to user space | ||
| 358 | * @fifo: the fifo to be used. | ||
| 359 | * @to: where the data must be copied. | ||
| 360 | * @len: the size of the destination buffer. | ||
| 361 | * | ||
| 362 | * This function copies at most @len bytes from the FIFO into the | ||
| 363 | * @to buffer and returns the number of copied bytes. | ||
| 364 | * | ||
| 365 | * Note that with only one concurrent reader and one concurrent | ||
| 366 | * writer, you don't need extra locking to use these functions. | ||
| 367 | */ | ||
| 368 | unsigned int kfifo_to_user(struct kfifo *fifo, | ||
| 369 | void __user *to, unsigned int len) | ||
| 370 | { | ||
| 371 | len = min(kfifo_len(fifo), len); | ||
| 372 | len -= __kfifo_to_user_data(fifo, to, len, 0); | ||
| 373 | __kfifo_add_out(fifo, len); | ||
| 297 | return len; | 374 | return len; |
| 298 | } | 375 | } |
| 299 | EXPORT_SYMBOL(kfifo_to_user); | 376 | EXPORT_SYMBOL(kfifo_to_user); |
| 300 | 377 | ||
| 378 | unsigned int __kfifo_to_user_generic(struct kfifo *fifo, | ||
| 379 | void __user *to, unsigned int len, unsigned int recsize, | ||
| 380 | unsigned int *total) | ||
| 381 | { | ||
| 382 | return __kfifo_to_user_rec(fifo, to, len, recsize, total); | ||
| 383 | } | ||
| 384 | EXPORT_SYMBOL(__kfifo_to_user_generic); | ||
| 385 | |||
| 386 | unsigned int __kfifo_peek_generic(struct kfifo *fifo, unsigned int recsize) | ||
| 387 | { | ||
| 388 | if (recsize == 0) | ||
| 389 | return kfifo_avail(fifo); | ||
| 390 | |||
| 391 | return __kfifo_peek_n(fifo, recsize); | ||
| 392 | } | ||
| 393 | EXPORT_SYMBOL(__kfifo_peek_generic); | ||
| 394 | |||
| 395 | void __kfifo_skip_generic(struct kfifo *fifo, unsigned int recsize) | ||
| 396 | { | ||
| 397 | __kfifo_skip_rec(fifo, recsize); | ||
| 398 | } | ||
| 399 | EXPORT_SYMBOL(__kfifo_skip_generic); | ||
| 400 | |||
