Skip to content

Commit 282631c

Browse files
urezkiakpm00
authored andcommitted
mm: vmalloc: remove global purge_vmap_area_root rb-tree
Similar to busy VA, lazily-freed area is stored to a node it belongs to. Such approach does not require any global locking primitive, instead an access becomes scalable what mitigates a contention. This patch removes a global purge-lock, global purge-tree and global purge list. Link: https://lkml.kernel.org/r/20240102184633.748113-7-urezki@gmail.com Signed-off-by: Uladzislau Rezki (Sony) <urezki@gmail.com> Reviewed-by: Baoquan He <bhe@redhat.com> Cc: Christoph Hellwig <hch@lst.de> Cc: Dave Chinner <david@fromorbit.com> Cc: Joel Fernandes (Google) <joel@joelfernandes.org> Cc: Kazuhito Hagio <k-hagio-ab@nec.com> Cc: Liam R. Howlett <Liam.Howlett@oracle.com> Cc: Lorenzo Stoakes <lstoakes@gmail.com> Cc: Matthew Wilcox (Oracle) <willy@infradead.org> Cc: Oleksiy Avramchenko <oleksiy.avramchenko@sony.com> Cc: Paul E. McKenney <paulmck@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
1 parent 55c49fe commit 282631c

File tree

1 file changed

+82
-53
lines changed

1 file changed

+82
-53
lines changed

mm/vmalloc.c

+82-53
Original file line numberDiff line numberDiff line change
@@ -731,10 +731,6 @@ EXPORT_SYMBOL(vmalloc_to_pfn);
731731
static DEFINE_SPINLOCK(free_vmap_area_lock);
732732
static bool vmap_initialized __read_mostly;
733733

734-
static struct rb_root purge_vmap_area_root = RB_ROOT;
735-
static LIST_HEAD(purge_vmap_area_list);
736-
static DEFINE_SPINLOCK(purge_vmap_area_lock);
737-
738734
/*
739735
* This kmem_cache is used for vmap_area objects. Instead of
740736
* allocating from slab we reuse an object from this cache to
@@ -782,6 +778,12 @@ struct rb_list {
782778
static struct vmap_node {
783779
/* Bookkeeping data of this node. */
784780
struct rb_list busy;
781+
struct rb_list lazy;
782+
783+
/*
784+
* Ready-to-free areas.
785+
*/
786+
struct list_head purge_list;
785787
} single;
786788

787789
static struct vmap_node *vmap_nodes = &single;
@@ -1766,40 +1768,22 @@ static DEFINE_MUTEX(vmap_purge_lock);
17661768

17671769
/* for per-CPU blocks */
17681770
static void purge_fragmented_blocks_allcpus(void);
1771+
static cpumask_t purge_nodes;
17691772

