|
@@ -354,6 +354,42 @@ static __always_inline void slab_unlock(struct page *page)
|
|
|
__bit_spin_unlock(PG_locked, &page->flags);
|
|
|
}
|
|
|
|
|
|
+/* Interrupts must be disabled (for the fallback code to work right) */
|
|
|
+static inline bool __cmpxchg_double_slab(struct kmem_cache *s, struct page *page,
|
|
|
+ void *freelist_old, unsigned long counters_old,
|
|
|
+ void *freelist_new, unsigned long counters_new,
|
|
|
+ const char *n)
|
|
|
+{
|
|
|
+ VM_BUG_ON(!irqs_disabled());
|
|
|
+#ifdef CONFIG_CMPXCHG_DOUBLE
|
|
|
+ if (s->flags & __CMPXCHG_DOUBLE) {
|
|
|
+ if (cmpxchg_double(&page->freelist,
|
|
|
+ freelist_old, counters_old,
|
|
|
+ freelist_new, counters_new))
|
|
|
+ return 1;
|
|
|
+ } else
|
|
|
+#endif
|
|
|
+ {
|
|
|
+ slab_lock(page);
|
|
|
+ if (page->freelist == freelist_old && page->counters == counters_old) {
|
|
|
+ page->freelist = freelist_new;
|
|
|
+ page->counters = counters_new;
|
|
|
+ slab_unlock(page);
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ slab_unlock(page);
|
|
|
+ }
|
|
|
+
|
|
|
+ cpu_relax();
|
|
|
+ stat(s, CMPXCHG_DOUBLE_FAIL);
|
|
|
+
|
|
|
+#ifdef SLUB_DEBUG_CMPXCHG
|
|
|
+ printk(KERN_INFO "%s %s: cmpxchg double redo ", n, s->name);
|
|
|
+#endif
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static inline bool cmpxchg_double_slab(struct kmem_cache *s, struct page *page,
|
|
|
void *freelist_old, unsigned long counters_old,
|
|
|
void *freelist_new, unsigned long counters_new,
|
|
@@ -368,14 +404,19 @@ static inline bool cmpxchg_double_slab(struct kmem_cache *s, struct page *page,
|
|
|
} else
|
|
|
#endif
|
|
|
{
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
+ local_irq_save(flags);
|
|
|
slab_lock(page);
|
|
|
if (page->freelist == freelist_old && page->counters == counters_old) {
|
|
|
page->freelist = freelist_new;
|
|
|
page->counters = counters_new;
|
|
|
slab_unlock(page);
|
|
|
+ local_irq_restore(flags);
|
|
|
return 1;
|
|
|
}
|
|
|
slab_unlock(page);
|
|
|
+ local_irq_restore(flags);
|
|
|
}
|
|
|
|
|
|
cpu_relax();
|
|
@@ -1471,7 +1512,7 @@ static inline int acquire_slab(struct kmem_cache *s,
|
|
|
VM_BUG_ON(new.frozen);
|
|
|
new.frozen = 1;
|
|
|
|
|
|
- } while (!cmpxchg_double_slab(s, page,
|
|
|
+ } while (!__cmpxchg_double_slab(s, page,
|
|
|
freelist, counters,
|
|
|
NULL, new.counters,
|
|
|
"lock and freeze"));
|
|
@@ -1709,7 +1750,7 @@ static void deactivate_slab(struct kmem_cache *s, struct kmem_cache_cpu *c)
|
|
|
new.inuse--;
|
|
|
VM_BUG_ON(!new.frozen);
|
|
|
|
|
|
- } while (!cmpxchg_double_slab(s, page,
|
|
|
+ } while (!__cmpxchg_double_slab(s, page,
|
|
|
prior, counters,
|
|
|
freelist, new.counters,
|
|
|
"drain percpu freelist"));
|
|
@@ -1798,7 +1839,7 @@ redo:
|
|
|
}
|
|
|
|
|
|
l = m;
|
|
|
- if (!cmpxchg_double_slab(s, page,
|
|
|
+ if (!__cmpxchg_double_slab(s, page,
|
|
|
old.freelist, old.counters,
|
|
|
new.freelist, new.counters,
|
|
|
"unfreezing slab"))
|
|
@@ -1992,7 +2033,7 @@ static void *__slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
|
|
|
new.inuse = page->objects;
|
|
|
new.frozen = object != NULL;
|
|
|
|
|
|
- } while (!cmpxchg_double_slab(s, page,
|
|
|
+ } while (!__cmpxchg_double_slab(s, page,
|
|
|
object, counters,
|
|
|
NULL, new.counters,
|
|
|
"__slab_alloc"));
|