From: Christoph Hellwig <hch@infradead.org>
To: Joel Fernandes <joelaf@google.com>
Cc: linux-kernel@vger.kernel.org, linux-rt-users@vger.kernel.org,
Chris Wilson <chris@chris-wilson.co.uk>,
Jisheng Zhang <jszhang@marvell.com>,
John Dias <joaodias@google.com>,
Andrew Morton <akpm@linux-foundation.org>,
"open list:MEMORY MANAGEMENT" <linux-mm@kvack.org>
Subject: Re: [PATCH v3] mm: vmalloc: Replace purge_lock spinlock with atomic refcount
Date: Sat, 15 Oct 2016 09:46:13 -0700 [thread overview]
Message-ID: <20161015164613.GA26079@infradead.org> (raw)
In-Reply-To: <1476535979-27467-1-git-send-email-joelaf@google.com>
atomic_t magic for llocking is always a bit iffy.
The real question is: what is purge_lock even supposed to protect?
- purge_fragmented_blocks seems to have it's own local protection.
- all handling of of valist is implicity protected by the atomic
list deletion in llist_del_all
- the manipulation of vmap_lazy_nr already is atomic
- flush_tlb_kernel_range should not require any synchronization
- the calls to __free_vmap_area are sychronized by vmap_area_lock
- *start and *end always point to on-stack variables, never mind
that the caller never looks at the updated values anyway.
And once we use the cmpxchg in llist_del_all as the effectit protection
against multiple concurrent callers (slightly sloopy) there just be
nothing else to synchronize.
And while we're at it the code structure here is totally grotty.
So what about the patch below (only boot tested):
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index f2481cb..c2b9a98 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -613,82 +613,43 @@ void set_iounmap_nonlazy(void)
atomic_set(&vmap_lazy_nr, lazy_max_pages()+1);
}
-/*
- * Purges all lazily-freed vmap areas.
- *
- * If sync is 0 then don't purge if there is already a purge in progress.
- * If force_flush is 1, then flush kernel TLBs between *start and *end even
- * if we found no lazy vmap areas to unmap (callers can use this to optimise
- * their own TLB flushing).
- * Returns with *start = min(*start, lowest purged address)
- * *end = max(*end, highest purged address)
- */
-static void __purge_vmap_area_lazy(unsigned long *start, unsigned long *end,
- int sync, int force_flush)
+static bool __purge_vmap_area_lazy(unsigned long start, unsigned long end)
{
- static DEFINE_SPINLOCK(purge_lock);
struct llist_node *valist;
struct vmap_area *va;
struct vmap_area *n_va;
int nr = 0;
- /*
- * If sync is 0 but force_flush is 1, we'll go sync anyway but callers
- * should not expect such behaviour. This just simplifies locking for
- * the case that isn't actually used at the moment anyway.
- */
- if (!sync && !force_flush) {
- if (!spin_trylock(&purge_lock))
- return;
- } else
- spin_lock(&purge_lock);
-
- if (sync)
- purge_fragmented_blocks_allcpus();
-
valist = llist_del_all(&vmap_purge_list);
llist_for_each_entry(va, valist, purge_list) {
- if (va->va_start < *start)
- *start = va->va_start;
- if (va->va_end > *end)
- *end = va->va_end;
+ if (va->va_start < start)
+ start = va->va_start;
+ if (va->va_end > end)
+ end = va->va_end;
nr += (va->va_end - va->va_start) >> PAGE_SHIFT;
}
- if (nr)
- atomic_sub(nr, &vmap_lazy_nr);
-
- if (nr || force_flush)
- flush_tlb_kernel_range(*start, *end);
-
- if (nr) {
- spin_lock(&vmap_area_lock);
- llist_for_each_entry_safe(va, n_va, valist, purge_list)
- __free_vmap_area(va);
- spin_unlock(&vmap_area_lock);
- }
- spin_unlock(&purge_lock);
-}
+ if (!nr)
+ return false;
-/*
- * Kick off a purge of the outstanding lazy areas. Don't bother if somebody
- * is already purging.
- */
-static void try_purge_vmap_area_lazy(void)
-{
- unsigned long start = ULONG_MAX, end = 0;
+ atomic_sub(nr, &vmap_lazy_nr);
- __purge_vmap_area_lazy(&start, &end, 0, 0);
+ spin_lock(&vmap_area_lock);
+ llist_for_each_entry_safe(va, n_va, valist, purge_list)
+ __free_vmap_area(va);
+ spin_unlock(&vmap_area_lock);
+ return true;
}
/*
- * Kick off a purge of the outstanding lazy areas.
+ * Kick off a purge of the outstanding lazy areas, including the fragment
+ * blocks on the per-cpu lists.
*/
static void purge_vmap_area_lazy(void)
{
- unsigned long start = ULONG_MAX, end = 0;
+ purge_fragmented_blocks_allcpus();
+ __purge_vmap_area_lazy(ULONG_MAX, 0);
- __purge_vmap_area_lazy(&start, &end, 1, 0);
}
/*
@@ -706,8 +667,12 @@ static void free_vmap_area_noflush(struct vmap_area *va)
/* After this point, we may free va at any time */
llist_add(&va->purge_list, &vmap_purge_list);
+ /*
+ * Kick off a purge of the outstanding lazy areas. Don't bother to
+ * to purge the per-cpu lists of fragmented blocks.
+ */
if (unlikely(nr_lazy > lazy_max_pages()))
- try_purge_vmap_area_lazy();
+ __purge_vmap_area_lazy(ULONG_MAX, 0);
}
/*
@@ -1094,7 +1059,9 @@ void vm_unmap_aliases(void)
rcu_read_unlock();
}
- __purge_vmap_area_lazy(&start, &end, 1, flush);
+ purge_fragmented_blocks_allcpus();
+ if (!__purge_vmap_area_lazy(start, end) && flush)
+ flush_tlb_kernel_range(start, end);
}
EXPORT_SYMBOL_GPL(vm_unmap_aliases);
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
next prev parent reply other threads:[~2016-10-15 16:46 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-10-15 12:52 [PATCH v3] mm: vmalloc: Replace purge_lock spinlock with atomic refcount Joel Fernandes
2016-10-15 16:46 ` Christoph Hellwig [this message]
2016-10-15 16:54 ` Christoph Hellwig
2016-10-15 22:59 ` Joel Fernandes
2016-10-16 6:10 ` Christoph Hellwig
2016-10-16 22:06 ` Joel Fernandes
2016-10-16 22:48 ` Joel Fernandes
2016-10-17 9:32 ` Christoph Hellwig
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20161015164613.GA26079@infradead.org \
--to=hch@infradead.org \
--cc=akpm@linux-foundation.org \
--cc=chris@chris-wilson.co.uk \
--cc=joaodias@google.com \
--cc=joelaf@google.com \
--cc=jszhang@marvell.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=linux-rt-users@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).