2 /* This file implements the methods of memory-mapped files. */
12 /* These functions are static so as to not pollute the
13 * global namespace, and are accessed through their function
17 static void mappedfile_split(struct vmproc
*vmp
, struct vir_region
*vr
,
18 struct vir_region
*r1
, struct vir_region
*r2
);
19 static int mappedfile_unreference(struct phys_region
*pr
);
20 static int mappedfile_pagefault(struct vmproc
*vmp
, struct vir_region
*region
,
21 struct phys_region
*ph
, int write
, vfs_callback_t callback
, void *state
,
23 static int mappedfile_sanitycheck(struct phys_region
*pr
, const char *file
, int line
);
24 static int mappedfile_writable(struct phys_region
*pr
);
25 static int mappedfile_copy(struct vir_region
*vr
, struct vir_region
*newvr
);
26 static int mappedfile_lowshrink(struct vir_region
*vr
, vir_bytes len
);
27 static void mappedfile_delete(struct vir_region
*region
);
28 static int mappedfile_pt_flags(struct vir_region
*vr
);
30 struct mem_type mem_type_mappedfile
= {
31 .name
= "file-mapped memory",
32 .ev_unreference
= mappedfile_unreference
,
33 .ev_pagefault
= mappedfile_pagefault
,
34 .ev_sanitycheck
= mappedfile_sanitycheck
,
35 .ev_copy
= mappedfile_copy
,
36 .writable
= mappedfile_writable
,
37 .ev_split
= mappedfile_split
,
38 .ev_lowshrink
= mappedfile_lowshrink
,
39 .ev_delete
= mappedfile_delete
,
40 .pt_flags
= mappedfile_pt_flags
,
43 static int mappedfile_pt_flags(struct vir_region
*vr
){
45 return ARM_VM_PTE_CACHED
;
51 static int mappedfile_unreference(struct phys_region
*pr
)
53 assert(pr
->ph
->refcount
== 0);
54 if(pr
->ph
->phys
!= MAP_NONE
)
55 free_mem(ABS2CLICK(pr
->ph
->phys
), 1);
59 static int cow_block(struct vmproc
*vmp
, struct vir_region
*region
,
60 struct phys_region
*ph
, u16_t clearend
)
64 if((r
=mem_cow(region
, ph
, MAP_NONE
, MAP_NONE
)) != OK
) {
65 printf("mappedfile_pagefault: COW failed\n");
69 /* After COW we are a normal piece of anonymous memory. */
70 ph
->memtype
= &mem_type_anon
;
73 phys_bytes phaddr
= ph
->ph
->phys
, po
= VM_PAGE_SIZE
-clearend
;
74 assert(clearend
< VM_PAGE_SIZE
);
76 if(sys_memset(NONE
, 0, phaddr
, clearend
) != OK
) {
77 panic("cow_block: clearend failed\n");
84 static int mappedfile_pagefault(struct vmproc
*vmp
, struct vir_region
*region
,
85 struct phys_region
*ph
, int write
, vfs_callback_t cb
,
86 void *state
, int statelen
, int *io
)
89 int procfd
= region
->param
.file
.fdref
->fd
;
91 allocflags
= vrallocflags(region
->flags
);
93 assert(ph
->ph
->refcount
> 0);
94 assert(region
->param
.file
.inited
);
95 assert(region
->param
.file
.fdref
);
96 assert(region
->param
.file
.fdref
->dev
!= NO_DEV
);
98 /* Totally new block? Create it. */
99 if(ph
->ph
->phys
== MAP_NONE
) {
100 struct cached_page
*cp
;
101 u64_t referenced_offset
=
102 region
->param
.file
.offset
+ ph
->offset
;
103 if(region
->param
.file
.fdref
->ino
== VMC_NO_INODE
) {
104 cp
= find_cached_page_bydev(region
->param
.file
.fdref
->dev
,
105 referenced_offset
, VMC_NO_INODE
, 0, 1);
107 cp
= find_cached_page_byino(region
->param
.file
.fdref
->dev
,
108 region
->param
.file
.fdref
->ino
, referenced_offset
, 1);
112 pb_unreferenced(region
, ph
, 0);
113 pb_link(ph
, cp
->page
, ph
->offset
, region
);
115 if(roundup(ph
->offset
+region
->param
.file
.clearend
,
116 VM_PAGE_SIZE
) >= region
->length
) {
117 result
= cow_block(vmp
, region
, ph
,
118 region
->param
.file
.clearend
);
119 } else if(result
== OK
&& write
) {
120 result
= cow_block(vmp
, region
, ph
, 0);
128 printf("VM: mem_file: no callback, returning EFAULT\n");
130 sys_diagctl_stacktrace(vmp
->vm_endpoint
);
134 if(vfs_request(VMVFSREQ_FDIO
, procfd
, vmp
, referenced_offset
,
135 VM_PAGE_SIZE
, cb
, NULL
, state
, statelen
) != OK
) {
136 printf("VM: mappedfile_pagefault: vfs_request failed\n");
145 printf("mappedfile_pagefault: nonwrite fault?\n");
150 return cow_block(vmp
, region
, ph
, 0);
153 static int mappedfile_sanitycheck(struct phys_region
*pr
, const char *file
, int line
)
155 MYASSERT(usedpages_add(pr
->ph
->phys
, VM_PAGE_SIZE
) == OK
);
159 static int mappedfile_writable(struct phys_region
*pr
)
161 /* We are never writable. */
165 int mappedfile_copy(struct vir_region
*vr
, struct vir_region
*newvr
)
167 assert(vr
->param
.file
.inited
);
168 mappedfile_setfile(newvr
->parent
, newvr
, vr
->param
.file
.fdref
->fd
,
169 vr
->param
.file
.offset
,
170 vr
->param
.file
.fdref
->dev
, vr
->param
.file
.fdref
->ino
,
171 vr
->param
.file
.clearend
, 0, 0);
172 assert(newvr
->param
.file
.inited
);
177 int mappedfile_setfile(struct vmproc
*owner
,
178 struct vir_region
*region
, int fd
, u64_t offset
,
179 dev_t dev
, ino_t ino
, u16_t clearend
, int prefill
, int mayclosefd
)
182 struct fdref
*newref
;
184 newref
= fdref_dedup_or_new(owner
, ino
, dev
, fd
, mayclosefd
);
187 assert(!region
->param
.file
.inited
);
188 assert(dev
!= NO_DEV
);
189 fdref_ref(newref
, region
);
190 region
->param
.file
.offset
= offset
;
191 region
->param
.file
.clearend
= clearend
;
192 region
->param
.file
.inited
= 1;
194 if(!prefill
) return OK
;
196 for(vaddr
= 0; vaddr
< region
->length
; vaddr
+=VM_PAGE_SIZE
) {
197 struct cached_page
*cp
= NULL
;
198 struct phys_region
*pr
;
199 u64_t referenced_offset
= offset
+ vaddr
;
201 if(roundup(vaddr
+region
->param
.file
.clearend
,
202 VM_PAGE_SIZE
) >= region
->length
) {
206 if(ino
== VMC_NO_INODE
) {
207 cp
= find_cached_page_bydev(dev
, referenced_offset
,
210 cp
= find_cached_page_byino(dev
, ino
,
211 referenced_offset
, 1);
214 if(!(pr
= pb_reference(cp
->page
, vaddr
, region
,
215 &mem_type_mappedfile
))) {
216 printf("mappedfile_setfile: pb_reference failed\n");
219 if(map_ph_writept(region
->parent
, region
, pr
) != OK
) {
220 printf("mappedfile_setfile: map_ph_writept failed\n");
228 static void mappedfile_split(struct vmproc
*vmp
, struct vir_region
*vr
,
229 struct vir_region
*r1
, struct vir_region
*r2
)
231 assert(!r1
->param
.file
.inited
);
232 assert(!r2
->param
.file
.inited
);
233 assert(vr
->param
.file
.inited
);
234 assert(r1
->length
+ r2
->length
== vr
->length
);
235 assert(vr
->def_memtype
== &mem_type_mappedfile
);
236 assert(r1
->def_memtype
== &mem_type_mappedfile
);
237 assert(r2
->def_memtype
== &mem_type_mappedfile
);
239 r1
->param
.file
= vr
->param
.file
;
240 r2
->param
.file
= vr
->param
.file
;
242 fdref_ref(vr
->param
.file
.fdref
, r1
);
243 fdref_ref(vr
->param
.file
.fdref
, r2
);
245 r1
->param
.file
.clearend
= 0;
246 r2
->param
.file
.offset
+= r1
->length
;
248 assert(r1
->param
.file
.inited
);
249 assert(r2
->param
.file
.inited
);
252 static int mappedfile_lowshrink(struct vir_region
*vr
, vir_bytes len
)
254 assert(vr
->param
.file
.inited
);
255 vr
->param
.file
.offset
+= len
;
259 static void mappedfile_delete(struct vir_region
*region
)
261 assert(region
->def_memtype
== &mem_type_mappedfile
);
262 assert(region
->param
.file
.inited
);
263 assert(region
->param
.file
.fdref
);
265 region
->param
.file
.inited
= 0;