Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/uvm Make swap encryption MP-safe.
details: https://anonhg.NetBSD.org/src/rev/1a0a0f5d94f6
branches: trunk
changeset: 933169:1a0a0f5d94f6
user: riastradh <riastradh%NetBSD.org@localhost>
date: Wed May 20 17:48:34 2020 +0000
description:
Make swap encryption MP-safe.
Not entirely sure the rest of the swap system is MP-safe, but let's
not make it worse!
XXX Why is swap_syscall_lock an rwlock? We don't seem to take the
reader lock ever.
diffstat:
sys/uvm/uvm_swap.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++-------
1 files changed, 85 insertions(+), 14 deletions(-)
diffs (240 lines):
diff -r 968e4651f6ed -r 1a0a0f5d94f6 sys/uvm/uvm_swap.c
--- a/sys/uvm/uvm_swap.c Wed May 20 17:32:27 2020 +0000
+++ b/sys/uvm/uvm_swap.c Wed May 20 17:48:34 2020 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: uvm_swap.c,v 1.189 2020/05/10 02:38:10 riastradh Exp $ */
+/* $NetBSD: uvm_swap.c,v 1.190 2020/05/20 17:48:34 riastradh Exp $ */
/*
* Copyright (c) 1995, 1996, 1997, 2009 Matthew R. Green
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uvm_swap.c,v 1.189 2020/05/10 02:38:10 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uvm_swap.c,v 1.190 2020/05/20 17:48:34 riastradh Exp $");
#include "opt_uvmhist.h"
#include "opt_compat_netbsd.h"
@@ -147,7 +147,7 @@
struct bufq_state *swd_tab; /* buffer list */
int swd_active; /* number of active buffers */
- uint8_t *swd_encmap; /* bitmap of encrypted slots */
+ volatile uint32_t *swd_encmap; /* bitmap of encrypted slots */
keyInstance swd_enckey; /* AES key expanded for enc */
keyInstance swd_deckey; /* AES key expanded for dec */
bool swd_encinit; /* true if keys initialized */
@@ -234,6 +234,19 @@
static void uvm_swap_encryptpage(struct swapdev *, void *, int);
static void uvm_swap_decryptpage(struct swapdev *, void *, int);
+static size_t
+encmap_size(size_t npages)
+{
+ struct swapdev *sdp;
+ const size_t bytesperword = sizeof(sdp->swd_encmap[0]);
+ const size_t bitsperword = NBBY * bytesperword;
+ const size_t nbits = npages; /* one bit for each page */
+ const size_t nwords = howmany(nbits, bitsperword);
+ const size_t nbytes = nwords * bytesperword;
+
+ return nbytes;
+}
+
/*
* uvm_swap_init: init the swap system data structures and locks
*
@@ -304,6 +317,9 @@
struct swappri *spp, *pspp;
UVMHIST_FUNC("swaplist_insert"); UVMHIST_CALLED(pdhist);
+ KASSERT(rw_write_held(&swap_syscall_lock));
+ KASSERT(mutex_owned(&uvm_swap_data_lock));
+
/*
* find entry at or after which to insert the new device.
*/
@@ -356,6 +372,10 @@
struct swapdev *sdp;
struct swappri *spp;
+ KASSERT(rw_lock_held(&swap_syscall_lock));
+ KASSERT(remove ? rw_write_held(&swap_syscall_lock) : 1);
+ KASSERT(mutex_owned(&uvm_swap_data_lock));
+
/*
* search the lists for the requested vp
*/
@@ -386,6 +406,9 @@
{
struct swappri *spp, *nextspp;
+ KASSERT(rw_write_held(&swap_syscall_lock));
+ KASSERT(mutex_owned(&uvm_swap_data_lock));
+
LIST_FOREACH_SAFE(spp, &swap_priority, spi_swappri, nextspp) {
if (!TAILQ_EMPTY(&spp->spi_swapdev))
continue;
@@ -407,6 +430,8 @@
struct swapdev *sdp;
struct swappri *spp;
+ KASSERT(mutex_owned(&uvm_swap_data_lock));
+
LIST_FOREACH(spp, &swap_priority, spi_swappri) {
TAILQ_FOREACH(sdp, &spp->spi_swapdev, swd_next) {
if (sdp->swd_flags & SWF_FAKE)
@@ -420,6 +445,23 @@
return NULL;
}
+/*
+ * swapdrum_sdp_is: true iff the swap device for pgno is sdp
+ *
+ * => for use in positive assertions only; result is not stable
+ */
+static bool __debugused
+swapdrum_sdp_is(int pgno, struct swapdev *sdp)
+{
+ bool result;
+
+ mutex_enter(&uvm_swap_data_lock);
+ result = swapdrum_getsdp(pgno) == sdp;
+ mutex_exit(&uvm_swap_data_lock);
+
+ return result;
+}
+
void swapsys_lock(krw_t op)
{
rw_enter(&swap_syscall_lock, op);
@@ -904,7 +946,7 @@
* allocate space to for swap encryption state and mark the
* keys uninitialized so we generate them lazily
*/
- sdp->swd_encmap = kmem_zalloc(howmany(npages, NBBY), KM_SLEEP);
+ sdp->swd_encmap = kmem_zalloc(encmap_size(npages), KM_SLEEP);
sdp->swd_encinit = false;
/*
@@ -1011,6 +1053,9 @@
UVMHIST_FUNC("swap_off"); UVMHIST_CALLED(pdhist);
UVMHIST_LOG(pdhist, " dev=%jx, npages=%jd", sdp->swd_dev,npages, 0, 0);
+ KASSERT(rw_write_held(&swap_syscall_lock));
+ KASSERT(mutex_owned(&uvm_swap_data_lock));
+
/* disable the swap area being removed */
sdp->swd_flags &= ~SWF_ENABLE;
uvmexp.swpgavail -= npages;
@@ -1079,7 +1124,8 @@
vmem_free(swapmap, sdp->swd_drumoffset, sdp->swd_drumsize);
blist_destroy(sdp->swd_blist);
bufq_free(sdp->swd_tab);
- kmem_free(sdp->swd_encmap, howmany(sdp->swd_npages, NBBY));
+ kmem_free(__UNVOLATILE(sdp->swd_encmap),
+ encmap_size(sdp->swd_drumsize));
explicit_memset(&sdp->swd_enckey, 0, sizeof sdp->swd_enckey);
explicit_memset(&sdp->swd_deckey, 0, sizeof sdp->swd_deckey);
kmem_free(sdp, sizeof(*sdp));
@@ -1856,33 +1902,39 @@
* 4. KEY, ENCRYPTION: Encrypt and mark the slots
* encrypted.
*/
+ mutex_enter(&uvm_swap_data_lock);
sdp = swapdrum_getsdp(startslot);
if (!sdp->swd_encinit) {
- if (!swap_encrypt)
+ if (!swap_encrypt) {
+ mutex_exit(&uvm_swap_data_lock);
break;
+ }
uvm_swap_genkey(sdp);
}
KASSERT(sdp->swd_encinit);
+ mutex_exit(&uvm_swap_data_lock);
if (swap_encrypt) {
for (i = 0; i < npages; i++) {
int s = startslot + i;
- KDASSERT(swapdrum_getsdp(s) == sdp);
+ KDASSERT(swapdrum_sdp_is(s, sdp));
KASSERT(s >= sdp->swd_drumoffset);
s -= sdp->swd_drumoffset;
KASSERT(s < sdp->swd_drumsize);
uvm_swap_encryptpage(sdp,
(void *)(kva + (vsize_t)i*PAGE_SIZE), s);
- setbit(sdp->swd_encmap, s);
+ atomic_or_32(&sdp->swd_encmap[s/32],
+ __BIT(s%32));
}
} else {
for (i = 0; i < npages; i++) {
int s = startslot + i;
- KDASSERT(swapdrum_getsdp(s) == sdp);
+ KDASSERT(swapdrum_sdp_is(s, sdp));
KASSERT(s >= sdp->swd_drumoffset);
s -= sdp->swd_drumoffset;
KASSERT(s < sdp->swd_drumsize);
- clrbit(sdp->swd_encmap, s);
+ atomic_and_32(&sdp->swd_encmap[s/32],
+ ~__BIT(s%32));
}
}
} while (0);
@@ -1934,8 +1986,14 @@
*/
VOP_STRATEGY(swapdev_vp, bp);
- if (async)
+ if (async) {
+ /*
+ * Reads are always synchronous; if this changes, we
+ * need to add an asynchronous path for decryption.
+ */
+ KASSERT((bp->b_flags & B_READ) == 0);
return 0;
+ }
/*
* must be sync i/o. wait for it to finish
@@ -1949,10 +2007,22 @@
if (!write) do {
struct swapdev *sdp;
+ bool encinit;
int i;
+ /*
+ * Get the sdp. Everything about it except the encinit
+ * bit, saying whether the encryption key is
+ * initialized or not, and the encrypted bit for each
+ * page, is stable until all swap pages have been
+ * released and the device is removed.
+ */
+ mutex_enter(&uvm_swap_data_lock);
sdp = swapdrum_getsdp(startslot);
- if (!sdp->swd_encinit)
+ encinit = sdp->swd_encinit;
+ mutex_exit(&uvm_swap_data_lock);
+
+ if (!encinit)
/*
* If there's no encryption key, there's no way
* any of these slots can be encrypted, so
@@ -1961,11 +2031,12 @@
break;
for (i = 0; i < npages; i++) {
int s = startslot + i;
- KDASSERT(swapdrum_getsdp(s) == sdp);
+ KDASSERT(swapdrum_sdp_is(s, sdp));
KASSERT(s >= sdp->swd_drumoffset);
s -= sdp->swd_drumoffset;
KASSERT(s < sdp->swd_drumsize);
- if (isclr(sdp->swd_encmap, s))
+ if ((atomic_load_relaxed(&sdp->swd_encmap[s/32]) &
+ __BIT(s%32)) == 0)
continue;
uvm_swap_decryptpage(sdp,
(void *)(kva + (vsize_t)i*PAGE_SIZE), s);
Home |
Main Index |
Thread Index |
Old Index