Skip to content

Commit 8b0977e

Browse files
kelleymhChristoph Hellwig
authored andcommitted
swiotlb: track and report io_tlb_used high water marks in debugfs
swiotlb currently reports the total number of slabs and the instantaneous in-use slabs in debugfs. But with increased usage of swiotlb for all I/O in Confidential Computing (coco) VMs, it has become difficult to know how much memory to allocate for swiotlb bounce buffers, either via the automatic algorithm in the kernel or by specifying a value on the kernel boot line. The current automatic algorithm generously allocates swiotlb bounce buffer memory, and may be wasting significant memory in many use cases. To support better understanding of swiotlb usage, add tracking of the the high water mark for usage of the default swiotlb bounce buffer memory pool and any reserved memory pools. Report these high water marks in debugfs along with the other swiotlb pool metrics. Allow the high water marks to be reset to zero at runtime by writing to them. Signed-off-by: Michael Kelley <mikelley@microsoft.com> Signed-off-by: Christoph Hellwig <hch@lst.de>
1 parent 5499d01 commit 8b0977e

2 files changed

Lines changed: 73 additions & 0 deletions

File tree

include/linux/swiotlb.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,11 @@ dma_addr_t swiotlb_map(struct device *dev, phys_addr_t phys,
8787
* @for_alloc: %true if the pool is used for memory allocation
8888
* @nareas: The area number in the pool.
8989
* @area_nslabs: The slot number in the area.
90+
* @total_used: The total number of slots in the pool that are currently used
91+
* across all areas. Used only for calculating used_hiwater in
92+
* debugfs.
93+
* @used_hiwater: The high water mark for total_used. Used only for reporting
94+
* in debugfs.
9095
*/
9196
struct io_tlb_mem {
9297
phys_addr_t start;
@@ -102,6 +107,8 @@ struct io_tlb_mem {
102107
unsigned int area_nslabs;
103108
struct io_tlb_area *areas;
104109
struct io_tlb_slot *slots;
110+
atomic_long_t total_used;
111+
atomic_long_t used_hiwater;
105112
};
106113
extern struct io_tlb_mem io_tlb_default_mem;
107114

kernel/dma/swiotlb.c

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,40 @@ static unsigned int wrap_area_index(struct io_tlb_mem *mem, unsigned int index)
608608
return index;
609609
}
610610

611+
/*
612+
* Track the total used slots with a global atomic value in order to have
613+
* correct information to determine the high water mark. The mem_used()
614+
* function gives imprecise results because there's no locking across
615+
* multiple areas.
616+
*/
617+
#ifdef CONFIG_DEBUG_FS
618+
static void inc_used_and_hiwater(struct io_tlb_mem *mem, unsigned int nslots)
619+
{
620+
unsigned long old_hiwater, new_used;
621+
622+
new_used = atomic_long_add_return(nslots, &mem->total_used);
623+
old_hiwater = atomic_long_read(&mem->used_hiwater);
624+
do {
625+
if (new_used <= old_hiwater)
626+
break;
627+
} while (!atomic_long_try_cmpxchg(&mem->used_hiwater,
628+
&old_hiwater, new_used));
629+
}
630+
631+
static void dec_used(struct io_tlb_mem *mem, unsigned int nslots)
632+
{
633+
atomic_long_sub(nslots, &mem->total_used);
634+
}
635+
636+
#else /* !CONFIG_DEBUG_FS */
637+
static void inc_used_and_hiwater(struct io_tlb_mem *mem, unsigned int nslots)
638+
{
639+
}
640+
static void dec_used(struct io_tlb_mem *mem, unsigned int nslots)
641+
{
642+
}
643+
#endif /* CONFIG_DEBUG_FS */
644+
611645
/*
612646
* Find a suitable number of IO TLB entries size that will fit this request and
613647
* allocate a buffer from that IO TLB pool.
@@ -702,6 +736,8 @@ static int swiotlb_do_find_slots(struct device *dev, int area_index,
702736
area->index = wrap_area_index(mem, index + nslots);
703737
area->used += nslots;
704738
spin_unlock_irqrestore(&area->lock, flags);
739+
740+
inc_used_and_hiwater(mem, nslots);
705741
return slot_index;
706742
}
707743

@@ -834,6 +870,8 @@ static void swiotlb_release_slots(struct device *dev, phys_addr_t tlb_addr)
834870
mem->slots[i].list = ++count;
835871
area->used -= nslots;
836872
spin_unlock_irqrestore(&area->lock, flags);
873+
874+
dec_used(mem, nslots);
837875
}
838876

839877
/*
@@ -935,18 +973,46 @@ static int io_tlb_used_get(void *data, u64 *val)
935973
*val = mem_used(mem);
936974
return 0;
937975
}
976+
977+
static int io_tlb_hiwater_get(void *data, u64 *val)
978+
{
979+
struct io_tlb_mem *mem = data;
980+
981+
*val = atomic_long_read(&mem->used_hiwater);
982+
return 0;
983+
}
984+
985+
static int io_tlb_hiwater_set(void *data, u64 val)
986+
{
987+
struct io_tlb_mem *mem = data;
988+
989+
/* Only allow setting to zero */
990+
if (val != 0)
991+
return -EINVAL;
992+
993+
atomic_long_set(&mem->used_hiwater, val);
994+
return 0;
995+
}
996+
938997
DEFINE_DEBUGFS_ATTRIBUTE(fops_io_tlb_used, io_tlb_used_get, NULL, "%llu\n");
998+
DEFINE_DEBUGFS_ATTRIBUTE(fops_io_tlb_hiwater, io_tlb_hiwater_get,
999+
io_tlb_hiwater_set, "%llu\n");
9391000

9401001
static void swiotlb_create_debugfs_files(struct io_tlb_mem *mem,
9411002
const char *dirname)
9421003
{
1004+
atomic_long_set(&mem->total_used, 0);
1005+
atomic_long_set(&mem->used_hiwater, 0);
1006+
9431007
mem->debugfs = debugfs_create_dir(dirname, io_tlb_default_mem.debugfs);
9441008
if (!mem->nslabs)
9451009
return;
9461010

9471011
debugfs_create_ulong("io_tlb_nslabs", 0400, mem->debugfs, &mem->nslabs);
9481012
debugfs_create_file("io_tlb_used", 0400, mem->debugfs, mem,
9491013
&fops_io_tlb_used);
1014+
debugfs_create_file("io_tlb_used_hiwater", 0600, mem->debugfs, mem,
1015+
&fops_io_tlb_hiwater);
9501016
}
9511017

9521018
static int __init __maybe_unused swiotlb_create_default_debugfs(void)

0 commit comments

Comments
 (0)