On 1/26/22 19:34, Pasha Tatashin wrote: > The problems with page->_refcount are hard to debug, because usually > when they are detected, the damage has occurred a long time ago. Yet, > the problems with invalid page refcount may be catastrophic and lead to > memory corruptions. > > Reduce the scope of when the _refcount problems manifest themselves by > adding checks for underflows and overflows into functions that modify > _refcount. > > Use atomic_fetch_* functions to get the old values of the _refcount, > and use it to check for overflow/underflow. > > Signed-off-by: Pasha Tatashin <pasha.tatashin@xxxxxxxxxx> > --- > include/linux/page_ref.h | 59 +++++++++++++++++++++++++++++----------- > 1 file changed, 43 insertions(+), 16 deletions(-) > > diff --git a/include/linux/page_ref.h b/include/linux/page_ref.h > index 2e677e6ad09f..fe4864f7f69c 100644 > --- a/include/linux/page_ref.h > +++ b/include/linux/page_ref.h > @@ -117,7 +117,10 @@ static inline void init_page_count(struct page *page) > > static inline void page_ref_add(struct page *page, int nr) > { > - atomic_add(nr, &page->_refcount); > + int old_val = atomic_fetch_add(nr, &page->_refcount); > + int new_val = old_val + nr; > + > + VM_BUG_ON_PAGE((unsigned int)new_val < (unsigned int)old_val, page); This seems somewhat weird, as it will trigger not just on overflow, but also if nr is negative. Which I think is valid usage, even though the function has 'add' in name, because 'nr' is signed?