diff options
| -rw-r--r-- | include/linux/scatterlist.h | 5 | ||||
| -rw-r--r-- | lib/scatterlist.c | 88 |
2 files changed, 88 insertions, 5 deletions
diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h index 26806775b11b..adae88f5b0ab 100644 --- a/include/linux/scatterlist.h +++ b/include/linux/scatterlist.h | |||
| @@ -244,6 +244,11 @@ size_t sg_copy_from_buffer(struct scatterlist *sgl, unsigned int nents, | |||
| 244 | size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents, | 244 | size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents, |
| 245 | void *buf, size_t buflen); | 245 | void *buf, size_t buflen); |
| 246 | 246 | ||
| 247 | size_t sg_pcopy_from_buffer(struct scatterlist *sgl, unsigned int nents, | ||
| 248 | void *buf, size_t buflen, off_t skip); | ||
| 249 | size_t sg_pcopy_to_buffer(struct scatterlist *sgl, unsigned int nents, | ||
| 250 | void *buf, size_t buflen, off_t skip); | ||
| 251 | |||
| 247 | /* | 252 | /* |
| 248 | * Maximum number of entries that will be allocated in one piece, if | 253 | * Maximum number of entries that will be allocated in one piece, if |
| 249 | * a list larger than this is required then chaining will be utilized. | 254 | * a list larger than this is required then chaining will be utilized. |
diff --git a/lib/scatterlist.c b/lib/scatterlist.c index c35b929435f3..129a82f707df 100644 --- a/lib/scatterlist.c +++ b/lib/scatterlist.c | |||
| @@ -476,6 +476,43 @@ static bool sg_miter_get_next_page(struct sg_mapping_iter *miter) | |||
| 476 | } | 476 | } |
| 477 | 477 | ||
| 478 | /** | 478 | /** |
| 479 | * sg_miter_skip - reposition mapping iterator | ||
| 480 | * @miter: sg mapping iter to be skipped | ||
| 481 | * @offset: number of bytes to plus the current location | ||
| 482 | * | ||
| 483 | * Description: | ||
| 484 | * Sets the offset of @miter to its current location plus @offset bytes. | ||
| 485 | * If mapping iterator @miter has been proceeded by sg_miter_next(), this | ||
| 486 | * stops @miter. | ||
| 487 | * | ||
| 488 | * Context: | ||
| 489 | * Don't care if @miter is stopped, or not proceeded yet. | ||
| 490 | * Otherwise, preemption disabled if the SG_MITER_ATOMIC is set. | ||
| 491 | * | ||
| 492 | * Returns: | ||
| 493 | * true if @miter contains the valid mapping. false if end of sg | ||
| 494 | * list is reached. | ||
| 495 | */ | ||
| 496 | static bool sg_miter_skip(struct sg_mapping_iter *miter, off_t offset) | ||
| 497 | { | ||
| 498 | sg_miter_stop(miter); | ||
| 499 | |||
| 500 | while (offset) { | ||
| 501 | off_t consumed; | ||
| 502 | |||
| 503 | if (!sg_miter_get_next_page(miter)) | ||
| 504 | return false; | ||
| 505 | |||
| 506 | consumed = min_t(off_t, offset, miter->__remaining); | ||
| 507 | miter->__offset += consumed; | ||
| 508 | miter->__remaining -= consumed; | ||
| 509 | offset -= consumed; | ||
| 510 | } | ||
| 511 | |||
| 512 | return true; | ||
| 513 | } | ||
| 514 | |||
| 515 | /** | ||
| 479 | * sg_miter_next - proceed mapping iterator to the next mapping | 516 | * sg_miter_next - proceed mapping iterator to the next mapping |
| 480 | * @miter: sg mapping iter to proceed | 517 | * @miter: sg mapping iter to proceed |
| 481 | * | 518 | * |
| @@ -561,14 +598,16 @@ EXPORT_SYMBOL(sg_miter_stop); | |||
| 561 | * @nents: Number of SG entries | 598 | * @nents: Number of SG entries |
| 562 | * @buf: Where to copy from | 599 | * @buf: Where to copy from |
| 563 | * @buflen: The number of bytes to copy | 600 | * @buflen: The number of bytes to copy |
| 564 | * @to_buffer: transfer direction (non zero == from an sg list to a | 601 | * @skip: Number of bytes to skip before copying |
| 565 | * buffer, 0 == from a buffer to an sg list | 602 | * @to_buffer: transfer direction (true == from an sg list to a |
| 603 | * buffer, false == from a buffer to an sg list | ||
| 566 | * | 604 | * |
| 567 | * Returns the number of copied bytes. | 605 | * Returns the number of copied bytes. |
| 568 | * | 606 | * |
| 569 | **/ | 607 | **/ |
| 570 | static size_t sg_copy_buffer(struct scatterlist *sgl, unsigned int nents, | 608 | static size_t sg_copy_buffer(struct scatterlist *sgl, unsigned int nents, |
| 571 | void *buf, size_t buflen, int to_buffer) | 609 | void *buf, size_t buflen, off_t skip, |
| 610 | bool to_buffer) | ||
| 572 | { | 611 | { |
| 573 | unsigned int offset = 0; | 612 | unsigned int offset = 0; |
| 574 | struct sg_mapping_iter miter; | 613 | struct sg_mapping_iter miter; |
| @@ -582,6 +621,9 @@ static size_t sg_copy_buffer(struct scatterlist *sgl, unsigned int nents, | |||
| 582 | 621 | ||
| 583 | sg_miter_start(&miter, sgl, nents, sg_flags); | 622 | sg_miter_start(&miter, sgl, nents, sg_flags); |
| 584 | 623 | ||
| 624 | if (!sg_miter_skip(&miter, skip)) | ||
| 625 | return false; | ||
| 626 | |||
| 585 | local_irq_save(flags); | 627 | local_irq_save(flags); |
| 586 | 628 | ||
| 587 | while (sg_miter_next(&miter) && offset < buflen) { | 629 | while (sg_miter_next(&miter) && offset < buflen) { |
| @@ -616,7 +658,7 @@ static size_t sg_copy_buffer(struct scatterlist *sgl, unsigned int nents, | |||
| 616 | size_t sg_copy_from_buffer(struct scatterlist *sgl, unsigned int nents, | 658 | size_t sg_copy_from_buffer(struct scatterlist *sgl, unsigned int nents, |
| 617 | void *buf, size_t buflen) | 659 | void *buf, size_t buflen) |
| 618 | { | 660 | { |
| 619 | return sg_copy_buffer(sgl, nents, buf, buflen, 0); | 661 | return sg_copy_buffer(sgl, nents, buf, buflen, 0, false); |
| 620 | } | 662 | } |
| 621 | EXPORT_SYMBOL(sg_copy_from_buffer); | 663 | EXPORT_SYMBOL(sg_copy_from_buffer); |
| 622 | 664 | ||
| @@ -633,6 +675,42 @@ EXPORT_SYMBOL(sg_copy_from_buffer); | |||
| 633 | size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents, | 675 | size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents, |
| 634 | void *buf, size_t buflen) | 676 | void *buf, size_t buflen) |
| 635 | { | 677 | { |
| 636 | return sg_copy_buffer(sgl, nents, buf, buflen, 1); | 678 | return sg_copy_buffer(sgl, nents, buf, buflen, 0, true); |
| 637 | } | 679 | } |
| 638 | EXPORT_SYMBOL(sg_copy_to_buffer); | 680 | EXPORT_SYMBOL(sg_copy_to_buffer); |
| 681 | |||
| 682 | /** | ||
| 683 | * sg_pcopy_from_buffer - Copy from a linear buffer to an SG list | ||
| 684 | * @sgl: The SG list | ||
| 685 | * @nents: Number of SG entries | ||
| 686 | * @buf: Where to copy from | ||
| 687 | * @skip: Number of bytes to skip before copying | ||
| 688 | * @buflen: The number of bytes to copy | ||
| 689 | * | ||
| 690 | * Returns the number of copied bytes. | ||
| 691 | * | ||
| 692 | **/ | ||
| 693 | size_t sg_pcopy_from_buffer(struct scatterlist *sgl, unsigned int nents, | ||
| 694 | void *buf, size_t buflen, off_t skip) | ||
| 695 | { | ||
| 696 | return sg_copy_buffer(sgl, nents, buf, buflen, skip, false); | ||
| 697 | } | ||
| 698 | EXPORT_SYMBOL(sg_pcopy_from_buffer); | ||
| 699 | |||
| 700 | /** | ||
| 701 | * sg_pcopy_to_buffer - Copy from an SG list to a linear buffer | ||
| 702 | * @sgl: The SG list | ||
| 703 | * @nents: Number of SG entries | ||
| 704 | * @buf: Where to copy to | ||
| 705 | * @skip: Number of bytes to skip before copying | ||
| 706 | * @buflen: The number of bytes to copy | ||
| 707 | * | ||
| 708 | * Returns the number of copied bytes. | ||
| 709 | * | ||
| 710 | **/ | ||
| 711 | size_t sg_pcopy_to_buffer(struct scatterlist *sgl, unsigned int nents, | ||
| 712 | void *buf, size_t buflen, off_t skip) | ||
| 713 | { | ||
| 714 | return sg_copy_buffer(sgl, nents, buf, buflen, skip, true); | ||
| 715 | } | ||
| 716 | EXPORT_SYMBOL(sg_pcopy_to_buffer); | ||
