Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F133018670
D23034.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
9 KB
Referenced Files
None
Subscribers
None
D23034.diff
View Options
Index: head/sys/vm/vm_fault.c
===================================================================
--- head/sys/vm/vm_fault.c
+++ head/sys/vm/vm_fault.c
@@ -342,10 +342,10 @@
*m_hold = m;
vm_page_wire(m);
}
- vm_fault_dirty(fs->entry, m, prot, fault_type, fault_flags);
if (psind == 0 && !wired)
vm_fault_prefault(fs, vaddr, PFBAK, PFFOR, true);
VM_OBJECT_RUNLOCK(fs->first_object);
+ vm_fault_dirty(fs->entry, m, prot, fault_type, fault_flags);
vm_map_lookup_done(fs->map, fs->entry);
curthread->td_ru.ru_minflt++;
@@ -632,7 +632,7 @@
}
static int
-vm_fault_lock_vnode(struct faultstate *fs)
+vm_fault_lock_vnode(struct faultstate *fs, bool objlocked)
{
struct vnode *vp;
int error, locked;
@@ -668,7 +668,10 @@
}
vhold(vp);
- unlock_and_deallocate(fs);
+ if (objlocked)
+ unlock_and_deallocate(fs);
+ else
+ fault_deallocate(fs);
error = vget(vp, locked | LK_RETRY | LK_CANRECURSE, curthread);
vdrop(vp);
fs->vp = vp;
@@ -863,9 +866,11 @@
*/
if (!vm_page_all_valid(fs.m))
goto readrest;
- break; /* break to PAGE HAS BEEN FOUND */
+ VM_OBJECT_WUNLOCK(fs.object);
+ break; /* break to PAGE HAS BEEN FOUND. */
}
KASSERT(fs.m == NULL, ("fs.m should be NULL, not %p", fs.m));
+ VM_OBJECT_ASSERT_WLOCKED(fs.object);
/*
* Page is not resident. If the pager might contain the page
@@ -876,7 +881,7 @@
if (fs.object->type != OBJT_DEFAULT ||
fs.object == fs.first_object) {
if ((fs.object->flags & OBJ_SIZEVNLOCK) != 0) {
- rv = vm_fault_lock_vnode(&fs);
+ rv = vm_fault_lock_vnode(&fs, true);
MPASS(rv == KERN_SUCCESS ||
rv == KERN_RESOURCE_SHORTAGE);
if (rv == KERN_RESOURCE_SHORTAGE)
@@ -956,12 +961,23 @@
readrest:
/*
+ * Default objects have no pager so no exclusive busy exists
+ * to protect this page in the chain. Skip to the next
+ * object without dropping the lock to preserve atomicity of
+ * shadow faults.
+ */
+ if (fs.object->type == OBJT_DEFAULT)
+ goto next;
+
+ /*
* At this point, we have either allocated a new page or found
* an existing page that is only partially valid.
*
* We hold a reference on the current object and the page is
- * exclusive busied.
+ * exclusive busied. The exclusive busy prevents simultaneous
+ * faults and collapses while the object lock is dropped.
*/
+ VM_OBJECT_WUNLOCK(fs.object);
/*
* If the pager for the current object might have the page,
@@ -972,8 +988,7 @@
* have the page, the number of additional pages to read will
* apply to subsequent objects in the shadow chain.
*/
- if (fs.object->type != OBJT_DEFAULT && nera == -1 &&
- !P_KILLED(curproc)) {
+ if (nera == -1 && !P_KILLED(curproc)) {
KASSERT(fs.lookup_still_valid, ("map unlocked"));
era = fs.entry->read_ahead;
behavior = vm_map_entry_behavior(fs.entry);
@@ -1039,7 +1054,7 @@
*/
unlock_map(&fs);
- rv = vm_fault_lock_vnode(&fs);
+ rv = vm_fault_lock_vnode(&fs, false);
MPASS(rv == KERN_SUCCESS ||
rv == KERN_RESOURCE_SHORTAGE);
if (rv == KERN_RESOURCE_SHORTAGE)
@@ -1080,15 +1095,14 @@
}
ahead = ulmin(ahead, atop(e_end - vaddr) - 1);
}
- VM_OBJECT_WUNLOCK(fs.object);
rv = vm_pager_get_pages(fs.object, &fs.m, 1,
&behind, &ahead);
- VM_OBJECT_WLOCK(fs.object);
if (rv == VM_PAGER_OK) {
faultcount = behind + 1 + ahead;
hardfault = true;
- break; /* break to PAGE HAS BEEN FOUND */
+ break; /* break to PAGE HAS BEEN FOUND. */
}
+ VM_OBJECT_WLOCK(fs.object);
if (rv == VM_PAGER_ERROR)
printf("vm_fault: pager read error, pid %d (%s)\n",
curproc->p_pid, curproc->p_comm);
@@ -1106,6 +1120,7 @@
}
+next:
/*
* The requested page does not exist at this object/
* offset. Remove the invalid page from the object,
@@ -1126,19 +1141,18 @@
* Move on to the next object. Lock the next object before
* unlocking the current one.
*/
+ VM_OBJECT_ASSERT_WLOCKED(fs.object);
next_object = fs.object->backing_object;
if (next_object == NULL) {
/*
* If there's no object left, fill the page in the top
* object with zeros.
*/
+ VM_OBJECT_WUNLOCK(fs.object);
if (fs.object != fs.first_object) {
vm_object_pip_wakeup(fs.object);
- VM_OBJECT_WUNLOCK(fs.object);
-
fs.object = fs.first_object;
fs.pindex = fs.first_pindex;
- VM_OBJECT_WLOCK(fs.object);
}
MPASS(fs.first_m != NULL);
MPASS(fs.m == NULL);
@@ -1157,7 +1171,7 @@
vm_page_valid(fs.m);
/* Don't try to prefault neighboring pages. */
faultcount = 1;
- break; /* break to PAGE HAS BEEN FOUND */
+ break; /* break to PAGE HAS BEEN FOUND. */
} else {
MPASS(fs.first_m != NULL);
KASSERT(fs.object != next_object,
@@ -1173,12 +1187,12 @@
}
}
- vm_page_assert_xbusied(fs.m);
-
/*
- * PAGE HAS BEEN FOUND. [Loop invariant still holds -- the object lock
- * is held.]
+ * PAGE HAS BEEN FOUND. A valid page has been found and exclusively
+ * busied. The object lock must no longer be held.
*/
+ vm_page_assert_xbusied(fs.m);
+ VM_OBJECT_ASSERT_UNLOCKED(fs.object);
/*
* If the page is being written, but isn't already owned by the
@@ -1202,27 +1216,28 @@
*/
is_first_object_locked = false;
if (
- /*
- * Only one shadow object
- */
- (fs.object->shadow_count == 1) &&
- /*
- * No COW refs, except us
- */
- (fs.object->ref_count == 1) &&
- /*
- * No one else can look this object up
- */
- (fs.object->handle == NULL) &&
- /*
- * No other ways to look the object up
- */
- ((fs.object->flags & OBJ_ANON) != 0) &&
+ /*
+ * Only one shadow object
+ */
+ fs.object->shadow_count == 1 &&
+ /*
+ * No COW refs, except us
+ */
+ fs.object->ref_count == 1 &&
+ /*
+ * No one else can look this object up
+ */
+ fs.object->handle == NULL &&
+ /*
+ * No other ways to look the object up
+ */
+ (fs.object->flags & OBJ_ANON) != 0 &&
(is_first_object_locked = VM_OBJECT_TRYWLOCK(fs.first_object)) &&
- /*
- * We don't chase down the shadow chain
- */
- fs.object == fs.first_object->backing_object) {
+ /*
+ * We don't chase down the shadow chain
+ */
+ fs.object == fs.first_object->backing_object &&
+ VM_OBJECT_TRYWLOCK(fs.object)) {
/*
* Remove but keep xbusy for replace. fs.m is
@@ -1242,11 +1257,13 @@
fs.first_object->backing_object_offset));
#endif
VM_OBJECT_WUNLOCK(fs.object);
+ VM_OBJECT_WUNLOCK(fs.first_object);
fs.first_m = fs.m;
fs.m = NULL;
VM_CNT_INC(v_cow_optim);
} else {
- VM_OBJECT_WUNLOCK(fs.object);
+ if (is_first_object_locked)
+ VM_OBJECT_WUNLOCK(fs.first_object);
/*
* Oh, well, lets copy it.
*/
@@ -1285,8 +1302,6 @@
fs.object = fs.first_object;
fs.pindex = fs.first_pindex;
fs.m = fs.first_m;
- if (!is_first_object_locked)
- VM_OBJECT_WLOCK(fs.object);
VM_CNT_INC(v_cow_faults);
curthread->td_cow++;
} else {
@@ -1300,7 +1315,7 @@
*/
if (!fs.lookup_still_valid) {
if (!vm_map_trylock_read(fs.map)) {
- unlock_and_deallocate(&fs);
+ fault_deallocate(&fs);
goto RetryFault;
}
fs.lookup_still_valid = true;
@@ -1314,7 +1329,7 @@
* pageout will grab it eventually.
*/
if (result != KERN_SUCCESS) {
- unlock_and_deallocate(&fs);
+ fault_deallocate(&fs);
/*
* If retry of map lookup would have blocked then
@@ -1326,7 +1341,7 @@
}
if ((retry_object != fs.first_object) ||
(retry_pindex != fs.first_pindex)) {
- unlock_and_deallocate(&fs);
+ fault_deallocate(&fs);
goto RetryFault;
}
@@ -1341,7 +1356,7 @@
prot &= retry_prot;
fault_type &= retry_prot;
if (prot == 0) {
- unlock_and_deallocate(&fs);
+ fault_deallocate(&fs);
goto RetryFault;
}
@@ -1350,6 +1365,7 @@
("!wired && VM_FAULT_WIRE"));
}
}
+ VM_OBJECT_ASSERT_UNLOCKED(fs.object);
/*
* If the page was filled by a pager, save the virtual address that
@@ -1360,17 +1376,16 @@
if (hardfault)
fs.entry->next_read = vaddr + ptoa(ahead) + PAGE_SIZE;
- vm_page_assert_xbusied(fs.m);
- vm_fault_dirty(fs.entry, fs.m, prot, fault_type, fault_flags);
-
/*
* Page must be completely valid or it is not fit to
* map into user space. vm_pager_get_pages() ensures this.
*/
+ vm_page_assert_xbusied(fs.m);
KASSERT(vm_page_all_valid(fs.m),
("vm_fault: page %p partially invalid", fs.m));
- VM_OBJECT_WUNLOCK(fs.object);
+ vm_fault_dirty(fs.entry, fs.m, prot, fault_type, fault_flags);
+
/*
* Put this page into the physical map. We had to do the unlock above
* because pmap_enter() may sleep. We don't put the page
@@ -1451,17 +1466,11 @@
vm_size_t size;
object = fs->object;
- VM_OBJECT_ASSERT_WLOCKED(object);
+ VM_OBJECT_ASSERT_UNLOCKED(object);
first_object = fs->first_object;
- if (first_object != object) {
- if (!VM_OBJECT_TRYWLOCK(first_object)) {
- VM_OBJECT_WUNLOCK(object);
- VM_OBJECT_WLOCK(first_object);
- VM_OBJECT_WLOCK(object);
- }
- }
/* Neither fictitious nor unmanaged pages can be reclaimed. */
if ((first_object->flags & (OBJ_FICTITIOUS | OBJ_UNMANAGED)) == 0) {
+ VM_OBJECT_RLOCK(first_object);
size = VM_FAULT_DONTNEED_MIN;
if (MAXPAGESIZES > 1 && size < pagesizes[1])
size = pagesizes[1];
@@ -1501,9 +1510,8 @@
vm_page_deactivate(m);
}
}
+ VM_OBJECT_RUNLOCK(first_object);
}
- if (first_object != object)
- VM_OBJECT_WUNLOCK(first_object);
}
/*
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Oct 23, 3:07 AM (10 h, 14 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
24079845
Default Alt Text
D23034.diff (9 KB)
Attached To
Mode
D23034: Reduce object locking in vm_fault. The object is only needed until we have an exclusive busy.
Attached
Detach File
Event Timeline
Log In to Comment