Message ID | 20220305042855.BFBB9C004E1@smtp.kernel.org (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | [1/8] selftests/vm: cleanup hugetlb file after mremap test | expand |
On Fri, Mar 4, 2022 at 8:28 PM Andrew Morton <akpm@linux-foundation.org> wrote: > > To ensure anon_vma_name refcount does not overflow, stop anon_vma_name > sharing when the refcount reaches REFCOUNT_MAX (2147483647), which still > leaves INT_MAX/2 (1073741823) values before the counter reaches > REFCOUNT_SATURATED. This should provide enough headroom for raising the > refcounts temporarily. This is a classic case of kref simply being the wrong type for this. We sh ould move away from that idiotic "saturate with a warning" type, and just codify that what the page refs do is the RightThing(tm) to do. I've ranted against kref for years, I hate that damn thing. It's literally broken by design with the known leaking behavior. Oh well. I'm taking this patch as a "fix up refcount problems", and I guess I need to some day just extract the page_ref code into a nice type of its own so that it's usable outside of pages. (Others have copied the page_ref code manually, but there's no "helper type with functions to use it", which is why people then use that mis-designed refcount stuff). Linus
--- a/include/linux/mm_inline.h~mm-prevent-vm_area_struct-anon_name-refcount-saturation +++ a/include/linux/mm_inline.h @@ -161,15 +161,25 @@ static inline void anon_vma_name_put(str kref_put(&anon_name->kref, anon_vma_name_free); } +static inline +struct anon_vma_name *anon_vma_name_reuse(struct anon_vma_name *anon_name) +{ + /* Prevent anon_name refcount saturation early on */ + if (kref_read(&anon_name->kref) < REFCOUNT_MAX) { + anon_vma_name_get(anon_name); + return anon_name; + + } + return anon_vma_name_alloc(anon_name->name); +} + static inline void dup_anon_vma_name(struct vm_area_struct *orig_vma, struct vm_area_struct *new_vma) { struct anon_vma_name *anon_name = anon_vma_name(orig_vma); - if (anon_name) { - anon_vma_name_get(anon_name); - new_vma->anon_name = anon_name; - } + if (anon_name) + new_vma->anon_name = anon_vma_name_reuse(anon_name); } static inline void free_anon_vma_name(struct vm_area_struct *vma) --- a/mm/madvise.c~mm-prevent-vm_area_struct-anon_name-refcount-saturation +++ a/mm/madvise.c @@ -113,8 +113,7 @@ static int replace_anon_vma_name(struct if (anon_vma_name_eq(orig_name, anon_name)) return 0; - anon_vma_name_get(anon_name); - vma->anon_name = anon_name; + vma->anon_name = anon_vma_name_reuse(anon_name); anon_vma_name_put(orig_name); return 0;