Changeset View
Changeset View
Standalone View
Standalone View
sys/vm/vm_fault.c
Show First 20 Lines • Show All 117 Lines • ▼ Show 20 Lines | struct faultstate { | ||||
vm_object_t object; | vm_object_t object; | ||||
vm_pindex_t pindex; | vm_pindex_t pindex; | ||||
vm_page_t first_m; | vm_page_t first_m; | ||||
vm_object_t first_object; | vm_object_t first_object; | ||||
vm_pindex_t first_pindex; | vm_pindex_t first_pindex; | ||||
vm_map_t map; | vm_map_t map; | ||||
vm_map_entry_t entry; | vm_map_entry_t entry; | ||||
int lookup_still_valid; | int lookup_still_valid; | ||||
int ra_done; | |||||
struct vnode *vp; | struct vnode *vp; | ||||
}; | }; | ||||
static void vm_fault_dontneed(const struct faultstate *fs, vm_offset_t vaddr, | static void vm_fault_dontneed(const struct faultstate *fs, vm_offset_t vaddr, | ||||
int ahead); | int ahead); | ||||
static void vm_fault_prefault(const struct faultstate *fs, vm_offset_t addra, | static void vm_fault_prefault(const struct faultstate *fs, vm_offset_t addra, | ||||
int backward, int forward); | int backward, int forward); | ||||
▲ Show 20 Lines • Show All 153 Lines • ▼ Show 20 Lines | vm_fault_hold(vm_map_t map, vm_offset_t vaddr, vm_prot_t fault_type, | ||||
int alloc_req, era, faultcount, nera, result; | int alloc_req, era, faultcount, nera, result; | ||||
boolean_t dead, growstack, is_first_object_locked, wired; | boolean_t dead, growstack, is_first_object_locked, wired; | ||||
int map_generation; | int map_generation; | ||||
vm_object_t next_object; | vm_object_t next_object; | ||||
int hardfault; | int hardfault; | ||||
struct faultstate fs; | struct faultstate fs; | ||||
struct vnode *vp; | struct vnode *vp; | ||||
vm_page_t m; | vm_page_t m; | ||||
int ahead, behind, cluster_offset, error, locked; | int ahead, behind, cluster_offset, error, locked, rv; | ||||
u_char behavior; | |||||
hardfault = 0; | hardfault = 0; | ||||
growstack = TRUE; | growstack = TRUE; | ||||
PCPU_INC(cnt.v_vm_faults); | PCPU_INC(cnt.v_vm_faults); | ||||
fs.vp = NULL; | fs.vp = NULL; | ||||
faultcount = 0; | faultcount = 0; | ||||
fs.ra_done = FALSE; | |||||
RetryFault:; | RetryFault:; | ||||
/* | /* | ||||
* Find the backing store object and offset into it to begin the | * Find the backing store object and offset into it to begin the | ||||
* search. | * search. | ||||
*/ | */ | ||||
fs.map = map; | fs.map = map; | ||||
▲ Show 20 Lines • Show All 242 Lines • ▼ Show 20 Lines | readrest: | ||||
* We have either allocated a new page or found an existing | * We have either allocated a new page or found an existing | ||||
* page that is only partially valid. | * page that is only partially valid. | ||||
* | * | ||||
* Attempt to fault-in the page if there is a chance that the | * Attempt to fault-in the page if there is a chance that the | ||||
* pager has it, and potentially fault in additional pages | * pager has it, and potentially fault in additional pages | ||||
* at the same time. | * at the same time. | ||||
*/ | */ | ||||
if (fs.object->type != OBJT_DEFAULT) { | if (fs.object->type != OBJT_DEFAULT) { | ||||
int rv; | if (!fs.lookup_still_valid) { | ||||
u_char behavior = vm_map_entry_behavior(fs.entry); | locked = vm_map_trylock_read(fs.map); | ||||
if (locked) | |||||
fs.lookup_still_valid = TRUE; | |||||
if (!locked || fs.map->timestamp != | |||||
map_generation) { | |||||
release_page(&fs); | |||||
unlock_and_deallocate(&fs); | |||||
goto RetryFault; | |||||
} | |||||
} | |||||
behavior = vm_map_entry_behavior(fs.entry); | |||||
era = fs.entry->read_ahead; | era = fs.entry->read_ahead; | ||||
if (behavior == MAP_ENTRY_BEHAV_RANDOM || | if (behavior == MAP_ENTRY_BEHAV_RANDOM || | ||||
P_KILLED(curproc)) { | P_KILLED(curproc)) { | ||||
behind = 0; | behind = 0; | ||||
nera = 0; | nera = 0; | ||||
ahead = 0; | ahead = 0; | ||||
} else if (behavior == MAP_ENTRY_BEHAV_SEQUENTIAL) { | } else if (behavior == MAP_ENTRY_BEHAV_SEQUENTIAL) { | ||||
behind = 0; | behind = 0; | ||||
nera = VM_FAULT_READ_AHEAD_MAX; | nera = VM_FAULT_READ_AHEAD_MAX; | ||||
ahead = nera; | ahead = nera; | ||||
if (vaddr == fs.entry->next_read) | if (vaddr == fs.entry->next_read && !fs.ra_done) | ||||
vm_fault_dontneed(&fs, vaddr, ahead); | vm_fault_dontneed(&fs, vaddr, ahead); | ||||
} else if (vaddr == fs.entry->next_read) { | } else if (vaddr == fs.entry->next_read) { | ||||
/* | /* | ||||
* This is a sequential fault. Arithmetically | * This is a sequential fault. Arithmetically | ||||
* increase the requested number of pages in | * increase the requested number of pages in | ||||
* the read-ahead window. The requested | * the read-ahead window. The requested | ||||
* number of pages is "# of sequential faults | * number of pages is "# of sequential faults | ||||
* x (read ahead min + 1) + read ahead min" | * x (read ahead min + 1) + read ahead min" | ||||
*/ | */ | ||||
behind = 0; | behind = 0; | ||||
nera = VM_FAULT_READ_AHEAD_MIN; | if (!fs.ra_done) { | ||||
if (era > 0) { | if (era > 0) { | ||||
nera += era + 1; | nera += era + 1; | ||||
alc: Without the initialization of nera (on the old line 584), this "+=" appears problematic. | |||||
if (nera > VM_FAULT_READ_AHEAD_MAX) | if (nera > VM_FAULT_READ_AHEAD_MAX) | ||||
nera = VM_FAULT_READ_AHEAD_MAX; | nera = VM_FAULT_READ_AHEAD_MAX; | ||||
} else | |||||
nera = VM_FAULT_READ_AHEAD_MIN; | |||||
} | } | ||||
ahead = nera; | ahead = nera; | ||||
if (era == VM_FAULT_READ_AHEAD_MAX) | if (era == VM_FAULT_READ_AHEAD_MAX && | ||||
!fs.ra_done) | |||||
vm_fault_dontneed(&fs, vaddr, ahead); | vm_fault_dontneed(&fs, vaddr, ahead); | ||||
} else { | } else { | ||||
/* | /* | ||||
* This is a non-sequential fault. Request a | * This is a non-sequential fault. Request a | ||||
* cluster of pages that is aligned to a | * cluster of pages that is aligned to a | ||||
* VM_FAULT_READ_DEFAULT page offset boundary | * VM_FAULT_READ_DEFAULT page offset boundary | ||||
* within the object. Alignment to a page | * within the object. Alignment to a page | ||||
* offset boundary is more likely to coincide | * offset boundary is more likely to coincide | ||||
* with the underlying file system block than | * with the underlying file system block than | ||||
* alignment to a virtual address boundary. | * alignment to a virtual address boundary. | ||||
*/ | */ | ||||
cluster_offset = fs.pindex % | cluster_offset = fs.pindex % | ||||
VM_FAULT_READ_DEFAULT; | VM_FAULT_READ_DEFAULT; | ||||
behind = ulmin(cluster_offset, | behind = ulmin(cluster_offset, | ||||
atop(vaddr - fs.entry->start)); | atop(vaddr - fs.entry->start)); | ||||
nera = 0; | nera = 0; | ||||
ahead = VM_FAULT_READ_DEFAULT - 1 - | ahead = VM_FAULT_READ_DEFAULT - 1 - | ||||
cluster_offset; | cluster_offset; | ||||
} | } | ||||
ahead = ulmin(ahead, atop(fs.entry->end - vaddr) - 1); | ahead = ulmin(ahead, atop(fs.entry->end - vaddr) - 1); | ||||
if (era != nera) | if (era != nera) | ||||
/* | |||||
* Only read-lock on map is held | |||||
* there. It is fine for other thread | |||||
* faulting on the same entry to race | |||||
* with us for this update, causing | |||||
* some inaccuracy in the read-ahead | |||||
* heuristic. We do not separate two | |||||
* different streams of sequential | |||||
* faults on one entry anyway. | |||||
*/ | |||||
fs.entry->read_ahead = nera; | fs.entry->read_ahead = nera; | ||||
fs.ra_done = TRUE; | |||||
/* | /* | ||||
* Call the pager to retrieve the data, if any, after | * Call the pager to retrieve the data, if any, after | ||||
* releasing the lock on the map. We hold a ref on | * releasing the lock on the map. We hold a ref on | ||||
* fs.object and the pages are exclusive busied. | * fs.object and the pages are exclusive busied. | ||||
*/ | */ | ||||
unlock_map(&fs); | unlock_map(&fs); | ||||
▲ Show 20 Lines • Show All 836 Lines • Show Last 20 Lines |
Without the initialization of nera (on the old line 584), this "+=" appears problematic.