On (25/01/31 15:51), Yosry Ahmed wrote: > > +static void zspage_read_lock(struct zspage *zspage) > > +{ > > + atomic_t *lock = &zspage->lock; > > + int old = atomic_read(lock); > > + > > + do { > > + if (old == ZS_PAGE_WRLOCKED) { > > + cpu_relax(); > > + old = atomic_read(lock); > > + continue; > > + } > > + } while (!atomic_try_cmpxchg(lock, &old, old + 1)); > > +} > > + > > +static void zspage_read_unlock(struct zspage *zspage) > > +{ > > + atomic_dec(&zspage->lock); > > +} > > + > > +static bool zspage_try_write_lock(struct zspage *zspage) > > +{ > > + atomic_t *lock = &zspage->lock; > > + int old = ZS_PAGE_UNLOCKED; > > + > > + preempt_disable(); > > + if (atomic_try_cmpxchg(lock, &old, ZS_PAGE_WRLOCKED)) > > FWIW, I am usually afraid to manually implement locking like this. For > example, queued_spin_trylock() uses atomic_try_cmpxchg_acquire() not > atomic_try_cmpxchg(), and I am not quite sure what could happen without > ACQUIRE semantics here on some architectures. I looked into it a bit, wasn't sure either. Perhaps we can switch to acquire/release semantics, I'm not an expert on this, would highly appreciate help. > We also lose some debugging capabilities as Hilf pointed out in another > patch. So that zspage lock should have not been a lock, I think, it's a ref-counter and it's being used as one map() { page->users++; } unmap() { page->users--; } migrate() { if (!page->users) migrate_page(); } > Just my 2c. Perhaps we can sprinkle some lockdep on it. For instance: --- mm/zsmalloc.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c index 956445f4d554..06b1d8ca9e89 100644 --- a/mm/zsmalloc.c +++ b/mm/zsmalloc.c @@ -308,6 +308,10 @@ struct zspage { struct list_head list; /* fullness list */ struct zs_pool *pool; atomic_t lock; + +#ifdef CONFIG_DEBUG_LOCK_ALLOC + struct lockdep_map lockdep_map; +#endif }; struct mapping_area { @@ -319,6 +323,12 @@ struct mapping_area { static void zspage_lock_init(struct zspage *zspage) { +#ifdef CONFIG_DEBUG_LOCK_ALLOC + static struct lock_class_key key; + + lockdep_init_map(&zspage->lockdep_map, "zsmalloc-page", &key, 0); +#endif + atomic_set(&zspage->lock, ZS_PAGE_UNLOCKED); } @@ -344,11 +354,19 @@ static void zspage_read_lock(struct zspage *zspage) continue; } } while (!atomic_try_cmpxchg(lock, &old, old + 1)); + +#ifdef CONFIG_DEBUG_LOCK_ALLOC + rwsem_acquire_read(&zspage->lockdep_map, 0, 0, _RET_IP_); +#endif } static void zspage_read_unlock(struct zspage *zspage) { atomic_dec(&zspage->lock); + +#ifdef CONFIG_DEBUG_LOCK_ALLOC + rwsem_release(&zspage->lockdep_map, _RET_IP_); +#endif } static bool zspage_try_write_lock(struct zspage *zspage) @@ -357,8 +375,12 @@ static bool zspage_try_write_lock(struct zspage *zspage) int old = ZS_PAGE_UNLOCKED; preempt_disable(); - if (atomic_try_cmpxchg(lock, &old, ZS_PAGE_WRLOCKED)) + if (atomic_try_cmpxchg(lock, &old, ZS_PAGE_WRLOCKED)) { +#ifdef CONFIG_DEBUG_LOCK_ALLOC + rwsem_acquire(&zspage->lockdep_map, 0, 0, _RET_IP_); +#endif return true; + } preempt_enable(); return false; -- 2.48.1.362.g079036d154-goog