diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2013-07-12 06:34:42 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2013-07-12 06:34:42 -0400 |
commit | f2006e27396f55276f24434f56e208d86e7f9908 (patch) | |
tree | 71896db916d33888b4286f80117d3cac0da40e6d /lib/scatterlist.c | |
parent | e399eb56a6110e13f97e644658648602e2b08de7 (diff) | |
parent | 9903883f1dd6e86f286b7bfa6e4b423f98c1cd9e (diff) |
Merge branch 'linus' into timers/urgent
Get upstream changes so we can apply fixes against them
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'lib/scatterlist.c')
-rw-r--r-- | lib/scatterlist.c | 133 |
1 files changed, 111 insertions, 22 deletions
diff --git a/lib/scatterlist.c b/lib/scatterlist.c index a1cf8cae60e7..a685c8a79578 100644 --- a/lib/scatterlist.c +++ b/lib/scatterlist.c | |||
@@ -247,13 +247,15 @@ int __sg_alloc_table(struct sg_table *table, unsigned int nents, | |||
247 | struct scatterlist *sg, *prv; | 247 | struct scatterlist *sg, *prv; |
248 | unsigned int left; | 248 | unsigned int left; |
249 | 249 | ||
250 | memset(table, 0, sizeof(*table)); | ||
251 | |||
252 | if (nents == 0) | ||
253 | return -EINVAL; | ||
250 | #ifndef ARCH_HAS_SG_CHAIN | 254 | #ifndef ARCH_HAS_SG_CHAIN |
251 | if (WARN_ON_ONCE(nents > max_ents)) | 255 | if (WARN_ON_ONCE(nents > max_ents)) |
252 | return -EINVAL; | 256 | return -EINVAL; |
253 | #endif | 257 | #endif |
254 | 258 | ||
255 | memset(table, 0, sizeof(*table)); | ||
256 | |||
257 | left = nents; | 259 | left = nents; |
258 | prv = NULL; | 260 | prv = NULL; |
259 | do { | 261 | do { |
@@ -453,6 +455,65 @@ void sg_miter_start(struct sg_mapping_iter *miter, struct scatterlist *sgl, | |||
453 | } | 455 | } |
454 | EXPORT_SYMBOL(sg_miter_start); | 456 | EXPORT_SYMBOL(sg_miter_start); |
455 | 457 | ||
458 | static bool sg_miter_get_next_page(struct sg_mapping_iter *miter) | ||
459 | { | ||
460 | if (!miter->__remaining) { | ||
461 | struct scatterlist *sg; | ||
462 | unsigned long pgoffset; | ||
463 | |||
464 | if (!__sg_page_iter_next(&miter->piter)) | ||
465 | return false; | ||
466 | |||
467 | sg = miter->piter.sg; | ||
468 | pgoffset = miter->piter.sg_pgoffset; | ||
469 | |||
470 | miter->__offset = pgoffset ? 0 : sg->offset; | ||
471 | miter->__remaining = sg->offset + sg->length - | ||
472 | (pgoffset << PAGE_SHIFT) - miter->__offset; | ||
473 | miter->__remaining = min_t(unsigned long, miter->__remaining, | ||
474 | PAGE_SIZE - miter->__offset); | ||
475 | } | ||
476 | |||
477 | return true; | ||
478 | } | ||
479 | |||
480 | /** | ||
481 | * sg_miter_skip - reposition mapping iterator | ||
482 | * @miter: sg mapping iter to be skipped | ||
483 | * @offset: number of bytes to plus the current location | ||
484 | * | ||
485 | * Description: | ||
486 | * Sets the offset of @miter to its current location plus @offset bytes. | ||
487 | * If mapping iterator @miter has been proceeded by sg_miter_next(), this | ||
488 | * stops @miter. | ||
489 | * | ||
490 | * Context: | ||
491 | * Don't care if @miter is stopped, or not proceeded yet. | ||
492 | * Otherwise, preemption disabled if the SG_MITER_ATOMIC is set. | ||
493 | * | ||
494 | * Returns: | ||
495 | * true if @miter contains the valid mapping. false if end of sg | ||
496 | * list is reached. | ||
497 | */ | ||
498 | static bool sg_miter_skip(struct sg_mapping_iter *miter, off_t offset) | ||
499 | { | ||
500 | sg_miter_stop(miter); | ||
501 | |||
502 | while (offset) { | ||
503 | off_t consumed; | ||
504 | |||
505 | if (!sg_miter_get_next_page(miter)) | ||
506 | return false; | ||
507 | |||
508 | consumed = min_t(off_t, offset, miter->__remaining); | ||
509 | miter->__offset += consumed; | ||
510 | miter->__remaining -= consumed; | ||
511 | offset -= consumed; | ||
512 | } | ||
513 | |||
514 | return true; | ||
515 | } | ||
516 | |||
456 | /** | 517 | /** |
457 | * sg_miter_next - proceed mapping iterator to the next mapping | 518 | * sg_miter_next - proceed mapping iterator to the next mapping |
458 | * @miter: sg mapping iter to proceed | 519 | * @miter: sg mapping iter to proceed |
@@ -478,22 +539,9 @@ bool sg_miter_next(struct sg_mapping_iter *miter) | |||
478 | * Get to the next page if necessary. | 539 | * Get to the next page if necessary. |
479 | * __remaining, __offset is adjusted by sg_miter_stop | 540 | * __remaining, __offset is adjusted by sg_miter_stop |
480 | */ | 541 | */ |
481 | if (!miter->__remaining) { | 542 | if (!sg_miter_get_next_page(miter)) |
482 | struct scatterlist *sg; | 543 | return false; |
483 | unsigned long pgoffset; | ||
484 | |||
485 | if (!__sg_page_iter_next(&miter->piter)) | ||
486 | return false; | ||
487 | |||
488 | sg = miter->piter.sg; | ||
489 | pgoffset = miter->piter.sg_pgoffset; | ||
490 | 544 | ||
491 | miter->__offset = pgoffset ? 0 : sg->offset; | ||
492 | miter->__remaining = sg->offset + sg->length - | ||
493 | (pgoffset << PAGE_SHIFT) - miter->__offset; | ||
494 | miter->__remaining = min_t(unsigned long, miter->__remaining, | ||
495 | PAGE_SIZE - miter->__offset); | ||
496 | } | ||
497 | miter->page = sg_page_iter_page(&miter->piter); | 545 | miter->page = sg_page_iter_page(&miter->piter); |
498 | miter->consumed = miter->length = miter->__remaining; | 546 | miter->consumed = miter->length = miter->__remaining; |
499 | 547 | ||
@@ -552,14 +600,16 @@ EXPORT_SYMBOL(sg_miter_stop); | |||
552 | * @nents: Number of SG entries | 600 | * @nents: Number of SG entries |
553 | * @buf: Where to copy from | 601 | * @buf: Where to copy from |
554 | * @buflen: The number of bytes to copy | 602 | * @buflen: The number of bytes to copy |
555 | * @to_buffer: transfer direction (non zero == from an sg list to a | 603 | * @skip: Number of bytes to skip before copying |
556 | * buffer, 0 == from a buffer to an sg list | 604 | * @to_buffer: transfer direction (true == from an sg list to a |
605 | * buffer, false == from a buffer to an sg list | ||
557 | * | 606 | * |
558 | * Returns the number of copied bytes. | 607 | * Returns the number of copied bytes. |
559 | * | 608 | * |
560 | **/ | 609 | **/ |
561 | static size_t sg_copy_buffer(struct scatterlist *sgl, unsigned int nents, | 610 | static size_t sg_copy_buffer(struct scatterlist *sgl, unsigned int nents, |
562 | void *buf, size_t buflen, int to_buffer) | 611 | void *buf, size_t buflen, off_t skip, |
612 | bool to_buffer) | ||
563 | { | 613 | { |
564 | unsigned int offset = 0; | 614 | unsigned int offset = 0; |
565 | struct sg_mapping_iter miter; | 615 | struct sg_mapping_iter miter; |
@@ -573,6 +623,9 @@ static size_t sg_copy_buffer(struct scatterlist *sgl, unsigned int nents, | |||
573 | 623 | ||
574 | sg_miter_start(&miter, sgl, nents, sg_flags); | 624 | sg_miter_start(&miter, sgl, nents, sg_flags); |
575 | 625 | ||
626 | if (!sg_miter_skip(&miter, skip)) | ||
627 | return false; | ||
628 | |||
576 | local_irq_save(flags); | 629 | local_irq_save(flags); |
577 | 630 | ||
578 | while (sg_miter_next(&miter) && offset < buflen) { | 631 | while (sg_miter_next(&miter) && offset < buflen) { |
@@ -607,7 +660,7 @@ static size_t sg_copy_buffer(struct scatterlist *sgl, unsigned int nents, | |||
607 | size_t sg_copy_from_buffer(struct scatterlist *sgl, unsigned int nents, | 660 | size_t sg_copy_from_buffer(struct scatterlist *sgl, unsigned int nents, |
608 | void *buf, size_t buflen) | 661 | void *buf, size_t buflen) |
609 | { | 662 | { |
610 | return sg_copy_buffer(sgl, nents, buf, buflen, 0); | 663 | return sg_copy_buffer(sgl, nents, buf, buflen, 0, false); |
611 | } | 664 | } |
612 | EXPORT_SYMBOL(sg_copy_from_buffer); | 665 | EXPORT_SYMBOL(sg_copy_from_buffer); |
613 | 666 | ||
@@ -624,6 +677,42 @@ EXPORT_SYMBOL(sg_copy_from_buffer); | |||
624 | size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents, | 677 | size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents, |
625 | void *buf, size_t buflen) | 678 | void *buf, size_t buflen) |
626 | { | 679 | { |
627 | return sg_copy_buffer(sgl, nents, buf, buflen, 1); | 680 | return sg_copy_buffer(sgl, nents, buf, buflen, 0, true); |
628 | } | 681 | } |
629 | EXPORT_SYMBOL(sg_copy_to_buffer); | 682 | EXPORT_SYMBOL(sg_copy_to_buffer); |
683 | |||
684 | /** | ||
685 | * sg_pcopy_from_buffer - Copy from a linear buffer to an SG list | ||
686 | * @sgl: The SG list | ||
687 | * @nents: Number of SG entries | ||
688 | * @buf: Where to copy from | ||
689 | * @skip: Number of bytes to skip before copying | ||
690 | * @buflen: The number of bytes to copy | ||
691 | * | ||
692 | * Returns the number of copied bytes. | ||
693 | * | ||
694 | **/ | ||
695 | size_t sg_pcopy_from_buffer(struct scatterlist *sgl, unsigned int nents, | ||
696 | void *buf, size_t buflen, off_t skip) | ||
697 | { | ||
698 | return sg_copy_buffer(sgl, nents, buf, buflen, skip, false); | ||
699 | } | ||
700 | EXPORT_SYMBOL(sg_pcopy_from_buffer); | ||
701 | |||
702 | /** | ||
703 | * sg_pcopy_to_buffer - Copy from an SG list to a linear buffer | ||
704 | * @sgl: The SG list | ||
705 | * @nents: Number of SG entries | ||
706 | * @buf: Where to copy to | ||
707 | * @skip: Number of bytes to skip before copying | ||
708 | * @buflen: The number of bytes to copy | ||
709 | * | ||
710 | * Returns the number of copied bytes. | ||
711 | * | ||
712 | **/ | ||
713 | size_t sg_pcopy_to_buffer(struct scatterlist *sgl, unsigned int nents, | ||
714 | void *buf, size_t buflen, off_t skip) | ||
715 | { | ||
716 | return sg_copy_buffer(sgl, nents, buf, buflen, skip, true); | ||
717 | } | ||
718 | EXPORT_SYMBOL(sg_pcopy_to_buffer); | ||