|
@@ -1560,7 +1560,7 @@ static inline void remove_partial(struct kmem_cache_node *n,
|
|
|
*/
|
|
|
static inline void *acquire_slab(struct kmem_cache *s,
|
|
|
struct kmem_cache_node *n, struct page *page,
|
|
|
- struct kmem_cache_cpu *c)
|
|
|
+ int mode)
|
|
|
{
|
|
|
void *freelist;
|
|
|
unsigned long counters;
|
|
@@ -1575,7 +1575,8 @@ static inline void *acquire_slab(struct kmem_cache *s,
|
|
|
freelist = page->freelist;
|
|
|
counters = page->counters;
|
|
|
new.counters = counters;
|
|
|
- new.inuse = page->objects;
|
|
|
+ if (mode)
|
|
|
+ new.inuse = page->objects;
|
|
|
|
|
|
VM_BUG_ON(new.frozen);
|
|
|
new.frozen = 1;
|
|
@@ -1586,34 +1587,20 @@ static inline void *acquire_slab(struct kmem_cache *s,
|
|
|
"lock and freeze"));
|
|
|
|
|
|
remove_partial(n, page);
|
|
|
-
|
|
|
- if (freelist) {
|
|
|
- /* Populate the per cpu freelist */
|
|
|
- c->page = page;
|
|
|
- c->node = page_to_nid(page);
|
|
|
- stat(s, ALLOC_FROM_PARTIAL);
|
|
|
-
|
|
|
- return freelist;
|
|
|
- } else {
|
|
|
- /*
|
|
|
- * Slab page came from the wrong list. No object to allocate
|
|
|
- * from. Put it onto the correct list and continue partial
|
|
|
- * scan.
|
|
|
- */
|
|
|
- printk(KERN_ERR "SLUB: %s : Page without available objects on"
|
|
|
- " partial list\n", s->name);
|
|
|
- return NULL;
|
|
|
- }
|
|
|
+ return freelist;
|
|
|
}
|
|
|
|
|
|
+static int put_cpu_partial(struct kmem_cache *s, struct page *page, int drain);
|
|
|
+
|
|
|
/*
|
|
|
* Try to allocate a partial slab from a specific node.
|
|
|
*/
|
|
|
static void *get_partial_node(struct kmem_cache *s,
|
|
|
struct kmem_cache_node *n, struct kmem_cache_cpu *c)
|
|
|
{
|
|
|
- struct page *page;
|
|
|
- void *object;
|
|
|
+ struct page *page, *page2;
|
|
|
+ void *object = NULL;
|
|
|
+ int count = 0;
|
|
|
|
|
|
/*
|
|
|
* Racy check. If we mistakenly see no partial slabs then we
|
|
@@ -1625,13 +1612,28 @@ static void *get_partial_node(struct kmem_cache *s,
|
|
|
return NULL;
|
|
|
|
|
|
spin_lock(&n->list_lock);
|
|
|
- list_for_each_entry(page, &n->partial, lru) {
|
|
|
- object = acquire_slab(s, n, page, c);
|
|
|
- if (object)
|
|
|
- goto out;
|
|
|
+ list_for_each_entry_safe(page, page2, &n->partial, lru) {
|
|
|
+ void *t = acquire_slab(s, n, page, count == 0);
|
|
|
+ int available;
|
|
|
+
|
|
|
+ if (!t)
|
|
|
+ break;
|
|
|
+
|
|
|
+ if (!count) {
|
|
|
+ c->page = page;
|
|
|
+ c->node = page_to_nid(page);
|
|
|
+ stat(s, ALLOC_FROM_PARTIAL);
|
|
|
+ count++;
|
|
|
+ object = t;
|
|
|
+ available = page->objects - page->inuse;
|
|
|
+ } else {
|
|
|
+ page->freelist = t;
|
|
|
+ available = put_cpu_partial(s, page, 0);
|
|
|
+ }
|
|
|
+ if (kmem_cache_debug(s) || available > s->cpu_partial / 2)
|
|
|
+ break;
|
|
|
+
|
|
|
}
|
|
|
- object = NULL;
|
|
|
-out:
|
|
|
spin_unlock(&n->list_lock);
|
|
|
return object;
|
|
|
}
|
|
@@ -1926,6 +1928,123 @@ redo:
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/* Unfreeze all the cpu partial slabs */
|
|
|
+static void unfreeze_partials(struct kmem_cache *s)
|
|
|
+{
|
|
|
+ struct kmem_cache_node *n = NULL;
|
|
|
+ struct kmem_cache_cpu *c = this_cpu_ptr(s->cpu_slab);
|
|
|
+ struct page *page;
|
|
|
+
|
|
|
+ while ((page = c->partial)) {
|
|
|
+ enum slab_modes { M_PARTIAL, M_FREE };
|
|
|
+ enum slab_modes l, m;
|
|
|
+ struct page new;
|
|
|
+ struct page old;
|
|
|
+
|
|
|
+ c->partial = page->next;
|
|
|
+ l = M_FREE;
|
|
|
+
|
|
|
+ do {
|
|
|
+
|
|
|
+ old.freelist = page->freelist;
|
|
|
+ old.counters = page->counters;
|
|
|
+ VM_BUG_ON(!old.frozen);
|
|
|
+
|
|
|
+ new.counters = old.counters;
|
|
|
+ new.freelist = old.freelist;
|
|
|
+
|
|
|
+ new.frozen = 0;
|
|
|
+
|
|
|
+ if (!new.inuse && (!n || n->nr_partial < s->min_partial))
|
|
|
+ m = M_FREE;
|
|
|
+ else {
|
|
|
+ struct kmem_cache_node *n2 = get_node(s,
|
|
|
+ page_to_nid(page));
|
|
|
+
|
|
|
+ m = M_PARTIAL;
|
|
|
+ if (n != n2) {
|
|
|
+ if (n)
|
|
|
+ spin_unlock(&n->list_lock);
|
|
|
+
|
|
|
+ n = n2;
|
|
|
+ spin_lock(&n->list_lock);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (l != m) {
|
|
|
+ if (l == M_PARTIAL)
|
|
|
+ remove_partial(n, page);
|
|
|
+ else
|
|
|
+ add_partial(n, page, 1);
|
|
|
+
|
|
|
+ l = m;
|
|
|
+ }
|
|
|
+
|
|
|
+ } while (!cmpxchg_double_slab(s, page,
|
|
|
+ old.freelist, old.counters,
|
|
|
+ new.freelist, new.counters,
|
|
|
+ "unfreezing slab"));
|
|
|
+
|
|
|
+ if (m == M_FREE) {
|
|
|
+ stat(s, DEACTIVATE_EMPTY);
|
|
|
+ discard_slab(s, page);
|
|
|
+ stat(s, FREE_SLAB);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (n)
|
|
|
+ spin_unlock(&n->list_lock);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Put a page that was just frozen (in __slab_free) into a partial page
|
|
|
+ * slot if available. This is done without interrupts disabled and without
|
|
|
+ * preemption disabled. The cmpxchg is racy and may put the partial page
|
|
|
+ * onto a random cpus partial slot.
|
|
|
+ *
|
|
|
+ * If we did not find a slot then simply move all the partials to the
|
|
|
+ * per node partial list.
|
|
|
+ */
|
|
|
+int put_cpu_partial(struct kmem_cache *s, struct page *page, int drain)
|
|
|
+{
|
|
|
+ struct page *oldpage;
|
|
|
+ int pages;
|
|
|
+ int pobjects;
|
|
|
+
|
|
|
+ do {
|
|
|
+ pages = 0;
|
|
|
+ pobjects = 0;
|
|
|
+ oldpage = this_cpu_read(s->cpu_slab->partial);
|
|
|
+
|
|
|
+ if (oldpage) {
|
|
|
+ pobjects = oldpage->pobjects;
|
|
|
+ pages = oldpage->pages;
|
|
|
+ if (drain && pobjects > s->cpu_partial) {
|
|
|
+ unsigned long flags;
|
|
|
+ /*
|
|
|
+ * partial array is full. Move the existing
|
|
|
+ * set to the per node partial list.
|
|
|
+ */
|
|
|
+ local_irq_save(flags);
|
|
|
+ unfreeze_partials(s);
|
|
|
+ local_irq_restore(flags);
|
|
|
+ pobjects = 0;
|
|
|
+ pages = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ pages++;
|
|
|
+ pobjects += page->objects - page->inuse;
|
|
|
+
|
|
|
+ page->pages = pages;
|
|
|
+ page->pobjects = pobjects;
|
|
|
+ page->next = oldpage;
|
|
|
+
|
|
|
+ } while (this_cpu_cmpxchg(s->cpu_slab->partial, oldpage, page) != oldpage);
|
|
|
+ stat(s, CPU_PARTIAL_FREE);
|
|
|
+ return pobjects;
|
|
|
+}
|
|
|
+
|
|
|
static inline void flush_slab(struct kmem_cache *s, struct kmem_cache_cpu *c)
|
|
|
{
|
|
|
stat(s, CPUSLAB_FLUSH);
|
|
@@ -1941,8 +2060,12 @@ static inline void __flush_cpu_slab(struct kmem_cache *s, int cpu)
|
|
|
{
|
|
|
struct kmem_cache_cpu *c = per_cpu_ptr(s->cpu_slab, cpu);
|
|
|
|
|
|
- if (likely(c && c->page))
|
|
|
- flush_slab(s, c);
|
|
|
+ if (likely(c)) {
|
|
|
+ if (c->page)
|
|
|
+ flush_slab(s, c);
|
|
|
+
|
|
|
+ unfreeze_partials(s);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
static void flush_cpu_slab(void *d)
|
|
@@ -2066,8 +2189,6 @@ static inline void *new_slab_objects(struct kmem_cache *s, gfp_t flags,
|
|
|
* Slow path. The lockless freelist is empty or we need to perform
|
|
|
* debugging duties.
|
|
|
*
|
|
|
- * Interrupts are disabled.
|
|
|
- *
|
|
|
* Processing is still very fast if new objects have been freed to the
|
|
|
* regular freelist. In that case we simply take over the regular freelist
|
|
|
* as the lockless freelist and zap the regular freelist.
|
|
@@ -2100,7 +2221,7 @@ static void *__slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
|
|
|
|
|
|
if (!c->page)
|
|
|
goto new_slab;
|
|
|
-
|
|
|
+redo:
|
|
|
if (unlikely(!node_match(c, node))) {
|
|
|
stat(s, ALLOC_NODE_MISMATCH);
|
|
|
deactivate_slab(s, c);
|
|
@@ -2133,7 +2254,7 @@ static void *__slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
|
|
|
NULL, new.counters,
|
|
|
"__slab_alloc"));
|
|
|
|
|
|
- if (unlikely(!object)) {
|
|
|
+ if (!object) {
|
|
|
c->page = NULL;
|
|
|
stat(s, DEACTIVATE_BYPASS);
|
|
|
goto new_slab;
|
|
@@ -2148,6 +2269,17 @@ load_freelist:
|
|
|
return object;
|
|
|
|
|
|
new_slab:
|
|
|
+
|
|
|
+ if (c->partial) {
|
|
|
+ c->page = c->partial;
|
|
|
+ c->partial = c->page->next;
|
|
|
+ c->node = page_to_nid(c->page);
|
|
|
+ stat(s, CPU_PARTIAL_ALLOC);
|
|
|
+ c->freelist = NULL;
|
|
|
+ goto redo;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Then do expensive stuff like retrieving pages from the partial lists */
|
|
|
object = get_partial(s, gfpflags, node, c);
|
|
|
|
|
|
if (unlikely(!object)) {
|
|
@@ -2341,16 +2473,29 @@ static void __slab_free(struct kmem_cache *s, struct page *page,
|
|
|
was_frozen = new.frozen;
|
|
|
new.inuse--;
|
|
|
if ((!new.inuse || !prior) && !was_frozen && !n) {
|
|
|
- n = get_node(s, page_to_nid(page));
|
|
|
- /*
|
|
|
- * Speculatively acquire the list_lock.
|
|
|
- * If the cmpxchg does not succeed then we may
|
|
|
- * drop the list_lock without any processing.
|
|
|
- *
|
|
|
- * Otherwise the list_lock will synchronize with
|
|
|
- * other processors updating the list of slabs.
|
|
|
- */
|
|
|
- spin_lock_irqsave(&n->list_lock, flags);
|
|
|
+
|
|
|
+ if (!kmem_cache_debug(s) && !prior)
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Slab was on no list before and will be partially empty
|
|
|
+ * We can defer the list move and instead freeze it.
|
|
|
+ */
|
|
|
+ new.frozen = 1;
|
|
|
+
|
|
|
+ else { /* Needs to be taken off a list */
|
|
|
+
|
|
|
+ n = get_node(s, page_to_nid(page));
|
|
|
+ /*
|
|
|
+ * Speculatively acquire the list_lock.
|
|
|
+ * If the cmpxchg does not succeed then we may
|
|
|
+ * drop the list_lock without any processing.
|
|
|
+ *
|
|
|
+ * Otherwise the list_lock will synchronize with
|
|
|
+ * other processors updating the list of slabs.
|
|
|
+ */
|
|
|
+ spin_lock_irqsave(&n->list_lock, flags);
|
|
|
+
|
|
|
+ }
|
|
|
}
|
|
|
inuse = new.inuse;
|
|
|
|
|
@@ -2360,7 +2505,15 @@ static void __slab_free(struct kmem_cache *s, struct page *page,
|
|
|
"__slab_free"));
|
|
|
|
|
|
if (likely(!n)) {
|
|
|
- /*
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If we just froze the page then put it onto the
|
|
|
+ * per cpu partial list.
|
|
|
+ */
|
|
|
+ if (new.frozen && !was_frozen)
|
|
|
+ put_cpu_partial(s, page, 1);
|
|
|
+
|
|
|
+ /*
|
|
|
* The list lock was not taken therefore no list
|
|
|
* activity can be necessary.
|
|
|
*/
|
|
@@ -2429,7 +2582,6 @@ static __always_inline void slab_free(struct kmem_cache *s,
|
|
|
slab_free_hook(s, x);
|
|
|
|
|
|
redo:
|
|
|
-
|
|
|
/*
|
|
|
* Determine the currently cpus per cpu slab.
|
|
|
* The cpu may change afterward. However that does not matter since
|
|
@@ -2919,7 +3071,34 @@ static int kmem_cache_open(struct kmem_cache *s,
|
|
|
* The larger the object size is, the more pages we want on the partial
|
|
|
* list to avoid pounding the page allocator excessively.
|
|
|
*/
|
|
|
- set_min_partial(s, ilog2(s->size));
|
|
|
+ set_min_partial(s, ilog2(s->size) / 2);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * cpu_partial determined the maximum number of objects kept in the
|
|
|
+ * per cpu partial lists of a processor.
|
|
|
+ *
|
|
|
+ * Per cpu partial lists mainly contain slabs that just have one
|
|
|
+ * object freed. If they are used for allocation then they can be
|
|
|
+ * filled up again with minimal effort. The slab will never hit the
|
|
|
+ * per node partial lists and therefore no locking will be required.
|
|
|
+ *
|
|
|
+ * This setting also determines
|
|
|
+ *
|
|
|
+ * A) The number of objects from per cpu partial slabs dumped to the
|
|
|
+ * per node list when we reach the limit.
|
|
|
+ * B) The number of objects in partial partial slabs to extract from the
|
|
|
+ * per node list when we run out of per cpu objects. We only fetch 50%
|
|
|
+ * to keep some capacity around for frees.
|
|
|
+ */
|
|
|
+ if (s->size >= PAGE_SIZE)
|
|
|
+ s->cpu_partial = 2;
|
|
|
+ else if (s->size >= 1024)
|
|
|
+ s->cpu_partial = 6;
|
|
|
+ else if (s->size >= 256)
|
|
|
+ s->cpu_partial = 13;
|
|
|
+ else
|
|
|
+ s->cpu_partial = 30;
|
|
|
+
|
|
|
s->refcount = 1;
|
|
|
#ifdef CONFIG_NUMA
|
|
|
s->remote_node_defrag_ratio = 1000;
|
|
@@ -4327,6 +4506,7 @@ static ssize_t show_slab_objects(struct kmem_cache *s,
|
|
|
|
|
|
for_each_possible_cpu(cpu) {
|
|
|
struct kmem_cache_cpu *c = per_cpu_ptr(s->cpu_slab, cpu);
|
|
|
+ struct page *page;
|
|
|
|
|
|
if (!c || c->node < 0)
|
|
|
continue;
|
|
@@ -4342,6 +4522,13 @@ static ssize_t show_slab_objects(struct kmem_cache *s,
|
|
|
total += x;
|
|
|
nodes[c->node] += x;
|
|
|
}
|
|
|
+ page = c->partial;
|
|
|
+
|
|
|
+ if (page) {
|
|
|
+ x = page->pobjects;
|
|
|
+ total += x;
|
|
|
+ nodes[c->node] += x;
|
|
|
+ }
|
|
|
per_cpu[c->node]++;
|
|
|
}
|
|
|
}
|
|
@@ -4493,6 +4680,27 @@ static ssize_t min_partial_store(struct kmem_cache *s, const char *buf,
|
|
|
}
|
|
|
SLAB_ATTR(min_partial);
|
|
|
|
|
|
+static ssize_t cpu_partial_show(struct kmem_cache *s, char *buf)
|
|
|
+{
|
|
|
+ return sprintf(buf, "%u\n", s->cpu_partial);
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t cpu_partial_store(struct kmem_cache *s, const char *buf,
|
|
|
+ size_t length)
|
|
|
+{
|
|
|
+ unsigned long objects;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ err = strict_strtoul(buf, 10, &objects);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ s->cpu_partial = objects;
|
|
|
+ flush_all(s);
|
|
|
+ return length;
|
|
|
+}
|
|
|
+SLAB_ATTR(cpu_partial);
|
|
|
+
|
|
|
static ssize_t ctor_show(struct kmem_cache *s, char *buf)
|
|
|
{
|
|
|
if (!s->ctor)
|
|
@@ -4531,6 +4739,37 @@ static ssize_t objects_partial_show(struct kmem_cache *s, char *buf)
|
|
|
}
|
|
|
SLAB_ATTR_RO(objects_partial);
|
|
|
|
|
|
+static ssize_t slabs_cpu_partial_show(struct kmem_cache *s, char *buf)
|
|
|
+{
|
|
|
+ int objects = 0;
|
|
|
+ int pages = 0;
|
|
|
+ int cpu;
|
|
|
+ int len;
|
|
|
+
|
|
|
+ for_each_online_cpu(cpu) {
|
|
|
+ struct page *page = per_cpu_ptr(s->cpu_slab, cpu)->partial;
|
|
|
+
|
|
|
+ if (page) {
|
|
|
+ pages += page->pages;
|
|
|
+ objects += page->pobjects;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ len = sprintf(buf, "%d(%d)", objects, pages);
|
|
|
+
|
|
|
+#ifdef CONFIG_SMP
|
|
|
+ for_each_online_cpu(cpu) {
|
|
|
+ struct page *page = per_cpu_ptr(s->cpu_slab, cpu) ->partial;
|
|
|
+
|
|
|
+ if (page && len < PAGE_SIZE - 20)
|
|
|
+ len += sprintf(buf + len, " C%d=%d(%d)", cpu,
|
|
|
+ page->pobjects, page->pages);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ return len + sprintf(buf + len, "\n");
|
|
|
+}
|
|
|
+SLAB_ATTR_RO(slabs_cpu_partial);
|
|
|
+
|
|
|
static ssize_t reclaim_account_show(struct kmem_cache *s, char *buf)
|
|
|
{
|
|
|
return sprintf(buf, "%d\n", !!(s->flags & SLAB_RECLAIM_ACCOUNT));
|
|
@@ -4853,6 +5092,8 @@ STAT_ATTR(DEACTIVATE_BYPASS, deactivate_bypass);
|
|
|
STAT_ATTR(ORDER_FALLBACK, order_fallback);
|
|
|
STAT_ATTR(CMPXCHG_DOUBLE_CPU_FAIL, cmpxchg_double_cpu_fail);
|
|
|
STAT_ATTR(CMPXCHG_DOUBLE_FAIL, cmpxchg_double_fail);
|
|
|
+STAT_ATTR(CPU_PARTIAL_ALLOC, cpu_partial_alloc);
|
|
|
+STAT_ATTR(CPU_PARTIAL_FREE, cpu_partial_free);
|
|
|
#endif
|
|
|
|
|
|
static struct attribute *slab_attrs[] = {
|
|
@@ -4861,6 +5102,7 @@ static struct attribute *slab_attrs[] = {
|
|
|
&objs_per_slab_attr.attr,
|
|
|
&order_attr.attr,
|
|
|
&min_partial_attr.attr,
|
|
|
+ &cpu_partial_attr.attr,
|
|
|
&objects_attr.attr,
|
|
|
&objects_partial_attr.attr,
|
|
|
&partial_attr.attr,
|
|
@@ -4873,6 +5115,7 @@ static struct attribute *slab_attrs[] = {
|
|
|
&destroy_by_rcu_attr.attr,
|
|
|
&shrink_attr.attr,
|
|
|
&reserved_attr.attr,
|
|
|
+ &slabs_cpu_partial_attr.attr,
|
|
|
#ifdef CONFIG_SLUB_DEBUG
|
|
|
&total_objects_attr.attr,
|
|
|
&slabs_attr.attr,
|
|
@@ -4914,6 +5157,8 @@ static struct attribute *slab_attrs[] = {
|
|
|
&order_fallback_attr.attr,
|
|
|
&cmpxchg_double_fail_attr.attr,
|
|
|
&cmpxchg_double_cpu_fail_attr.attr,
|
|
|
+ &cpu_partial_alloc_attr.attr,
|
|
|
+ &cpu_partial_free_attr.attr,
|
|
|
#endif
|
|
|
#ifdef CONFIG_FAILSLAB
|
|
|
&failslab_attr.attr,
|