From 793bf44fb8ccf3087cd7a1f304257b8b560d3dc6 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Sat, 7 Apr 2018 18:03:23 -0700 Subject: [PATCH] kernel - Fix pageout / sbusy race * For now, vm_page_sbusy_try() cannot safely increment m->busy_count, and then decrement it if it turns out to be busy. This interferes with any other thread that is holding the page hard-busy and expects the soft-busy mask to remain 0. * Eventually we should be able to rework the fetchadd optimization back in. Use atomic_cmpset_*() for now though. --- sys/vm/vm_page.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c index b2f9e7905c..275b7ed4c4 100644 --- a/sys/vm/vm_page.c +++ b/sys/vm/vm_page.c @@ -2835,6 +2835,10 @@ vm_page_io_finish(vm_page_t m) /* * Attempt to soft-busy a page. The page must not be PBUSY_LOCKED. * + * We can't use fetchadd here because we might race a hard-busy and the + * page freeing code asserts on a non-zero soft-busy count (even if only + * temporary). + * * Returns 0 on success, non-zero on failure. */ int @@ -2842,6 +2846,16 @@ vm_page_sbusy_try(vm_page_t m) { uint32_t ocount; + for (;;) { + ocount = m->busy_count; + cpu_ccfence(); + if (ocount & PBUSY_LOCKED) + return 1; + if (atomic_cmpset_int(&m->busy_count, ocount, ocount + 1)) + break; + } + return 0; +#if 0 if (m->busy_count & PBUSY_LOCKED) return 1; ocount = atomic_fetchadd_int(&m->busy_count, 1); @@ -2850,6 +2864,7 @@ vm_page_sbusy_try(vm_page_t m) return 1; } return 0; +#endif } /* -- 2.11.4.GIT