17701773
/*
17711774
* Purges all lazily-freed vmap areas.
17721775
*/
1773-
static bool __purge_vmap_area_lazy(unsigned long start, unsigned long end)
1776+
static unsigned long
1777+
purge_vmap_node(struct vmap_node *vn)
17741778
{
1775-
unsigned long resched_threshold;
1776-
unsigned int num_purged_areas = 0;
1777-
struct list_head local_purge_list;
1779+
unsigned long num_purged_areas = 0;
17781780
struct vmap_area *va, *n_va;
17791781

1780-
lockdep_assert_held(&vmap_purge_lock);
1781-
1782-
spin_lock(&purge_vmap_area_lock);
1783-
purge_vmap_area_root = RB_ROOT;
1784-
list_replace_init(&purge_vmap_area_list, &local_purge_list);
1785-
spin_unlock(&purge_vmap_area_lock);
1786-
1787-
if (unlikely(list_empty(&local_purge_list)))
1788-
goto out;
1789-
1790-
start = min(start,
1791-
list_first_entry(&local_purge_list,
1792-
struct vmap_area, list)->va_start);
1793-
1794-
end = max(end,
1795-
list_last_entry(&local_purge_list,
1796-
struct vmap_area, list)->va_end);
1797-
1798-
flush_tlb_kernel_range(start, end);
1799-
resched_threshold = lazy_max_pages() << 1;
1782+
if (list_empty(&vn->purge_list))
1783+
return 0;
18001784

18011785
spin_lock(&free_vmap_area_lock);
1802-
list_for_each_entry_safe(va, n_va, &local_purge_list, list) {
1786+
list_for_each_entry_safe(va, n_va, &vn->purge_list, list) {
18031787
unsigned long nr = (va->va_end - va->va_start) >> PAGE_SHIFT;
18041788
unsigned long orig_start = va->va_start;
18051789
unsigned long orig_end = va->va_end;
@@ -1821,13 +1805,55 @@ static bool __purge_vmap_area_lazy(unsigned long start, unsigned long end)
18211805

18221806
atomic_long_sub(nr, &vmap_lazy_nr);
18231807
num_purged_areas++;
1824-
1825-
if (atomic_long_read(&vmap_lazy_nr) < resched_threshold)
1826-
cond_resched_lock(&free_vmap_area_lock);
18271808
}
18281809
spin_unlock(&free_vmap_area_lock);
18291810

1830-
out:
1811+
return num_purged_areas;
1812+
}
1813+
1814+
/*
1815+
* Purges all lazily-freed vmap areas.
1816+
*/
1817+
static bool __purge_vmap_area_lazy(unsigned long start, unsigned long end)
1818+
{
1819+
unsigned long num_purged_areas = 0;
1820+
struct vmap_node *vn;
1821+
int i;
1822+
1823+
lockdep_assert_held(&vmap_purge_lock);
1824+
purge_nodes = CPU_MASK_NONE;
1825+
1826+
for (i = 0; i < nr_vmap_nodes; i++) {
1827+
vn = &vmap_nodes[i];
1828+
1829+
INIT_LIST_HEAD(&vn->purge_list);
1830+
1831+
if (RB_EMPTY_ROOT(&vn->lazy.root))
1832+
continue;
1833+
1834+
spin_lock(&vn->lazy.lock);
1835+
WRITE_ONCE(vn->lazy.root.rb_node, NULL);
1836+
list_replace_init(&vn->lazy.head, &vn->purge_list);
1837+
spin_unlock(&vn->lazy.lock);
1838+
1839+
start = min(start, list_first_entry(&vn->purge_list,
1840+
struct vmap_area, list)->va_start);
1841+
1842+
end = max(end, list_last_entry(&vn->purge_list,
1843+
struct vmap_area, list)->va_end);
1844+
1845+
cpumask_set_cpu(i, &purge_nodes);
1846+
}
1847+
1848+
if (cpumask_weight(&purge_nodes) > 0) {
1849+
flush_tlb_kernel_range(start, end);
1850+
1851+
for_each_cpu(i, &purge_nodes) {
1852+
vn = &nodes[i];
1853+
num_purged_areas += purge_vmap_node(vn);
1854+
}
1855+
}
1856+
18311857
trace_purge_vmap_area_lazy(start, end, num_purged_areas);
18321858
return num_purged_areas > 0;
18331859
}
@@ -1846,16 +1872,9 @@ static void reclaim_and_purge_vmap_areas(void)
18461872

18471873
static void drain_vmap_area_work(struct work_struct *work)
18481874
{
1849-
unsigned long nr_lazy;
1850-
1851-
do {
1852-
mutex_lock(&vmap_purge_lock);
1853-
__purge_vmap_area_lazy(ULONG_MAX, 0);
1854-
mutex_unlock(&vmap_purge_lock);
1855-
1856-
/* Recheck if further work is required. */
1857-
nr_lazy = atomic_long_read(&vmap_lazy_nr);
1858-
} while (nr_lazy > lazy_max_pages());
1875+
mutex_lock(&vmap_purge_lock);
1876+
__purge_vmap_area_lazy(ULONG_MAX, 0);
1877+
mutex_unlock(&vmap_purge_lock);
18591878
}
18601879

18611880
/*
@@ -1865,6 +1884,7 @@ static void drain_vmap_area_work(struct work_struct *work)
18651884
*/
18661885
static void free_vmap_area_noflush(struct vmap_area *va)
18671886
{
1887+
struct vmap_node *vn = addr_to_node(va->va_start);
18681888
unsigned long nr_lazy_max = lazy_max_pages();
18691889
unsigned long va_start = va->va_start;
18701890
unsigned long nr_lazy;
@@ -1878,10 +1898,9 @@ static void free_vmap_area_noflush(struct vmap_area *va)
18781898
/*
18791899
* Merge or place it to the purge tree/list.
18801900
*/
1881-
spin_lock(&purge_vmap_area_lock);
1882-
merge_or_add_vmap_area(va,
1883-
&purge_vmap_area_root, &purge_vmap_area_list);
1884-
spin_unlock(&purge_vmap_area_lock);
1901+
spin_lock(&vn->lazy.lock);
1902+
merge_or_add_vmap_area(va, &vn->lazy.root, &vn->lazy.head);
1903+
spin_unlock(&vn->lazy.lock);
18851904

18861905
trace_free_vmap_area_noflush(va_start, nr_lazy, nr_lazy_max);
18871906

@@ -4411,15 +4430,21 @@ static void show_numa_info(struct seq_file *m, struct vm_struct *v)
44114430

44124431
static void show_purge_info(struct seq_file *m)
44134432
{
4433+
struct vmap_node *vn;
44144434
struct vmap_area *va;
4435+
int i;
44154436

4416-
spin_lock(&purge_vmap_area_lock);
4417-
list_for_each_entry(va, &purge_vmap_area_list, list) {
4418-
seq_printf(m, "0x%pK-0x%pK %7ld unpurged vm_area\n",
4419-
(void *)va->va_start, (void *)va->va_end,
4420-
va->va_end - va->va_start);
4437+
for (i = 0; i < nr_vmap_nodes; i++) {
4438+
vn = &vmap_nodes[i];
4439+
4440+
spin_lock(&vn->lazy.lock);
4441+
list_for_each_entry(va, &vn->lazy.head, list) {
4442+
seq_printf(m, "0x%pK-0x%pK %7ld unpurged vm_area\n",
4443+
(void *)va->va_start, (void *)va->va_end,
4444+
va->va_end - va->va_start);
4445+
}
4446+
spin_unlock(&vn->lazy.lock);
44214447
}
4422-
spin_unlock(&purge_vmap_area_lock);
44234448
}
44244449

44254450
static int s_show(struct seq_file *m, void *p)
@@ -4558,6 +4583,10 @@ static void vmap_init_nodes(void)
45584583
vn->busy.root = RB_ROOT;
45594584
INIT_LIST_HEAD(&vn->busy.head);
45604585
spin_lock_init(&vn->busy.lock);
4586+
4587+
vn->lazy.root = RB_ROOT;
4588+
INIT_LIST_HEAD(&vn->lazy.head);
4589+
spin_lock_init(&vn->lazy.lock);
45614590
}
45624591
}
45634592

0 commit comments

Comments
 (0)