xref: /minix3/minix/servers/vm/pagefaults.c (revision f202792edf8f6ad088098ebce355e08c37bd92d0)
1433d6423SLionel Sambuc 
2433d6423SLionel Sambuc #define _SYSTEM 1
3433d6423SLionel Sambuc 
4433d6423SLionel Sambuc #include <minix/callnr.h>
5433d6423SLionel Sambuc #include <minix/com.h>
6433d6423SLionel Sambuc #include <minix/config.h>
7433d6423SLionel Sambuc #include <minix/const.h>
8433d6423SLionel Sambuc #include <minix/ds.h>
9433d6423SLionel Sambuc #include <minix/endpoint.h>
10433d6423SLionel Sambuc #include <minix/minlib.h>
11433d6423SLionel Sambuc #include <minix/type.h>
12433d6423SLionel Sambuc #include <minix/ipc.h>
13433d6423SLionel Sambuc #include <minix/sysutil.h>
14433d6423SLionel Sambuc #include <minix/syslib.h>
15433d6423SLionel Sambuc #include <minix/safecopies.h>
16433d6423SLionel Sambuc #include <minix/bitmap.h>
17433d6423SLionel Sambuc #include <minix/vfsif.h>
18433d6423SLionel Sambuc 
19433d6423SLionel Sambuc #include <machine/vmparam.h>
20433d6423SLionel Sambuc 
21433d6423SLionel Sambuc #include <errno.h>
22433d6423SLionel Sambuc #include <string.h>
23433d6423SLionel Sambuc #include <env.h>
24433d6423SLionel Sambuc #include <stdio.h>
25433d6423SLionel Sambuc #include <fcntl.h>
26433d6423SLionel Sambuc #include <signal.h>
27433d6423SLionel Sambuc #include <assert.h>
28433d6423SLionel Sambuc 
29433d6423SLionel Sambuc #include "glo.h"
30433d6423SLionel Sambuc #include "proto.h"
31433d6423SLionel Sambuc #include "util.h"
32433d6423SLionel Sambuc #include "region.h"
33433d6423SLionel Sambuc 
34433d6423SLionel Sambuc struct pf_state {
35433d6423SLionel Sambuc         endpoint_t ep;
36433d6423SLionel Sambuc         vir_bytes vaddr;
37433d6423SLionel Sambuc 	u32_t err;
38433d6423SLionel Sambuc };
39433d6423SLionel Sambuc 
40433d6423SLionel Sambuc struct hm_state {
41433d6423SLionel Sambuc 	endpoint_t caller;	/* KERNEL or process? if NONE, no callback */
42433d6423SLionel Sambuc 	endpoint_t requestor;	/* on behalf of whom? */
43433d6423SLionel Sambuc 	int transid;		/* VFS transaction id if valid */
44433d6423SLionel Sambuc 	struct vmproc *vmp;	/* target address space */
45433d6423SLionel Sambuc 	vir_bytes mem, len;	/* memory range */
46433d6423SLionel Sambuc 	int wrflag;		/* must it be writable or not */
47433d6423SLionel Sambuc 	int valid;		/* sanity check */
48433d6423SLionel Sambuc 	int vfs_avail;		/* may vfs be called to satisfy this range? */
49433d6423SLionel Sambuc #define VALID	0xc0ff1
50433d6423SLionel Sambuc };
51433d6423SLionel Sambuc 
52433d6423SLionel Sambuc static void handle_memory_continue(struct vmproc *vmp, message *m,
53433d6423SLionel Sambuc         void *arg, void *statearg);
54*f202792eSDavid van Moolenbroek static int handle_memory_step(struct hm_state *hmstate, int retry);
55433d6423SLionel Sambuc static void handle_memory_final(struct hm_state *state, int result);
56433d6423SLionel Sambuc 
57433d6423SLionel Sambuc /*===========================================================================*
58433d6423SLionel Sambuc  *				pf_errstr	     		     	*
59433d6423SLionel Sambuc  *===========================================================================*/
60433d6423SLionel Sambuc char *pf_errstr(u32_t err)
61433d6423SLionel Sambuc {
62433d6423SLionel Sambuc 	static char buf[100];
63433d6423SLionel Sambuc 
64433d6423SLionel Sambuc 	sprintf(buf, "err 0x%lx ", (long)err);
65433d6423SLionel Sambuc 	if(PFERR_NOPAGE(err)) strcat(buf, "nopage ");
66433d6423SLionel Sambuc 	if(PFERR_PROT(err)) strcat(buf, "protection ");
67433d6423SLionel Sambuc 	if(PFERR_WRITE(err)) strcat(buf, "write");
68433d6423SLionel Sambuc 	if(PFERR_READ(err)) strcat(buf, "read");
69433d6423SLionel Sambuc 
70433d6423SLionel Sambuc 	return buf;
71433d6423SLionel Sambuc }
72433d6423SLionel Sambuc 
73433d6423SLionel Sambuc static void pf_cont(struct vmproc *vmp, message *m, void *arg, void *statearg);
74433d6423SLionel Sambuc 
75433d6423SLionel Sambuc static void handle_memory_continue(struct vmproc *vmp, message *m, void *arg, void *statearg);
76433d6423SLionel Sambuc 
77433d6423SLionel Sambuc static void handle_pagefault(endpoint_t ep, vir_bytes addr, u32_t err, int retry)
78433d6423SLionel Sambuc {
79433d6423SLionel Sambuc 	struct vmproc *vmp;
80433d6423SLionel Sambuc 	int s, result;
81433d6423SLionel Sambuc 	struct vir_region *region;
82433d6423SLionel Sambuc 	vir_bytes offset;
83433d6423SLionel Sambuc 	int p, wr = PFERR_WRITE(err);
84433d6423SLionel Sambuc 	int io = 0;
85433d6423SLionel Sambuc 
86433d6423SLionel Sambuc 	if(vm_isokendpt(ep, &p) != OK)
87433d6423SLionel Sambuc 		panic("handle_pagefault: endpoint wrong: %d", ep);
88433d6423SLionel Sambuc 
89433d6423SLionel Sambuc 	vmp = &vmproc[p];
90433d6423SLionel Sambuc 	assert(vmp->vm_flags & VMF_INUSE);
91433d6423SLionel Sambuc 
92433d6423SLionel Sambuc 	/* See if address is valid at all. */
93433d6423SLionel Sambuc 	if(!(region = map_lookup(vmp, addr, NULL))) {
94433d6423SLionel Sambuc 		if(PFERR_PROT(err))  {
95433d6423SLionel Sambuc 			printf("VM: pagefault: SIGSEGV %d protected addr 0x%lx; %s\n",
96433d6423SLionel Sambuc 				ep, addr, pf_errstr(err));
97433d6423SLionel Sambuc 		} else {
98433d6423SLionel Sambuc 			assert(PFERR_NOPAGE(err));
99433d6423SLionel Sambuc 			printf("VM: pagefault: SIGSEGV %d bad addr 0x%lx; %s\n",
100433d6423SLionel Sambuc 					ep, addr, pf_errstr(err));
101433d6423SLionel Sambuc 			sys_diagctl_stacktrace(ep);
102433d6423SLionel Sambuc 		}
103433d6423SLionel Sambuc 		if((s=sys_kill(vmp->vm_endpoint, SIGSEGV)) != OK)
104433d6423SLionel Sambuc 			panic("sys_kill failed: %d", s);
105433d6423SLionel Sambuc 		if((s=sys_vmctl(ep, VMCTL_CLEAR_PAGEFAULT, 0 /*unused*/)) != OK)
106433d6423SLionel Sambuc 			panic("do_pagefaults: sys_vmctl failed: %d", ep);
107433d6423SLionel Sambuc 		return;
108433d6423SLionel Sambuc 	}
109433d6423SLionel Sambuc 
110433d6423SLionel Sambuc 	/* If process was writing, see if it's writable. */
111433d6423SLionel Sambuc 	if(!(region->flags & VR_WRITABLE) && wr) {
112433d6423SLionel Sambuc 		printf("VM: pagefault: SIGSEGV %d ro map 0x%lx %s\n",
113433d6423SLionel Sambuc 				ep, addr, pf_errstr(err));
114433d6423SLionel Sambuc 		if((s=sys_kill(vmp->vm_endpoint, SIGSEGV)) != OK)
115433d6423SLionel Sambuc 			panic("sys_kill failed: %d", s);
116433d6423SLionel Sambuc 		if((s=sys_vmctl(ep, VMCTL_CLEAR_PAGEFAULT, 0 /*unused*/)) != OK)
117433d6423SLionel Sambuc 			panic("do_pagefaults: sys_vmctl failed: %d", ep);
118433d6423SLionel Sambuc 		return;
119433d6423SLionel Sambuc 	}
120433d6423SLionel Sambuc 
121433d6423SLionel Sambuc 	assert(addr >= region->vaddr);
122433d6423SLionel Sambuc 	offset = addr - region->vaddr;
123433d6423SLionel Sambuc 
124433d6423SLionel Sambuc 	/* Access is allowed; handle it. */
125433d6423SLionel Sambuc 	if(retry) {
126433d6423SLionel Sambuc 		result = map_pf(vmp, region, offset, wr, NULL, NULL, 0, &io);
127433d6423SLionel Sambuc 		assert(result != SUSPEND);
128433d6423SLionel Sambuc 	} else {
129433d6423SLionel Sambuc 		struct pf_state state;
130433d6423SLionel Sambuc 		state.ep = ep;
131433d6423SLionel Sambuc 		state.vaddr = addr;
132433d6423SLionel Sambuc 		state.err = err;
133433d6423SLionel Sambuc 		result = map_pf(vmp, region, offset, wr, pf_cont,
134433d6423SLionel Sambuc 			&state, sizeof(state), &io);
135433d6423SLionel Sambuc 	}
136433d6423SLionel Sambuc 	if (io)
137433d6423SLionel Sambuc 		vmp->vm_major_page_fault++;
138433d6423SLionel Sambuc 	else
139433d6423SLionel Sambuc 		vmp->vm_minor_page_fault++;
140433d6423SLionel Sambuc 
141433d6423SLionel Sambuc 	if(result == SUSPEND) {
142433d6423SLionel Sambuc 		return;
143433d6423SLionel Sambuc 	}
144433d6423SLionel Sambuc 
145433d6423SLionel Sambuc 	if(result != OK) {
146433d6423SLionel Sambuc 		printf("VM: pagefault: SIGSEGV %d pagefault not handled\n", ep);
147433d6423SLionel Sambuc 		if((s=sys_kill(ep, SIGSEGV)) != OK)
148433d6423SLionel Sambuc 			panic("sys_kill failed: %d", s);
149433d6423SLionel Sambuc 		if((s=sys_vmctl(ep, VMCTL_CLEAR_PAGEFAULT, 0 /*unused*/)) != OK)
150433d6423SLionel Sambuc 			panic("do_pagefaults: sys_vmctl failed: %d", ep);
151433d6423SLionel Sambuc 		return;
152433d6423SLionel Sambuc 	}
153433d6423SLionel Sambuc 
154433d6423SLionel Sambuc         pt_clearmapcache();
155433d6423SLionel Sambuc 
156433d6423SLionel Sambuc 	/* Pagefault is handled, so now reactivate the process. */
157433d6423SLionel Sambuc 	if((s=sys_vmctl(ep, VMCTL_CLEAR_PAGEFAULT, 0 /*unused*/)) != OK)
158433d6423SLionel Sambuc 		panic("do_pagefaults: sys_vmctl failed: %d", ep);
159433d6423SLionel Sambuc }
160433d6423SLionel Sambuc 
161433d6423SLionel Sambuc 
162433d6423SLionel Sambuc static void pf_cont(struct vmproc *vmp, message *m,
163433d6423SLionel Sambuc         void *arg, void *statearg)
164433d6423SLionel Sambuc {
165433d6423SLionel Sambuc 	struct pf_state *state = statearg;
166433d6423SLionel Sambuc 	int p;
167433d6423SLionel Sambuc 	if(vm_isokendpt(state->ep, &p) != OK) return;	/* signal */
168433d6423SLionel Sambuc 	handle_pagefault(state->ep, state->vaddr, state->err, 1);
169433d6423SLionel Sambuc }
170433d6423SLionel Sambuc 
171433d6423SLionel Sambuc static void handle_memory_continue(struct vmproc *vmp, message *m,
172433d6423SLionel Sambuc         void *arg, void *statearg)
173433d6423SLionel Sambuc {
174433d6423SLionel Sambuc 	int r;
175433d6423SLionel Sambuc 	struct hm_state *state = statearg;
176433d6423SLionel Sambuc 	assert(state);
177433d6423SLionel Sambuc 	assert(state->caller != NONE);
178433d6423SLionel Sambuc 	assert(state->valid == VALID);
179433d6423SLionel Sambuc 
180433d6423SLionel Sambuc 	if(m->VMV_RESULT != OK) {
181433d6423SLionel Sambuc 		printf("VM: handle_memory_continue: vfs request failed\n");
182433d6423SLionel Sambuc 		handle_memory_final(state, m->VMV_RESULT);
183433d6423SLionel Sambuc 		return;
184433d6423SLionel Sambuc 	}
185433d6423SLionel Sambuc 
186*f202792eSDavid van Moolenbroek 	r = handle_memory_step(state, TRUE /*retry*/);
187433d6423SLionel Sambuc 
188433d6423SLionel Sambuc 	assert(state->valid == VALID);
189433d6423SLionel Sambuc 
190433d6423SLionel Sambuc 	if(r == SUSPEND) {
191433d6423SLionel Sambuc 		return;
192433d6423SLionel Sambuc 	}
193433d6423SLionel Sambuc 
194433d6423SLionel Sambuc 	assert(state->valid == VALID);
195433d6423SLionel Sambuc 
196433d6423SLionel Sambuc 	handle_memory_final(state, r);
197433d6423SLionel Sambuc }
198433d6423SLionel Sambuc 
199433d6423SLionel Sambuc static void handle_memory_final(struct hm_state *state, int result)
200433d6423SLionel Sambuc {
201433d6423SLionel Sambuc 	int r;
202433d6423SLionel Sambuc 
203433d6423SLionel Sambuc 	assert(state);
204433d6423SLionel Sambuc 	assert(state->valid == VALID);
205433d6423SLionel Sambuc 
206433d6423SLionel Sambuc 	if(state->caller == KERNEL) {
207433d6423SLionel Sambuc 		if((r=sys_vmctl(state->requestor, VMCTL_MEMREQ_REPLY, result)) != OK)
208433d6423SLionel Sambuc 			panic("handle_memory_continue: sys_vmctl failed: %d", r);
209433d6423SLionel Sambuc 	} else if(state->caller != NONE) {
210433d6423SLionel Sambuc 		/* Send a reply msg */
211433d6423SLionel Sambuc 		message msg;
212433d6423SLionel Sambuc 		memset(&msg, 0, sizeof(msg));
213433d6423SLionel Sambuc 		msg.m_type = result;
214433d6423SLionel Sambuc 
215433d6423SLionel Sambuc 		if(IS_VFS_FS_TRANSID(state->transid)) {
216433d6423SLionel Sambuc 			assert(state->caller == VFS_PROC_NR);
217433d6423SLionel Sambuc 			/* If a transaction ID was set, reset it */
218433d6423SLionel Sambuc 			msg.m_type = TRNS_ADD_ID(msg.m_type, state->transid);
219433d6423SLionel Sambuc 		}
220433d6423SLionel Sambuc 
221433d6423SLionel Sambuc 		if(asynsend3(state->caller, &msg, 0) != OK) {
222433d6423SLionel Sambuc 			panic("handle_memory_final: asynsend3 failed");
223433d6423SLionel Sambuc 		}
224433d6423SLionel Sambuc 
225433d6423SLionel Sambuc 		assert(state->valid == VALID);
226433d6423SLionel Sambuc 
227433d6423SLionel Sambuc 		/* fail fast if anyone tries to access this state again */
228433d6423SLionel Sambuc 		memset(state, 0, sizeof(*state));
229433d6423SLionel Sambuc 	}
230433d6423SLionel Sambuc }
231433d6423SLionel Sambuc 
232433d6423SLionel Sambuc /*===========================================================================*
233433d6423SLionel Sambuc  *				do_pagefaults	     		     *
234433d6423SLionel Sambuc  *===========================================================================*/
235433d6423SLionel Sambuc void do_pagefaults(message *m)
236433d6423SLionel Sambuc {
237433d6423SLionel Sambuc 	handle_pagefault(m->m_source, m->VPF_ADDR, m->VPF_FLAGS, 0);
238433d6423SLionel Sambuc }
239433d6423SLionel Sambuc 
240433d6423SLionel Sambuc int handle_memory_once(struct vmproc *vmp, vir_bytes mem, vir_bytes len,
241433d6423SLionel Sambuc 	int wrflag)
242433d6423SLionel Sambuc {
243433d6423SLionel Sambuc 	int r;
244433d6423SLionel Sambuc 	r = handle_memory_start(vmp, mem, len, wrflag, NONE, NONE, 0, 0);
245433d6423SLionel Sambuc 	assert(r != SUSPEND);
246433d6423SLionel Sambuc 	return r;
247433d6423SLionel Sambuc }
248433d6423SLionel Sambuc 
249433d6423SLionel Sambuc int handle_memory_start(struct vmproc *vmp, vir_bytes mem, vir_bytes len,
250433d6423SLionel Sambuc 	int wrflag, endpoint_t caller, endpoint_t requestor, int transid,
251433d6423SLionel Sambuc 	int vfs_avail)
252433d6423SLionel Sambuc {
253433d6423SLionel Sambuc 	int r;
254433d6423SLionel Sambuc 	struct hm_state state;
255433d6423SLionel Sambuc 	vir_bytes o;
256433d6423SLionel Sambuc 
257433d6423SLionel Sambuc 	if((o = mem % PAGE_SIZE)) {
258433d6423SLionel Sambuc 		mem -= o;
259433d6423SLionel Sambuc 		len += o;
260433d6423SLionel Sambuc 	}
261433d6423SLionel Sambuc 
262433d6423SLionel Sambuc 	len = roundup(len, PAGE_SIZE);
263433d6423SLionel Sambuc 
264433d6423SLionel Sambuc 	state.vmp = vmp;
265433d6423SLionel Sambuc 	state.mem = mem;
266433d6423SLionel Sambuc 	state.len = len;
267433d6423SLionel Sambuc 	state.wrflag = wrflag;
268433d6423SLionel Sambuc 	state.requestor = requestor;
269433d6423SLionel Sambuc 	state.caller = caller;
270433d6423SLionel Sambuc 	state.transid = transid;
271433d6423SLionel Sambuc 	state.valid = VALID;
272433d6423SLionel Sambuc 	state.vfs_avail = vfs_avail;
273433d6423SLionel Sambuc 
274*f202792eSDavid van Moolenbroek 	r = handle_memory_step(&state, FALSE /*retry*/);
275433d6423SLionel Sambuc 
276433d6423SLionel Sambuc 	if(r == SUSPEND) {
277433d6423SLionel Sambuc 		assert(caller != NONE);
278433d6423SLionel Sambuc 		assert(vfs_avail);
279433d6423SLionel Sambuc 	} else {
280433d6423SLionel Sambuc 		handle_memory_final(&state, r);
281433d6423SLionel Sambuc 	}
282433d6423SLionel Sambuc 
283433d6423SLionel Sambuc 	return r;
284433d6423SLionel Sambuc }
285433d6423SLionel Sambuc 
286433d6423SLionel Sambuc /*===========================================================================*
287433d6423SLionel Sambuc  *				   do_memory	     			     *
288433d6423SLionel Sambuc  *===========================================================================*/
289433d6423SLionel Sambuc void do_memory(void)
290433d6423SLionel Sambuc {
291433d6423SLionel Sambuc 	endpoint_t who, who_s, requestor;
292433d6423SLionel Sambuc 	vir_bytes mem, mem_s;
293433d6423SLionel Sambuc 	vir_bytes len;
294433d6423SLionel Sambuc 	int wrflag;
295433d6423SLionel Sambuc 
296433d6423SLionel Sambuc 	while(1) {
297433d6423SLionel Sambuc 		int p, r = OK;
298433d6423SLionel Sambuc 		struct vmproc *vmp;
299433d6423SLionel Sambuc 
300433d6423SLionel Sambuc 		r = sys_vmctl_get_memreq(&who, &mem, &len, &wrflag, &who_s,
301433d6423SLionel Sambuc 			&mem_s, &requestor);
302433d6423SLionel Sambuc 
303433d6423SLionel Sambuc 		switch(r) {
304433d6423SLionel Sambuc 		case VMPTYPE_CHECK:
305433d6423SLionel Sambuc 		{
306433d6423SLionel Sambuc 			int transid = 0;
307433d6423SLionel Sambuc 			int vfs_avail;
308433d6423SLionel Sambuc 
309433d6423SLionel Sambuc 			if(vm_isokendpt(who, &p) != OK)
310433d6423SLionel Sambuc 				panic("do_memory: bad endpoint: %d", who);
311433d6423SLionel Sambuc 			vmp = &vmproc[p];
312433d6423SLionel Sambuc 
313433d6423SLionel Sambuc 			assert(!IS_VFS_FS_TRANSID(transid));
314433d6423SLionel Sambuc 
315433d6423SLionel Sambuc 			/* is VFS blocked? */
316433d6423SLionel Sambuc 			if(requestor == VFS_PROC_NR) vfs_avail = 0;
317433d6423SLionel Sambuc 			else vfs_avail = 1;
318433d6423SLionel Sambuc 
319433d6423SLionel Sambuc 			handle_memory_start(vmp, mem, len, wrflag,
320433d6423SLionel Sambuc 				KERNEL, requestor, transid, vfs_avail);
321433d6423SLionel Sambuc 
322433d6423SLionel Sambuc 			break;
323433d6423SLionel Sambuc 		}
324433d6423SLionel Sambuc 
325433d6423SLionel Sambuc 		default:
326433d6423SLionel Sambuc 			return;
327433d6423SLionel Sambuc 		}
328433d6423SLionel Sambuc 	}
329433d6423SLionel Sambuc }
330433d6423SLionel Sambuc 
331*f202792eSDavid van Moolenbroek static int handle_memory_step(struct hm_state *hmstate, int retry)
332433d6423SLionel Sambuc {
333433d6423SLionel Sambuc 	struct vir_region *region;
334*f202792eSDavid van Moolenbroek 	vir_bytes offset, length, sublen;
335*f202792eSDavid van Moolenbroek 	int r;
336433d6423SLionel Sambuc 
337433d6423SLionel Sambuc 	/* Page-align memory and length. */
338433d6423SLionel Sambuc 	assert(hmstate);
339433d6423SLionel Sambuc 	assert(hmstate->valid == VALID);
340433d6423SLionel Sambuc 	assert(!(hmstate->mem % VM_PAGE_SIZE));
341433d6423SLionel Sambuc 	assert(!(hmstate->len % VM_PAGE_SIZE));
342433d6423SLionel Sambuc 
343433d6423SLionel Sambuc 	while(hmstate->len > 0) {
344433d6423SLionel Sambuc 		if(!(region = map_lookup(hmstate->vmp, hmstate->mem, NULL))) {
345433d6423SLionel Sambuc #if VERBOSE
346433d6423SLionel Sambuc 			map_printmap(hmstate->vmp);
347433d6423SLionel Sambuc 			printf("VM: do_memory: memory doesn't exist\n");
348433d6423SLionel Sambuc #endif
349433d6423SLionel Sambuc 			return EFAULT;
350433d6423SLionel Sambuc 		} else if(!(region->flags & VR_WRITABLE) && hmstate->wrflag) {
351433d6423SLionel Sambuc #if VERBOSE
352433d6423SLionel Sambuc 			printf("VM: do_memory: write to unwritable map\n");
353433d6423SLionel Sambuc #endif
354433d6423SLionel Sambuc 			return EFAULT;
355*f202792eSDavid van Moolenbroek 		}
356*f202792eSDavid van Moolenbroek 
357433d6423SLionel Sambuc 		assert(region->vaddr <= hmstate->mem);
358433d6423SLionel Sambuc 		assert(!(region->vaddr % VM_PAGE_SIZE));
359433d6423SLionel Sambuc 		offset = hmstate->mem - region->vaddr;
360*f202792eSDavid van Moolenbroek 		length = hmstate->len;
361*f202792eSDavid van Moolenbroek 		if (offset + length > region->length)
362*f202792eSDavid van Moolenbroek 			length = region->length - offset;
363433d6423SLionel Sambuc 
364*f202792eSDavid van Moolenbroek 		/*
365*f202792eSDavid van Moolenbroek 		 * Handle one page at a time.  While it seems beneficial to
366*f202792eSDavid van Moolenbroek 		 * handle multiple pages in one go, the opposite is true:
367*f202792eSDavid van Moolenbroek 		 * map_handle_memory will handle one page at a time anyway, and
368*f202792eSDavid van Moolenbroek 		 * if we give it the whole range multiple times, it will have
369*f202792eSDavid van Moolenbroek 		 * to recheck pages it already handled.  In addition, in order
370*f202792eSDavid van Moolenbroek 		 * to handle one-shot pages, we need to know whether we are
371*f202792eSDavid van Moolenbroek 		 * retrying a single page, and that is not possible if this is
372*f202792eSDavid van Moolenbroek 		 * hidden in map_handle_memory.
373*f202792eSDavid van Moolenbroek 		 */
374*f202792eSDavid van Moolenbroek 		while (length > 0) {
375*f202792eSDavid van Moolenbroek 			sublen = VM_PAGE_SIZE;
376*f202792eSDavid van Moolenbroek 
377*f202792eSDavid van Moolenbroek 			assert(sublen <= length);
378*f202792eSDavid van Moolenbroek 			assert(offset + sublen <= region->length);
379*f202792eSDavid van Moolenbroek 
380*f202792eSDavid van Moolenbroek 			/*
381*f202792eSDavid van Moolenbroek 			 * Upon the second try for this range, do not allow
382*f202792eSDavid van Moolenbroek 			 * calling into VFS again.  This prevents eternal loops
383*f202792eSDavid van Moolenbroek 			 * in case the FS messes up, and allows one-shot pages
384*f202792eSDavid van Moolenbroek 			 * to be mapped in on the second call.
385*f202792eSDavid van Moolenbroek 			 */
386433d6423SLionel Sambuc 			if((region->def_memtype == &mem_type_mappedfile &&
387*f202792eSDavid van Moolenbroek 			    (!hmstate->vfs_avail || retry)) ||
388*f202792eSDavid van Moolenbroek 			    hmstate->caller == NONE) {
389*f202792eSDavid van Moolenbroek 				r = map_handle_memory(hmstate->vmp, region,
390*f202792eSDavid van Moolenbroek 				    offset, sublen, hmstate->wrflag, NULL,
391*f202792eSDavid van Moolenbroek 				    NULL, 0);
392433d6423SLionel Sambuc 				assert(r != SUSPEND);
393433d6423SLionel Sambuc 			} else {
394*f202792eSDavid van Moolenbroek 				r = map_handle_memory(hmstate->vmp, region,
395*f202792eSDavid van Moolenbroek 				    offset, sublen, hmstate->wrflag,
396*f202792eSDavid van Moolenbroek 				    handle_memory_continue, hmstate,
397*f202792eSDavid van Moolenbroek 				    sizeof(*hmstate));
398433d6423SLionel Sambuc 			}
399433d6423SLionel Sambuc 
400433d6423SLionel Sambuc 			if(r != OK) return r;
401433d6423SLionel Sambuc 
402433d6423SLionel Sambuc 			hmstate->len -= sublen;
403433d6423SLionel Sambuc 			hmstate->mem += sublen;
404*f202792eSDavid van Moolenbroek 
405*f202792eSDavid van Moolenbroek 			offset += sublen;
406*f202792eSDavid van Moolenbroek 			length -= sublen;
407*f202792eSDavid van Moolenbroek 			retry = FALSE;
408433d6423SLionel Sambuc 		}
409433d6423SLionel Sambuc 	}
410433d6423SLionel Sambuc 
411433d6423SLionel Sambuc 	return OK;
412433d6423SLionel Sambuc }
413433d6423SLionel Sambuc 
414