Fix handling of subpage BIO_WRITE and BIO_DELETE requests on swap MDs.
Such requests would previously mark the entire page as valid, which was incorrect since nothing guaranteed that the page's contents had been initialized. This change also modifies subpage BIO_DELETEs so that the entire page is marked dirty, rather than only a subrange. There is no benefit to creating partially dirty swap pages. Reviewed by: alc, kib (previous version) MFC after: 3 days
This commit is contained in:
parent
2d1353a21d
commit
cc2fe2b0fb
@ -972,6 +972,16 @@ unmapped_step:
|
||||
return (error);
|
||||
}
|
||||
|
||||
static void
|
||||
md_swap_page_free(vm_page_t m)
|
||||
{
|
||||
|
||||
vm_page_xunbusy(m);
|
||||
vm_page_lock(m);
|
||||
vm_page_free(m);
|
||||
vm_page_unlock(m);
|
||||
}
|
||||
|
||||
static int
|
||||
mdstart_swap(struct md_s *sc, struct bio *bp)
|
||||
{
|
||||
@ -1044,15 +1054,17 @@ mdstart_swap(struct md_s *sc, struct bio *bp)
|
||||
cpu_flush_dcache(p, len);
|
||||
}
|
||||
} else if (bp->bio_cmd == BIO_WRITE) {
|
||||
if (len != PAGE_SIZE && m->valid != VM_PAGE_BITS_ALL)
|
||||
if (len == PAGE_SIZE || m->valid == VM_PAGE_BITS_ALL)
|
||||
rv = VM_PAGER_OK;
|
||||
else
|
||||
rv = vm_pager_get_pages(sc->object, &m, 1,
|
||||
NULL, NULL);
|
||||
else
|
||||
rv = VM_PAGER_OK;
|
||||
if (rv == VM_PAGER_ERROR) {
|
||||
vm_page_xunbusy(m);
|
||||
break;
|
||||
}
|
||||
} else if (rv == VM_PAGER_FAIL)
|
||||
pmap_zero_page(m);
|
||||
|
||||
if ((bp->bio_flags & BIO_UNMAPPED) != 0) {
|
||||
pmap_copy_pages(bp->bio_ma, ma_offs, &m,
|
||||
offs, len);
|
||||
@ -1062,34 +1074,40 @@ mdstart_swap(struct md_s *sc, struct bio *bp)
|
||||
} else {
|
||||
physcopyin(p, VM_PAGE_TO_PHYS(m) + offs, len);
|
||||
}
|
||||
|
||||
m->valid = VM_PAGE_BITS_ALL;
|
||||
vm_page_dirty(m);
|
||||
vm_pager_page_unswapped(m);
|
||||
} else if (bp->bio_cmd == BIO_DELETE) {
|
||||
if (len != PAGE_SIZE && m->valid != VM_PAGE_BITS_ALL)
|
||||
if (len == PAGE_SIZE || m->valid == VM_PAGE_BITS_ALL)
|
||||
rv = VM_PAGER_OK;
|
||||
else
|
||||
rv = vm_pager_get_pages(sc->object, &m, 1,
|
||||
NULL, NULL);
|
||||
else
|
||||
rv = VM_PAGER_OK;
|
||||
if (rv == VM_PAGER_ERROR) {
|
||||
vm_page_xunbusy(m);
|
||||
break;
|
||||
}
|
||||
if (len != PAGE_SIZE) {
|
||||
pmap_zero_page_area(m, offs, len);
|
||||
vm_page_clear_dirty(m, offs, len);
|
||||
m->valid = VM_PAGE_BITS_ALL;
|
||||
} else
|
||||
} else if (rv == VM_PAGER_FAIL) {
|
||||
md_swap_page_free(m);
|
||||
m = NULL;
|
||||
} else {
|
||||
/* Page is valid. */
|
||||
if (len != PAGE_SIZE) {
|
||||
pmap_zero_page_area(m, offs, len);
|
||||
vm_page_dirty(m);
|
||||
}
|
||||
vm_pager_page_unswapped(m);
|
||||
if (len == PAGE_SIZE) {
|
||||
md_swap_page_free(m);
|
||||
m = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
vm_page_xunbusy(m);
|
||||
vm_page_lock(m);
|
||||
if (bp->bio_cmd == BIO_DELETE && len == PAGE_SIZE)
|
||||
vm_page_free(m);
|
||||
else
|
||||
if (m != NULL) {
|
||||
vm_page_xunbusy(m);
|
||||
vm_page_lock(m);
|
||||
vm_page_activate(m);
|
||||
vm_page_unlock(m);
|
||||
if (bp->bio_cmd == BIO_WRITE) {
|
||||
vm_page_dirty(m);
|
||||
vm_pager_page_unswapped(m);
|
||||
vm_page_unlock(m);
|
||||
}
|
||||
|
||||
/* Actions on further pages start at offset 0 */
|
||||
|
Loading…
x
Reference in New Issue
Block a user