Skip to content

Commit

Permalink
Pull up following revision(s) (requested by chs in ticket #327):
Browse files Browse the repository at this point in the history
	sys/uvm/uvm_fault.c: revision 1.234

uvm: prevent TLB invalidation races during COW resolution

When a thread takes a page fault which results in COW resolution,
other threads in the same process can be concurrently accessing that
same mapping on other CPUs.  When the faulting thread updates the pmap
entry at the end of COW processing, the resulting TLB invalidations to
other CPUs are not done atomically, so another thread can write to the
new writable page and then a third thread might still read from the
old read-only page, resulting in inconsistent views of the page by the
latter two threads.  Fix this by removing the pmap entry entirely for
the original page before we install the new pmap entry for the new
page, so that the new page can only be modified after the old page is
no longer accessible.

This fixes PR 56535 as well as the netbsd versions of problems
described in various bug trackers:
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=225584
https://reviews.freebsd.org/D14347
golang/go#34988
  • Loading branch information
MartinHusemann committed Aug 15, 2023
1 parent 846936e commit 8e5edb9
Showing 1 changed file with 12 additions and 3 deletions.
15 changes: 12 additions & 3 deletions sys/uvm/uvm_fault.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* $NetBSD: uvm_fault.c,v 1.231 2022/10/26 23:27:32 riastradh Exp $ */
/* $NetBSD: uvm_fault.c,v 1.231.2.1 2023/08/15 09:44:09 martin Exp $ */

/*
* Copyright (c) 1997 Charles D. Cranor and Washington University.
Expand Down Expand Up @@ -32,7 +32,7 @@
*/

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: uvm_fault.c,v 1.231 2022/10/26 23:27:32 riastradh Exp $");
__KERNEL_RCSID(0, "$NetBSD: uvm_fault.c,v 1.231.2.1 2023/08/15 09:44:09 martin Exp $");

#include "opt_uvmhist.h"

Expand Down Expand Up @@ -633,8 +633,17 @@ uvmfault_promote(struct uvm_faultinfo *ufi,
goto done;
}

/* copy page [pg now dirty] */
/*
* copy the page [pg now dirty]
*
* Remove the pmap entry now for the old page at this address
* so that no thread can modify the new page while any thread
* might still see the old page.
*/
if (opg) {
pmap_remove(vm_map_pmap(ufi->orig_map), ufi->orig_rvaddr,
ufi->orig_rvaddr + PAGE_SIZE);
pmap_update(vm_map_pmap(ufi->orig_map));
uvm_pagecopy(opg, pg);
}
KASSERT(uvm_pagegetdirty(pg) == UVM_PAGE_STATUS_DIRTY);
Expand Down

0 comments on commit 8e5edb9

Please sign in to comment.