| @@ -292,7 +292,12 @@ static inline bool kmem_cache_has_cpu_partial(struct kmem_cache *s) · 291 unmodified lines |
| 292 | /* Poison object */ | 292 | /* Poison object */ |
| 293 | #define __OBJECT_POISON ((slab_flags_t __force)0x80000000U) | 293 | #define __OBJECT_POISON ((slab_flags_t __force)0x80000000U) |
| 294 | /* Use cmpxchg_double */ | 294 | /* Use cmpxchg_double */ |
| | 295 | |
| | 296 | #ifdef system_has_freelist_aba |
| 295 | #define __CMPXCHG_DOUBLE ((slab_flags_t __force)0x40000000U) | 297 | #define __CMPXCHG_DOUBLE ((slab_flags_t __force)0x40000000U) |
| | 298 | #else |
| | 299 | #define __CMPXCHG_DOUBLE ((slab_flags_t __force)0U) |
| | 300 | #endif |
| 296 | | 301 | |
| 297 | /* | 302 | /* |
| 298 | * Tracking user of a slab. | 303 | * Tracking user of a slab. |
| @@ -512,6 +517,40 @@ static __always_inline void slab_unlock(struct slab *slab) · 213 unmodified lines |
| 512 | __bit_spin_unlock(PG_locked, &page->flags); | 517 | __bit_spin_unlock(PG_locked, &page->flags); |
| 513 | } | 518 | } |
| 514 | | 519 | |
| | 520 | static inline bool |
| | 521 | __update_freelist_fast(struct slab *slab, |
| | 522 | void *freelist_old, unsigned long counters_old, |
| | 523 | void *freelist_new, unsigned long counters_new) |
| | 524 | { |
| | 525 | #ifdef system_has_freelist_aba |
| | 526 | freelist_aba_t old = { .freelist = freelist_old, .counter = counters_old }; |
| | 527 | freelist_aba_t new = { .freelist = freelist_new, .counter = counters_new }; |
| | 528 | |
| | 529 | return try_cmpxchg_freelist(&slab->freelist_counter.full, &old.full, new.full); |
| | 530 | #else |
| | 531 | return false; |
| | 532 | #endif |
| | 533 | } |
| | 534 | |
| | 535 | static inline bool |
| | 536 | __update_freelist_slow(struct slab *slab, |
| | 537 | void *freelist_old, unsigned long counters_old, |
| | 538 | void *freelist_new, unsigned long counters_new) |
| | 539 | { |
| | 540 | bool ret = false; |
| | 541 | |
| | 542 | slab_lock(slab); |
| | 543 | if (slab->freelist == freelist_old && |
| | 544 | slab->counters == counters_old) { |
| | 545 | slab->freelist = freelist_new; |
| | 546 | slab->counters = counters_new; |
| | 547 | ret = true; |
| | 548 | } |
| | 549 | slab_unlock(slab); |
| | 550 | |
| | 551 | return ret; |
| | 552 | } |
| | 553 | |
| 515 | /* | 554 | /* |
| 516 | * Interrupts must be disabled (for the fallback code to work right), typically | 555 | * Interrupts must be disabled (for the fallback code to work right), typically |
| 517 | * by an _irqsave() lock variant. On PREEMPT_RT the preempt_disable(), which is | 556 | * by an _irqsave() lock variant. On PREEMPT_RT the preempt_disable(), which is |
| @@ -519,33 +558,25 @@ static __always_inline void slab_unlock(struct slab *slab) · 1 unmodified line |
| 519 | * allocation/ free operation in hardirq context. Therefore nothing can | 558 | * allocation/ free operation in hardirq context. Therefore nothing can |
| 520 | * interrupt the operation. | 559 | * interrupt the operation. |
| 521 | */ | 560 | */ |
| 522 | static inline bool __cmpxchg_double_slab(struct kmem_cache *s, struct slab *slab, | 561 | static inline bool __slab_update_freelist(struct kmem_cache *s, struct slab *slab, |
| 523 | void *freelist_old, unsigned long counters_old, | 562 | void *freelist_old, unsigned long counters_old, |
| 524 | void *freelist_new, unsigned long counters_new, | 563 | void *freelist_new, unsigned long counters_new, |
| 525 | const char *n) | 564 | const char *n) |
| 526 | { | 565 | { |
| | 566 | bool ret; |
| | 567 | |
| 527 | if (USE_LOCKLESS_FAST_PATH()) | 568 | if (USE_LOCKLESS_FAST_PATH()) |
| 528 | lockdep_assert_irqs_disabled(); | 569 | lockdep_assert_irqs_disabled(); |
| 529 | #if defined(CONFIG_HAVE_CMPXCHG_DOUBLE) && \ | 570 | |
| 530 | defined(CONFIG_HAVE_ALIGNED_STRUCT_PAGE) | | |
| 531 | if (s->flags & __CMPXCHG_DOUBLE) { | 571 | if (s->flags & __CMPXCHG_DOUBLE) { |
| 532 | if (cmpxchg_double(&slab->freelist, &slab->counters, | 572 | ret = __update_freelist_fast(slab, freelist_old, counters_old, |
| 533 | freelist_old, counters_old, | 573 | freelist_new, counters_new); |
| 534 | freelist_new, counters_new)) | 574 | } else { |
| 535 | return true; | 575 | ret = __update_freelist_slow(slab, freelist_old, counters_old, |
| 536 | } else | 576 | freelist_new, counters_new); |
| 537 | #endif | | |
| 538 | { | | |
| 539 | slab_lock(slab); | | |
| 540 | if (slab->freelist == freelist_old && | | |
| 541 | slab->counters == counters_old) { | | |
| 542 | slab->freelist = freelist_new; | | |
| 543 | slab->counters = counters_new; | | |
| 544 | slab_unlock(slab); | | |
| 545 | return true; | | |
| 546 | } | | |
| 547 | slab_unlock(slab); | | |
| 548 | } | 577 | } |
| | 578 | if (likely(ret)) |
| | 579 | return true; |
| 549 | | 580 | |
| 550 | cpu_relax(); | 581 | cpu_relax(); |
| 551 | stat(s, CMPXCHG_DOUBLE_FAIL); | 582 | stat(s, CMPXCHG_DOUBLE_FAIL); |
| @@ -557,36 +588,26 @@ static inline bool __cmpxchg_double_slab(struct kmem_cache *s, struct slab *slab · 5 unmodified lines |
| 557 | return false; | 588 | return false; |
| 558 | } | 589 | } |
| 559 | | 590 | |
| 560 | static inline bool cmpxchg_double_slab(struct kmem_cache *s, struct slab *slab, | 591 | static inline bool slab_update_freelist(struct kmem_cache *s, struct slab *slab, |
| 561 | void *freelist_old, unsigned long counters_old, | 592 | void *freelist_old, unsigned long counters_old, |
| 562 | void *freelist_new, unsigned long counters_new, | 593 | void *freelist_new, unsigned long counters_new, |
| 563 | const char *n) | 594 | const char *n) |
| 564 | { | 595 | { |
| 565 | #if defined(CONFIG_HAVE_CMPXCHG_DOUBLE) && \ | 596 | bool ret; |
| 566 | defined(CONFIG_HAVE_ALIGNED_STRUCT_PAGE) | 597 | |
| 567 | if (s->flags & __CMPXCHG_DOUBLE) { | 598 | if (s->flags & __CMPXCHG_DOUBLE) { |
| 568 | if (cmpxchg_double(&slab->freelist, &slab->counters, | 599 | ret = __update_freelist_fast(slab, freelist_old, counters_old, |
| 569 | freelist_old, counters_old, | 600 | freelist_new, counters_new); |
| 570 | freelist_new, counters_new)) | 601 | } else { |
| 571 | return true; | | |
| 572 | } else | | |
| 573 | #endif | | |
| 574 | { | | |
| 575 | unsigned long flags; | 602 | unsigned long flags; |
| 576 | | 603 | |
| 577 | local_irq_save(flags); | 604 | local_irq_save(flags); |
| 578 | slab_lock(slab); | 605 | ret = __update_freelist_slow(slab, freelist_old, counters_old, |
| 579 | if (slab->freelist == freelist_old && | 606 | freelist_new, counters_new); |
| 580 | slab->counters == counters_old) { | | |
| 581 | slab->freelist = freelist_new; | | |
| 582 | slab->counters = counters_new; | | |
| 583 | slab_unlock(slab); | | |
| 584 | local_irq_restore(flags); | | |
| 585 | return true; | | |
| 586 | } | | |
| 587 | slab_unlock(slab); | | |
| 588 | local_irq_restore(flags); | 607 | local_irq_restore(flags); |
| 589 | } | 608 | } |
| | 609 | if (likely(ret)) |
| | 610 | return true; |
| 590 | | 611 | |
| 591 | cpu_relax(); | 612 | cpu_relax(); |
| 592 | stat(s, CMPXCHG_DOUBLE_FAIL); | 613 | stat(s, CMPXCHG_DOUBLE_FAIL); |
| @@ -2228,7 +2249,7 @@ static inline void *acquire_slab(struct kmem_cache *s, · 1635 unmodified lines |
| 2228 | VM_BUG_ON(new.frozen); | 2249 | VM_BUG_ON(new.frozen); |
| 2229 | new.frozen = 1; | 2250 | new.frozen = 1; |
| 2230 | | 2251 | |
| 2231 | if (!__cmpxchg_double_slab(s, slab, | 2252 | if (!__slab_update_freelist(s, slab, |
| 2232 | freelist, counters, | 2253 | freelist, counters, |
| 2233 | new.freelist, new.counters, | 2254 | new.freelist, new.counters, |
| 2234 | "acquire_slab")) | 2255 | "acquire_slab")) |
| @@ -2554,7 +2575,7 @@ redo: · 319 unmodified lines |
| 2554 | } | 2575 | } |
| 2555 | | 2576 | |
| 2556 | | 2577 | |
| 2557 | if (!cmpxchg_double_slab(s, slab, | 2578 | if (!slab_update_freelist(s, slab, |
| 2558 | old.freelist, old.counters, | 2579 | old.freelist, old.counters, |
| 2559 | new.freelist, new.counters, | 2580 | new.freelist, new.counters, |
| 2560 | "unfreezing slab")) { | 2581 | "unfreezing slab")) { |
| @@ -2611,7 +2632,7 @@ static void __unfreeze_partials(struct kmem_cache *s, struct slab *partial_slab) · 50 unmodified lines |
| 2611 | | 2632 | |
| 2612 | new.frozen = 0; | 2633 | new.frozen = 0; |
| 2613 | | 2634 | |
| 2614 | } while (!__cmpxchg_double_slab(s, slab, | 2635 | } while (!__slab_update_freelist(s, slab, |
| 2615 | old.freelist, old.counters, | 2636 | old.freelist, old.counters, |
| 2616 | new.freelist, new.counters, | 2637 | new.freelist, new.counters, |
| 2617 | "unfreezing slab")); | 2638 | "unfreezing slab")); |
| @@ -3008,6 +3029,18 @@ static inline bool pfmemalloc_match(struct slab *slab, gfp_t gfpflags) · 390 unmodified lines |
| 3008 | } | 3029 | } |
| 3009 | | 3030 | |
| 3010 | #ifndef CONFIG_SLUB_TINY | 3031 | #ifndef CONFIG_SLUB_TINY |
| | 3032 | static inline bool |
| | 3033 | __update_cpu_freelist_fast(struct kmem_cache *s, |
| | 3034 | void *freelist_old, void *freelist_new, |
| | 3035 | unsigned long tid) |
| | 3036 | { |
| | 3037 | freelist_aba_t old = { .freelist = freelist_old, .counter = tid }; |
| | 3038 | freelist_aba_t new = { .freelist = freelist_new, .counter = next_tid(tid) }; |
| | 3039 | |
| | 3040 | return this_cpu_try_cmpxchg_freelist(s->cpu_slab->freelist_tid.full, |
| | 3041 | &old.full, new.full); |
| | 3042 | } |
| | 3043 | |
| 3011 | /* | 3044 | /* |
| 3012 | * Check the slab->freelist and either transfer the freelist to the | 3045 | * Check the slab->freelist and either transfer the freelist to the |
| 3013 | * per cpu freelist or deactivate the slab. | 3046 | * per cpu freelist or deactivate the slab. |
| @@ -3034,7 +3067,7 @@ static inline void *get_freelist(struct kmem_cache *s, struct slab *slab) · 20 unmodified lines |
| 3034 | new.inuse = slab->objects; | 3067 | new.inuse = slab->objects; |
| 3035 | new.frozen = freelist != NULL; | 3068 | new.frozen = freelist != NULL; |
| 3036 | | 3069 | |
| 3037 | } while (!__cmpxchg_double_slab(s, slab, | 3070 | } while (!__slab_update_freelist(s, slab, |
| 3038 | freelist, counters, | 3071 | freelist, counters, |
| 3039 | NULL, new.counters, | 3072 | NULL, new.counters, |
| 3040 | "get_freelist")); | 3073 | "get_freelist")); |
| @@ -3359,11 +3392,7 @@ redo: · 318 unmodified lines |
| 3359 | * against code executing on this cpu *not* from access by | 3392 | * against code executing on this cpu *not* from access by |
| 3360 | * other cpus. | 3393 | * other cpus. |
| 3361 | */ | 3394 | */ |
| 3362 | if (unlikely(!this_cpu_cmpxchg_double( | 3395 | if (unlikely(!__update_cpu_freelist_fast(s, object, next_object, tid))) { |
| 3363 | s->cpu_slab->freelist, s->cpu_slab->tid, | | |
| 3364 | object, tid, | | |
| 3365 | next_object, next_tid(tid)))) { | | |
| 3366 | | | |
| 3367 | note_cmpxchg_failure("slab_alloc", s, tid); | 3396 | note_cmpxchg_failure("slab_alloc", s, tid); |
| 3368 | goto redo; | 3397 | goto redo; |
| 3369 | } | 3398 | } |
| @@ -3631,7 +3660,7 @@ static void __slab_free(struct kmem_cache *s, struct slab *slab, · 261 unmodified lines |
| 3631 | } | 3660 | } |
| 3632 | } | 3661 | } |
| 3633 | | 3662 | |
| 3634 | } while (!cmpxchg_double_slab(s, slab, | 3663 | } while (!slab_update_freelist(s, slab, |
| 3635 | prior, counters, | 3664 | prior, counters, |
| 3636 | head, new.counters, | 3665 | head, new.counters, |
| 3637 | "__slab_free")); | 3666 | "__slab_free")); |
| @@ -3736,11 +3765,7 @@ redo: · 98 unmodified lines |
| 3736 | | 3765 | |
| 3737 | set_freepointer(s, tail_obj, freelist); | 3766 | set_freepointer(s, tail_obj, freelist); |
| 3738 | | 3767 | |
| 3739 | if (unlikely(!this_cpu_cmpxchg_double( | 3768 | if (unlikely(!__update_cpu_freelist_fast(s, freelist, head, tid))) { |
| 3740 | s->cpu_slab->freelist, s->cpu_slab->tid, | | |
| 3741 | freelist, tid, | | |
| 3742 | head, next_tid(tid)))) { | | |
| 3743 | | | |
| 3744 | note_cmpxchg_failure("slab_free", s, tid); | 3769 | note_cmpxchg_failure("slab_free", s, tid); |
| 3745 | goto redo; | 3770 | goto redo; |
| 3746 | } | 3771 | } |
| @@ -4505,11 +4530,11 @@ static int kmem_cache_open(struct kmem_cache *s, slab_flags_t flags) · 758 unmodified lines |
| 4505 | } | 4530 | } |
| 4506 | } | 4531 | } |
| 4507 | | 4532 | |
| 4508 | #if defined(CONFIG_HAVE_CMPXCHG_DOUBLE) && \ | 4533 | #ifdef system_has_freelist_aba |
| 4509 | defined(CONFIG_HAVE_ALIGNED_STRUCT_PAGE) | 4534 | if (system_has_freelist_aba() && !(s->flags & SLAB_NO_CMPXCHG)) { |
| 4510 | if (system_has_cmpxchg_double() && (s->flags & SLAB_NO_CMPXCHG) == 0) | | |
| 4511 | /* Enable fast mode */ | 4535 | /* Enable fast mode */ |
| 4512 | s->flags |= __CMPXCHG_DOUBLE; | 4536 | s->flags |= __CMPXCHG_DOUBLE; |
| | 4537 | } |
| 4513 | #endif | 4538 | #endif |
| 4514 | | 4539 | |
| 4515 | /* | 4540 | /* |