On Sat, 2020-11-28 at 15:27 +0100, Oleksandr Natalenko wrote: > > > > Shouldn't the list manipulation be protected with > > > local_lock+this_cpu_ptr instead of get_cpu_ptr+spin_lock? > > Totally untested: Hrm, the thing doesn't seem to care deeply about preemption being disabled, so adding another lock may be overkill. It looks like you could get the job done via migrate_disable()+this_cpu_ptr(). In the case of the list in __z3fold_alloc(), after the unlocked peek, it double checks under the existing lock. There's not a whole lot of difference between another cpu a few lines down in the same function diddling the list and a preemption doing the same, so why bother? Ditto add_to_unbuddied(). Flow decisions are being made based on zhdr- >first/middle/last_chunks state prior to preemption being disabled as the thing sits, so presumably their stability is not dependent thereon, while the list is protected by the already existing lock, making the preempt_disable() look more incidental than intentional. Equally untested :) --- mm/z3fold.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) --- a/mm/z3fold.c +++ b/mm/z3fold.c @@ -642,14 +642,16 @@ static inline void add_to_unbuddied(stru { if (zhdr->first_chunks == 0 || zhdr->last_chunks == 0 || zhdr->middle_chunks == 0) { - struct list_head *unbuddied = get_cpu_ptr(pool->unbuddied); - + struct list_head *unbuddied; int freechunks = num_free_chunks(zhdr); + + migrate_disable(); + unbuddied = this_cpu_ptr(pool->unbuddied); spin_lock(&pool->lock); list_add(&zhdr->buddy, &unbuddied[freechunks]); spin_unlock(&pool->lock); zhdr->cpu = smp_processor_id(); - put_cpu_ptr(pool->unbuddied); + migrate_enable(); } } @@ -886,8 +888,9 @@ static inline struct z3fold_header *__z3 int chunks = size_to_chunks(size), i; lookup: + migrate_disable(); /* First, try to find an unbuddied z3fold page. */ - unbuddied = get_cpu_ptr(pool->unbuddied); + unbuddied = this_cpu_ptr(pool->unbuddied); for_each_unbuddied_list(i, chunks) { struct list_head *l = &unbuddied[i]; @@ -905,7 +908,7 @@ static inline struct z3fold_header *__z3 !z3fold_page_trylock(zhdr)) { spin_unlock(&pool->lock); zhdr = NULL; - put_cpu_ptr(pool->unbuddied); + migrate_enable(); if (can_sleep) cond_resched(); goto lookup; @@ -919,7 +922,7 @@ static inline struct z3fold_header *__z3 test_bit(PAGE_CLAIMED, &page->private)) { z3fold_page_unlock(zhdr); zhdr = NULL; - put_cpu_ptr(pool->unbuddied); + migrate_enable(); if (can_sleep) cond_resched(); goto lookup; @@ -934,7 +937,7 @@ static inline struct z3fold_header *__z3 kref_get(&zhdr->refcount); break; } - put_cpu_ptr(pool->unbuddied); + migrate_enable(); if (!zhdr) { int cpu;