Changeset View
Changeset View
Standalone View
Standalone View
sys/vm/vm_object.c
Show First 20 Lines • Show All 2,089 Lines • ▼ Show 20 Lines | again: | ||||
/* | /* | ||||
* Here, the variable "p" is either (1) the page with the least pindex | * Here, the variable "p" is either (1) the page with the least pindex | ||||
* greater than or equal to the parameter "start" or (2) NULL. | * greater than or equal to the parameter "start" or (2) NULL. | ||||
*/ | */ | ||||
for (; p != NULL && (p->pindex < end || end == 0); p = next) { | for (; p != NULL && (p->pindex < end || end == 0); p = next) { | ||||
next = TAILQ_NEXT(p, listq); | next = TAILQ_NEXT(p, listq); | ||||
/* | /* | ||||
* Skip invalid pages if asked to do so. Try to avoid acquiring | |||||
* the busy lock, as some consumers rely on this to avoid | |||||
* deadlocks. | |||||
* | |||||
* A thread may concurrently transition the page from invalid to | |||||
* valid using only the busy lock, so the result of this check | |||||
* is immediately stale. It is up to consumers to handle this, | |||||
* for instance by ensuring that all invalid->valid transitions | |||||
* happen with a mutex held, as may be possible for a | |||||
* filesystem. | |||||
*/ | |||||
if ((options & OBJPR_VALIDONLY) != 0 && vm_page_none_valid(p)) | |||||
continue; | |||||
/* | |||||
* If the page is wired for any reason besides the existence | * If the page is wired for any reason besides the existence | ||||
* of managed, wired mappings, then it cannot be freed. For | * of managed, wired mappings, then it cannot be freed. For | ||||
* example, fictitious pages, which represent device memory, | * example, fictitious pages, which represent device memory, | ||||
* are inherently wired and cannot be freed. They can, | * are inherently wired and cannot be freed. They can, | ||||
* however, be invalidated if the option OBJPR_CLEANONLY is | * however, be invalidated if the option OBJPR_CLEANONLY is | ||||
* not specified. | * not specified. | ||||
*/ | */ | ||||
if (vm_page_tryxbusy(p) == 0) { | if (vm_page_tryxbusy(p) == 0) { | ||||
vm_page_sleep_if_busy(p, "vmopar"); | vm_page_sleep_if_busy(p, "vmopar"); | ||||
goto again; | goto again; | ||||
} | |||||
if ((options & OBJPR_VALIDONLY) != 0 && vm_page_none_valid(p)) { | |||||
kib: Would this still cause the issue with partially valid pages at EOF? If the page is not fully… | |||||
markjAuthorUnsubmitted Done Inline ActionsI believe ZFS vnode pages are never partially valid. This is asserted in several places which maintain coherence between the page cache and the DMU. See page_busy() or dmu_read_pages(). Truncation (currently) does not mark pages partially invalid, see the last comment in vnode_pager_subpage_purge(). Maybe it is a somewhat fragile assumption, but it exists already. markj: I believe ZFS vnode pages are never partially valid. This is asserted in several places which… | |||||
vm_page_xunbusy(p); | |||||
continue; | |||||
} | } | ||||
if (vm_page_wired(p)) { | if (vm_page_wired(p)) { | ||||
wired: | wired: | ||||
if ((options & OBJPR_NOTMAPPED) == 0 && | if ((options & OBJPR_NOTMAPPED) == 0 && | ||||
object->ref_count != 0) | object->ref_count != 0) | ||||
pmap_remove_all(p); | pmap_remove_all(p); | ||||
if ((options & OBJPR_CLEANONLY) == 0) { | if ((options & OBJPR_CLEANONLY) == 0) { | ||||
vm_page_invalid(p); | vm_page_invalid(p); | ||||
▲ Show 20 Lines • Show All 741 Lines • Show Last 20 Lines |
Would this still cause the issue with partially valid pages at EOF? If the page is not fully valid, vm_fault() still calls into pager, and pager calls into VOP. The validation of the rest of the page is performed by vm_pager_get_pages() after pgo_getpages() validated page up to EOF.
It might be simplest to avoid this issue at all by unconditionally doing vm_page_zero_invalid() in zfs VOP_GETPAGES().