* Grab a page and make it valid, paging in if necessary. Pages missing from * their pager are zero filled and validated. If a VM_ALLOC_COUNT is supplied * and the page is not valid as many as VM_INITIAL_PAGEIN pages can be brought * in simultaneously. Additional pages will be left on a paging queue but * will neither be wired nor busy regardless of allocflags. */
| 4580 | * will neither be wired nor busy regardless of allocflags. |
| 4581 | */ |
| 4582 | int |
| 4583 | vm_page_grab_valid(vm_page_t *mp, vm_object_t object, vm_pindex_t pindex, int allocflags) |
| 4584 | { |
| 4585 | vm_page_t m; |
| 4586 | vm_page_t ma[VM_INITIAL_PAGEIN]; |
| 4587 | int after, i, pflags, rv; |
| 4588 | |
| 4589 | KASSERT((allocflags & VM_ALLOC_SBUSY) == 0 || |
| 4590 | (allocflags & VM_ALLOC_IGN_SBUSY) != 0, |
| 4591 | ("vm_page_grab_valid: VM_ALLOC_SBUSY/VM_ALLOC_IGN_SBUSY mismatch")); |
| 4592 | KASSERT((allocflags & |
| 4593 | (VM_ALLOC_NOWAIT | VM_ALLOC_WAITFAIL | VM_ALLOC_ZERO)) == 0, |
| 4594 | ("vm_page_grab_valid: Invalid flags 0x%X", allocflags)); |
| 4595 | VM_OBJECT_ASSERT_WLOCKED(object); |
| 4596 | pflags = allocflags & ~(VM_ALLOC_NOBUSY | VM_ALLOC_SBUSY | |
| 4597 | VM_ALLOC_WIRED); |
| 4598 | pflags |= VM_ALLOC_WAITFAIL; |
| 4599 | |
| 4600 | retrylookup: |
| 4601 | if ((m = vm_page_lookup(object, pindex)) != NULL) { |
| 4602 | /* |
| 4603 | * If the page is fully valid it can only become invalid |
| 4604 | * with the object lock held. If it is not valid it can |
| 4605 | * become valid with the busy lock held. Therefore, we |
| 4606 | * may unnecessarily lock the exclusive busy here if we |
| 4607 | * race with I/O completion not using the object lock. |
| 4608 | * However, we will not end up with an invalid page and a |
| 4609 | * shared lock. |
| 4610 | */ |
| 4611 | if (!vm_page_trybusy(m, |
| 4612 | vm_page_all_valid(m) ? allocflags : 0)) { |
| 4613 | (void)vm_page_grab_sleep(object, m, pindex, "pgrbwt", |
| 4614 | allocflags, true); |
| 4615 | goto retrylookup; |
| 4616 | } |
| 4617 | if (vm_page_all_valid(m)) |
| 4618 | goto out; |
| 4619 | if ((allocflags & VM_ALLOC_NOCREAT) != 0) { |
| 4620 | vm_page_busy_release(m); |
| 4621 | *mp = NULL; |
| 4622 | return (VM_PAGER_FAIL); |
| 4623 | } |
| 4624 | } else if ((allocflags & VM_ALLOC_NOCREAT) != 0) { |
| 4625 | *mp = NULL; |
| 4626 | return (VM_PAGER_FAIL); |
| 4627 | } else if ((m = vm_page_alloc(object, pindex, pflags)) == NULL) { |
| 4628 | goto retrylookup; |
| 4629 | } |
| 4630 | |
| 4631 | vm_page_assert_xbusied(m); |
| 4632 | if (vm_pager_has_page(object, pindex, NULL, &after)) { |
| 4633 | after = MIN(after, VM_INITIAL_PAGEIN); |
| 4634 | after = MIN(after, allocflags >> VM_ALLOC_COUNT_SHIFT); |
| 4635 | after = MAX(after, 1); |
| 4636 | ma[0] = m; |
| 4637 | for (i = 1; i < after; i++) { |
| 4638 | if ((ma[i] = vm_page_next(ma[i - 1])) != NULL) { |
| 4639 | if (ma[i]->valid || !vm_page_tryxbusy(ma[i])) |
no test coverage detected