On Mon, Jul 29, 2024 at 07:25:14PM +0800, alexs@xxxxxxxxxx wrote: > From: Alex Shi <alexs@xxxxxxxxxx> > > To use zpdesc in trylock_zspage/lock_zspage funcs, we add couple of helpers: > zpdesc_lock/zpdesc_unlock/zpdesc_trylock/zpdesc_wait_locked and > zpdesc_get/zpdesc_put for this purpose. You should always include the "()" following function names. It just makes everything more readable. > Here we use the folio series func in guts for 2 reasons, one zswap.zpool > only get single page, and use folio could save some compound_head checking; > two, folio_put could bypass devmap checking that we don't need. > > Originally-by: Hyeonggon Yoo <42.hyeyoo@xxxxxxxxx> > Signed-off-by: Alex Shi <alexs@xxxxxxxxxx> > --- > mm/zpdesc.h | 30 ++++++++++++++++++++++++ > mm/zsmalloc.c | 64 ++++++++++++++++++++++++++++++++++----------------- > 2 files changed, 73 insertions(+), 21 deletions(-) > > diff --git a/mm/zpdesc.h b/mm/zpdesc.h > index 2dbef231f616..3b04197cec9d 100644 > --- a/mm/zpdesc.h > +++ b/mm/zpdesc.h > @@ -63,4 +63,34 @@ static_assert(sizeof(struct zpdesc) <= sizeof(struct page)); > const struct page *: (const struct zpdesc *)(p), \ > struct page *: (struct zpdesc *)(p))) > > +static inline void zpdesc_lock(struct zpdesc *zpdesc) > +{ > + folio_lock(zpdesc_folio(zpdesc)); > +} > + > +static inline bool zpdesc_trylock(struct zpdesc *zpdesc) > +{ > + return folio_trylock(zpdesc_folio(zpdesc)); > +} > + > +static inline void zpdesc_unlock(struct zpdesc *zpdesc) > +{ > + folio_unlock(zpdesc_folio(zpdesc)); > +} > + > +static inline void zpdesc_wait_locked(struct zpdesc *zpdesc) > +{ > + folio_wait_locked(zpdesc_folio(zpdesc)); > +} The more I look at zsmalloc, the more skeptical I get about it "needing" the folio_lock. At a glance it seems like a zspage already has its own lock, and the migration doesn't appear to be truly physical? There's probably something I'm missing... it would make this code a lot simpler to drop many of the folio locks. > + > +static inline void zpdesc_get(struct zpdesc *zpdesc) > +{ > + folio_get(zpdesc_folio(zpdesc)); > +} > + > +static inline void zpdesc_put(struct zpdesc *zpdesc) > +{ > + folio_put(zpdesc_folio(zpdesc)); > +} > + > #endif > diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c > index a532851025f9..243677a9c6d2 100644 > --- a/mm/zsmalloc.c > +++ b/mm/zsmalloc.c > @@ -433,13 +433,17 @@ static __maybe_unused int is_first_page(struct page *page) > return PagePrivate(page); > } > > +static int is_first_zpdesc(struct zpdesc *zpdesc) > +{ > + return PagePrivate(zpdesc_page(zpdesc)); > +} > + I feel like we might not even need to use the PG_private flag for zpages? It seems to me like its just used for sanity checking. Can zpage->first_page ever not point to the first zpdesc? For the purpose of introducing the memdesc its fine to continue using it; just some food for thought.