vm_object_split(): Handle orig_object type changes.

orig_object->type can change from OBJT_DEFAULT to OBJT_SWAP while
vm_object_split() is sleeping.  In this case some pages in new_object
may be left unbusied, but vm_object_split() attempts to unbusy all of
them.

Track the beginning of the busied range.  Add an assertion to verify
that pages are not re-added to the source object while sleeping.

Reported by:	Olympios Petrakis <olympios.petrakis@netapp.com>
Reviewed by:	alc, kib
Tested by:	pho
MFC after:	1 week
Sponsored by:	NetApp, Inc.
Sponsored by:	Klara, Inc.
Differential Revision:	https://reviews.freebsd.org/D26223
This commit is contained in:
Mark Johnston 2020-09-07 23:28:33 +00:00
parent 7de1bc13e2
commit aec9e7d8b0
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=365437

View File

@ -1496,7 +1496,7 @@ vm_object_shadow(vm_object_t *object, vm_ooffset_t *offset, vm_size_t length,
void
vm_object_split(vm_map_entry_t entry)
{
vm_page_t m, m_next;
vm_page_t m, m_busy, m_next;
vm_object_t orig_object, new_object, backing_object;
vm_pindex_t idx, offidxstart;
vm_size_t size;
@ -1553,8 +1553,14 @@ vm_object_split(vm_map_entry_t entry)
* that the object is in transition.
*/
vm_object_set_flag(orig_object, OBJ_SPLIT);
m_busy = NULL;
#ifdef INVARIANTS
idx = 0;
#endif
retry:
m = vm_page_find_least(orig_object, offidxstart);
KASSERT(m == NULL || idx <= m->pindex - offidxstart,
("%s: object %p was repopulated", __func__, orig_object));
for (; m != NULL && (idx = m->pindex - offidxstart) < size;
m = m_next) {
m_next = TAILQ_NEXT(m, listq);
@ -1609,8 +1615,15 @@ vm_object_split(vm_map_entry_t entry)
*/
vm_reserv_rename(m, new_object, orig_object, offidxstart);
#endif
/*
* orig_object's type may change while sleeping, so keep track
* of the beginning of the busied range.
*/
if (orig_object->type != OBJT_SWAP)
vm_page_xunbusy(m);
else if (m_busy == NULL)
m_busy = m;
}
if (orig_object->type == OBJT_SWAP) {
/*
@ -1618,8 +1631,9 @@ vm_object_split(vm_map_entry_t entry)
* and new_object's locks are released and reacquired.
*/
swap_pager_copy(orig_object, new_object, offidxstart, 0);
TAILQ_FOREACH(m, &new_object->memq, listq)
vm_page_xunbusy(m);
if (m_busy != NULL)
TAILQ_FOREACH_FROM(m_busy, &new_object->memq, listq)
vm_page_xunbusy(m_busy);
}
vm_object_clear_flag(orig_object, OBJ_SPLIT);
VM_OBJECT_WUNLOCK(orig_object);