1 | /* $NetBSD: uvm_io.c,v 1.28 2016/05/25 17:43:58 christos Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 1997 Charles D. Cranor and Washington University. |
5 | * All rights reserved. |
6 | * |
7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions |
9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. |
15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
21 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
22 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | * |
27 | * from: Id: uvm_io.c,v 1.1.2.2 1997/12/30 12:02:00 mrg Exp |
28 | */ |
29 | |
30 | /* |
31 | * uvm_io.c: uvm i/o ops |
32 | */ |
33 | |
34 | #include <sys/cdefs.h> |
35 | __KERNEL_RCSID(0, "$NetBSD: uvm_io.c,v 1.28 2016/05/25 17:43:58 christos Exp $" ); |
36 | |
37 | #include <sys/param.h> |
38 | #include <sys/systm.h> |
39 | #include <sys/mman.h> |
40 | #include <sys/uio.h> |
41 | |
42 | #include <uvm/uvm.h> |
43 | |
44 | /* |
45 | * functions |
46 | */ |
47 | |
48 | /* |
49 | * uvm_io: perform I/O on a map |
50 | * |
51 | * => caller must have a reference to "map" so that it doesn't go away |
52 | * while we are working. |
53 | */ |
54 | |
55 | int |
56 | uvm_io(struct vm_map *map, struct uio *uio, int flags) |
57 | { |
58 | vaddr_t baseva, endva, pageoffset, kva; |
59 | vsize_t chunksz, togo, sz; |
60 | struct vm_map_entry *dead_entries; |
61 | int error; |
62 | |
63 | /* |
64 | * step 0: sanity checks and set up for copy loop. start with a |
65 | * large chunk size. if we have trouble finding vm space we will |
66 | * reduce it. |
67 | */ |
68 | |
69 | if (uio->uio_resid == 0) |
70 | return(0); |
71 | togo = uio->uio_resid; |
72 | |
73 | baseva = (vaddr_t) uio->uio_offset; |
74 | endva = baseva + (togo - 1); |
75 | |
76 | if (endva < baseva) /* wrap around? */ |
77 | return(EIO); |
78 | |
79 | if (baseva >= VM_MAXUSER_ADDRESS) |
80 | return(0); |
81 | if (endva >= VM_MAXUSER_ADDRESS) |
82 | /* EOF truncate */ |
83 | togo = togo - (endva - VM_MAXUSER_ADDRESS + 1); |
84 | pageoffset = baseva & PAGE_MASK; |
85 | baseva = trunc_page(baseva); |
86 | chunksz = MIN(round_page(togo + pageoffset), trunc_page(MAXPHYS)); |
87 | error = 0; |
88 | |
89 | flags |= UVM_EXTRACT_QREF | UVM_EXTRACT_CONTIG | UVM_EXTRACT_FIXPROT; |
90 | /* |
91 | * step 1: main loop... while we've got data to move |
92 | */ |
93 | |
94 | for (/*null*/; togo > 0 ; pageoffset = 0) { |
95 | |
96 | /* |
97 | * step 2: extract mappings from the map into kernel_map |
98 | */ |
99 | |
100 | error = uvm_map_extract(map, baseva, chunksz, kernel_map, &kva, |
101 | flags); |
102 | if (error) { |
103 | |
104 | /* retry with a smaller chunk... */ |
105 | if (error == ENOMEM && chunksz > PAGE_SIZE) { |
106 | chunksz = trunc_page(chunksz / 2); |
107 | if (chunksz < PAGE_SIZE) |
108 | chunksz = PAGE_SIZE; |
109 | continue; |
110 | } |
111 | |
112 | break; |
113 | } |
114 | |
115 | /* |
116 | * step 3: move a chunk of data |
117 | */ |
118 | |
119 | sz = chunksz - pageoffset; |
120 | if (sz > togo) |
121 | sz = togo; |
122 | error = uiomove((void *) (kva + pageoffset), sz, uio); |
123 | togo -= sz; |
124 | baseva += chunksz; |
125 | |
126 | /* |
127 | * step 4: unmap the area of kernel memory |
128 | */ |
129 | |
130 | vm_map_lock(kernel_map); |
131 | uvm_unmap_remove(kernel_map, kva, kva + chunksz, &dead_entries, |
132 | 0); |
133 | vm_map_unlock(kernel_map); |
134 | if (dead_entries != NULL) |
135 | uvm_unmap_detach(dead_entries, AMAP_REFALL); |
136 | |
137 | if (error) |
138 | break; |
139 | } |
140 | return (error); |
141 | } |
142 | |