Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'dma-mapping-6.3-2023-03-31' of git://git.infradead.org/users/hch/dma-mapping

Pull dma-mapping fixes from Christoph Hellwig:

- fix for swiotlb deadlock due to wrong alignment checks (GuoRui.Yu,
Petr Tesarik)

* tag 'dma-mapping-6.3-2023-03-31' of git://git.infradead.org/users/hch/dma-mapping:
swiotlb: fix slot alignment checks
swiotlb: use wrap_area_index() instead of open-coding it
swiotlb: fix the deadlock in swiotlb_do_find_slots

+16 -13
+16 -13
kernel/dma/swiotlb.c
··· 625 625 unsigned int iotlb_align_mask = 626 626 dma_get_min_align_mask(dev) & ~(IO_TLB_SIZE - 1); 627 627 unsigned int nslots = nr_slots(alloc_size), stride; 628 - unsigned int index, wrap, count = 0, i; 629 628 unsigned int offset = swiotlb_align_offset(dev, orig_addr); 629 + unsigned int index, slots_checked, count = 0, i; 630 630 unsigned long flags; 631 631 unsigned int slot_base; 632 632 unsigned int slot_index; ··· 635 635 BUG_ON(area_index >= mem->nareas); 636 636 637 637 /* 638 + * For allocations of PAGE_SIZE or larger only look for page aligned 639 + * allocations. 640 + */ 641 + if (alloc_size >= PAGE_SIZE) 642 + iotlb_align_mask &= PAGE_MASK; 643 + iotlb_align_mask &= alloc_align_mask; 644 + 645 + /* 638 646 * For mappings with an alignment requirement don't bother looping to 639 - * unaligned slots once we found an aligned one. For allocations of 640 - * PAGE_SIZE or larger only look for page aligned allocations. 647 + * unaligned slots once we found an aligned one. 641 648 */ 642 649 stride = (iotlb_align_mask >> IO_TLB_SHIFT) + 1; 643 - if (alloc_size >= PAGE_SIZE) 644 - stride = max(stride, stride << (PAGE_SHIFT - IO_TLB_SHIFT)); 645 - stride = max(stride, (alloc_align_mask >> IO_TLB_SHIFT) + 1); 646 650 647 651 spin_lock_irqsave(&area->lock, flags); 648 652 if (unlikely(nslots > mem->area_nslabs - area->used)) 649 653 goto not_found; 650 654 651 655 slot_base = area_index * mem->area_nslabs; 652 - index = wrap = wrap_area_index(mem, ALIGN(area->index, stride)); 656 + index = area->index; 653 657 654 - do { 658 + for (slots_checked = 0; slots_checked < mem->area_nslabs; ) { 655 659 slot_index = slot_base + index; 656 660 657 661 if (orig_addr && 658 662 (slot_addr(tbl_dma_addr, slot_index) & 659 663 iotlb_align_mask) != (orig_addr & iotlb_align_mask)) { 660 664 index = wrap_area_index(mem, index + 1); 665 + slots_checked++; 661 666 continue; 662 667 } 663 668 ··· 678 673 goto found; 679 674 } 680 675 index = wrap_area_index(mem, index + stride); 681 - } while (index != wrap); 676 + slots_checked += stride; 677 + } 682 678 683 679 not_found: 684 680 spin_unlock_irqrestore(&area->lock, flags); ··· 699 693 /* 700 694 * Update the indices to avoid searching in the next round. 701 695 */ 702 - if (index + nslots < mem->area_nslabs) 703 - area->index = index + nslots; 704 - else 705 - area->index = 0; 696 + area->index = wrap_area_index(mem, index + nslots); 706 697 area->used += nslots; 707 698 spin_unlock_irqrestore(&area->lock, flags); 708 699 return slot_index;