diff options
author | Mark Johnston <markj@FreeBSD.org> | 2018-08-23 20:34:22 +0000 |
---|---|---|
committer | Mark Johnston <markj@FreeBSD.org> | 2018-08-23 20:34:22 +0000 |
commit | 99d92d732f3bbbcd9bea43298341ab44f7bd4a5f (patch) | |
tree | 3add724fc6ea9ffd5c1fa2a0d6ae7c7f1a004586 /sys/vm/vm_page.h | |
parent | 608226d5596fb7683e9b649d01e3241624f77b3c (diff) | |
download | src-99d92d732f3bbbcd9bea43298341ab44f7bd4a5f.tar.gz src-99d92d732f3bbbcd9bea43298341ab44f7bd4a5f.zip |
Ensure that queue state is cleared when vm_page_dequeue() returns.
Per-page queue state is updated non-atomically, with either the page
lock or the page queue lock held. When vm_page_dequeue() is called
without the page lock, in rare cases a different thread may be
concurrently dequeuing the page with the pagequeue lock held. Because
of the non-atomic update, vm_page_dequeue() might return before queue
state is completely updated, which can lead to race conditions.
Restrict the vm_page_dequeue() interface so that it must be called
either with the page lock held or on a free page, and busy wait when
a different thread is concurrently updating queue state, which must
happen in a critical section.
While here, do some related cleanup: inline vm_page_dequeue_locked()
into its only caller and delete a prototype for the unimplemented
vm_page_requeue_locked(). Replace the volatile qualifier for "queue"
added in r333703 with explicit uses of atomic_load_8() where required.
Reported and tested by: pho
Reviewed by: alc
Differential Revision: https://reviews.freebsd.org/D15980
Notes
Notes:
svn path=/head/; revision=338276
Diffstat (limited to 'sys/vm/vm_page.h')
-rw-r--r-- | sys/vm/vm_page.h | 4 |
1 files changed, 1 insertions, 3 deletions
diff --git a/sys/vm/vm_page.h b/sys/vm/vm_page.h index 5f3852d5fc48..d6a4115b89be 100644 --- a/sys/vm/vm_page.h +++ b/sys/vm/vm_page.h @@ -208,7 +208,7 @@ struct vm_page { uint16_t flags; /* page PG_* flags (P) */ uint8_t aflags; /* access is atomic */ uint8_t oflags; /* page VPO_* flags (O) */ - volatile uint8_t queue; /* page queue index (Q) */ + uint8_t queue; /* page queue index (Q) */ int8_t psind; /* pagesizes[] index (O) */ int8_t segind; /* vm_phys segment index (C) */ uint8_t order; /* index of the buddy queue (F) */ @@ -539,7 +539,6 @@ void vm_page_deactivate(vm_page_t); void vm_page_deactivate_noreuse(vm_page_t); void vm_page_dequeue(vm_page_t m); void vm_page_dequeue_deferred(vm_page_t m); -void vm_page_dequeue_locked(vm_page_t m); void vm_page_drain_pqbatch(void); vm_page_t vm_page_find_least(vm_object_t, vm_pindex_t); bool vm_page_free_prep(vm_page_t m); @@ -565,7 +564,6 @@ int vm_page_rename (vm_page_t, vm_object_t, vm_pindex_t); vm_page_t vm_page_replace(vm_page_t mnew, vm_object_t object, vm_pindex_t pindex); void vm_page_requeue(vm_page_t m); -void vm_page_requeue_locked(vm_page_t m); int vm_page_sbusied(vm_page_t m); vm_page_t vm_page_scan_contig(u_long npages, vm_page_t m_start, vm_page_t m_end, u_long alignment, vm_paddr_t boundary, int options); |