uvm_readahead.c revision 1.1.2.2 1 1.1.2.2 yamt /* $NetBSD: uvm_readahead.c,v 1.1.2.2 2005/11/15 05:24:48 yamt Exp $ */
2 1.1.2.1 yamt
3 1.1.2.1 yamt /*-
4 1.1.2.1 yamt * Copyright (c)2003, 2005 YAMAMOTO Takashi,
5 1.1.2.1 yamt * All rights reserved.
6 1.1.2.1 yamt *
7 1.1.2.1 yamt * Redistribution and use in source and binary forms, with or without
8 1.1.2.1 yamt * modification, are permitted provided that the following conditions
9 1.1.2.1 yamt * are met:
10 1.1.2.1 yamt * 1. Redistributions of source code must retain the above copyright
11 1.1.2.1 yamt * notice, this list of conditions and the following disclaimer.
12 1.1.2.1 yamt * 2. Redistributions in binary form must reproduce the above copyright
13 1.1.2.1 yamt * notice, this list of conditions and the following disclaimer in the
14 1.1.2.1 yamt * documentation and/or other materials provided with the distribution.
15 1.1.2.1 yamt *
16 1.1.2.1 yamt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 1.1.2.1 yamt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 1.1.2.1 yamt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 1.1.2.1 yamt * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 1.1.2.1 yamt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 1.1.2.1 yamt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 1.1.2.1 yamt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 1.1.2.1 yamt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 1.1.2.1 yamt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 1.1.2.1 yamt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 1.1.2.1 yamt * SUCH DAMAGE.
27 1.1.2.1 yamt */
28 1.1.2.1 yamt
29 1.1.2.1 yamt #include <sys/cdefs.h>
30 1.1.2.2 yamt __KERNEL_RCSID(0, "$NetBSD: uvm_readahead.c,v 1.1.2.2 2005/11/15 05:24:48 yamt Exp $");
31 1.1.2.1 yamt
32 1.1.2.1 yamt #include <sys/param.h>
33 1.1.2.1 yamt #include <sys/pool.h>
34 1.1.2.2 yamt #include <sys/fcntl.h> /* POSIX_FADV_* */
35 1.1.2.1 yamt
36 1.1.2.1 yamt #include <uvm/uvm.h>
37 1.1.2.1 yamt #include <uvm/uvm_readahead.h>
38 1.1.2.1 yamt
39 1.1.2.1 yamt struct uvm_ractx {
40 1.1.2.1 yamt int ra_flags;
41 1.1.2.1 yamt #define RA_VALID 1
42 1.1.2.2 yamt int ra_advice;
43 1.1.2.1 yamt off_t ra_winstart;
44 1.1.2.1 yamt size_t ra_winsize;
45 1.1.2.1 yamt off_t ra_next;
46 1.1.2.1 yamt };
47 1.1.2.1 yamt
48 1.1.2.1 yamt /*
49 1.1.2.1 yamt * XXX tune
50 1.1.2.1 yamt * XXX should consider the amount of memory in the system
51 1.1.2.1 yamt */
52 1.1.2.1 yamt
53 1.1.2.1 yamt #define RA_WINSIZE_INIT MAXPHYS
54 1.1.2.1 yamt #define RA_WINSIZE_MAX (MAXPHYS * 8)
55 1.1.2.2 yamt #define RA_WINSIZE_SEQENTIAL RA_WINSIZE_MAX
56 1.1.2.1 yamt #define RA_MINSIZE (MAXPHYS * 2)
57 1.1.2.1 yamt
58 1.1.2.1 yamt static off_t ra_startio(struct uvm_object *, off_t, size_t);
59 1.1.2.1 yamt static struct uvm_ractx *ra_allocctx(void);
60 1.1.2.1 yamt static void ra_freectx(struct uvm_ractx *);
61 1.1.2.1 yamt
62 1.1.2.1 yamt POOL_INIT(ractx_pool, sizeof(struct uvm_ractx), 0, 0, 0, "ractx",
63 1.1.2.1 yamt &pool_allocator_nointr);
64 1.1.2.1 yamt
65 1.1.2.1 yamt static struct uvm_ractx *
66 1.1.2.1 yamt ra_allocctx(void)
67 1.1.2.1 yamt {
68 1.1.2.1 yamt
69 1.1.2.1 yamt return pool_get(&ractx_pool, PR_NOWAIT);
70 1.1.2.1 yamt }
71 1.1.2.1 yamt
72 1.1.2.1 yamt static void
73 1.1.2.1 yamt ra_freectx(struct uvm_ractx *ra)
74 1.1.2.1 yamt {
75 1.1.2.1 yamt
76 1.1.2.1 yamt pool_put(&ractx_pool, ra);
77 1.1.2.1 yamt }
78 1.1.2.1 yamt
79 1.1.2.1 yamt static off_t
80 1.1.2.1 yamt ra_startio(struct uvm_object *uobj, off_t off, size_t sz)
81 1.1.2.1 yamt {
82 1.1.2.1 yamt const off_t endoff = off + sz;
83 1.1.2.1 yamt
84 1.1.2.1 yamt #if 0
85 1.1.2.1 yamt printf("%s: uobj=%p, off=%" PRIu64 ", endoff=%" PRIu64 "\n",
86 1.1.2.1 yamt __func__, uobj, off, endoff);
87 1.1.2.1 yamt #endif
88 1.1.2.1 yamt off = trunc_page(off);
89 1.1.2.1 yamt while (off < endoff) {
90 1.1.2.1 yamt const size_t chunksize = MAXPHYS;
91 1.1.2.1 yamt int error;
92 1.1.2.1 yamt size_t donebytes;
93 1.1.2.1 yamt int npages;
94 1.1.2.1 yamt int orignpages;
95 1.1.2.1 yamt size_t bytelen;
96 1.1.2.1 yamt
97 1.1.2.1 yamt KASSERT((chunksize & (chunksize - 1)) == 0);
98 1.1.2.1 yamt KASSERT((off & PAGE_MASK) == 0);
99 1.1.2.1 yamt bytelen = ((off + chunksize) & -(off_t)chunksize) - off;
100 1.1.2.1 yamt #if 0
101 1.1.2.1 yamt printf("%s: off=%" PRIu64 ", bytelen=%zu\n",
102 1.1.2.1 yamt __func__, off, bytelen);
103 1.1.2.1 yamt #endif
104 1.1.2.1 yamt KASSERT((bytelen & PAGE_MASK) == 0);
105 1.1.2.1 yamt npages = orignpages = bytelen >> PAGE_SHIFT;
106 1.1.2.1 yamt KASSERT(npages != 0);
107 1.1.2.1 yamt simple_lock(&uobj->vmobjlock);
108 1.1.2.1 yamt error = (*uobj->pgops->pgo_get)(uobj, off, NULL,
109 1.1.2.1 yamt &npages, 0, VM_PROT_READ, 0, 0);
110 1.1.2.1 yamt if (error) {
111 1.1.2.1 yamt #if 1
112 1.1.2.1 yamt if (error != EINVAL) {
113 1.1.2.1 yamt printf("%s: error=%d\n", __func__, error);
114 1.1.2.1 yamt }
115 1.1.2.1 yamt #endif
116 1.1.2.1 yamt break;
117 1.1.2.1 yamt }
118 1.1.2.1 yamt donebytes = orignpages << PAGE_SHIFT;
119 1.1.2.1 yamt off += donebytes;
120 1.1.2.1 yamt if (orignpages != npages) {
121 1.1.2.1 yamt #if 1
122 1.1.2.1 yamt printf("%s: orignpages=%d, npages=%d\n",
123 1.1.2.1 yamt __func__, orignpages, npages);
124 1.1.2.1 yamt #endif
125 1.1.2.1 yamt /* XXX */
126 1.1.2.1 yamt }
127 1.1.2.1 yamt }
128 1.1.2.1 yamt
129 1.1.2.1 yamt return off;
130 1.1.2.1 yamt }
131 1.1.2.1 yamt
132 1.1.2.1 yamt /* ------------------------------------------------------------ */
133 1.1.2.1 yamt
134 1.1.2.1 yamt struct uvm_ractx *
135 1.1.2.2 yamt uvm_ra_allocctx(int advice)
136 1.1.2.1 yamt {
137 1.1.2.1 yamt struct uvm_ractx *ra;
138 1.1.2.1 yamt
139 1.1.2.2 yamt KASSERT(advice == POSIX_FADV_NORMAL ||
140 1.1.2.2 yamt advice == POSIX_FADV_SEQUENTIAL ||
141 1.1.2.2 yamt advice == POSIX_FADV_RANDOM);
142 1.1.2.2 yamt
143 1.1.2.1 yamt ra = ra_allocctx();
144 1.1.2.1 yamt if (ra != NULL) {
145 1.1.2.1 yamt ra->ra_flags = 0;
146 1.1.2.2 yamt ra->ra_winstart = 0;
147 1.1.2.2 yamt ra->ra_advice = advice;
148 1.1.2.1 yamt }
149 1.1.2.1 yamt
150 1.1.2.1 yamt return ra;
151 1.1.2.1 yamt }
152 1.1.2.1 yamt
153 1.1.2.1 yamt void
154 1.1.2.1 yamt uvm_ra_freectx(struct uvm_ractx *ra)
155 1.1.2.1 yamt {
156 1.1.2.1 yamt
157 1.1.2.1 yamt KASSERT(ra != NULL);
158 1.1.2.1 yamt ra_freectx(ra);
159 1.1.2.1 yamt }
160 1.1.2.1 yamt
161 1.1.2.1 yamt void
162 1.1.2.1 yamt uvm_ra_request(struct uvm_ractx *ra, struct uvm_object *uobj,
163 1.1.2.1 yamt off_t reqoff, size_t reqsize)
164 1.1.2.1 yamt {
165 1.1.2.1 yamt
166 1.1.2.1 yamt if (ra == NULL) {
167 1.1.2.1 yamt return;
168 1.1.2.1 yamt }
169 1.1.2.1 yamt
170 1.1.2.2 yamt switch (ra->ra_advice) {
171 1.1.2.2 yamt case POSIX_FADV_NORMAL:
172 1.1.2.2 yamt break;
173 1.1.2.2 yamt
174 1.1.2.2 yamt case POSIX_FADV_RANDOM:
175 1.1.2.2 yamt return;
176 1.1.2.2 yamt
177 1.1.2.2 yamt case POSIX_FADV_SEQUENTIAL:
178 1.1.2.2 yamt if (reqoff <= ra->ra_winstart) {
179 1.1.2.2 yamt ra->ra_next = reqoff;
180 1.1.2.2 yamt }
181 1.1.2.2 yamt ra->ra_winsize = RA_WINSIZE_SEQENTIAL;
182 1.1.2.2 yamt goto do_readahead;
183 1.1.2.2 yamt
184 1.1.2.2 yamt default:
185 1.1.2.2 yamt #if defined(DIAGNOSTIC)
186 1.1.2.2 yamt panic("%s: unknown advice %d", __func__, ra->ra_advice);
187 1.1.2.2 yamt #endif /* defined(DIAGNOSTIC) */
188 1.1.2.2 yamt break;
189 1.1.2.2 yamt }
190 1.1.2.2 yamt
191 1.1.2.1 yamt if ((ra->ra_flags & RA_VALID) == 0) {
192 1.1.2.1 yamt initialize:
193 1.1.2.1 yamt ra->ra_winstart = ra->ra_next = reqoff + reqsize;
194 1.1.2.1 yamt ra->ra_winsize = RA_WINSIZE_INIT;
195 1.1.2.1 yamt ra->ra_flags |= RA_VALID;
196 1.1.2.1 yamt return;
197 1.1.2.1 yamt }
198 1.1.2.1 yamt
199 1.1.2.1 yamt if (reqoff < ra->ra_winstart ||
200 1.1.2.1 yamt ra->ra_winstart + ra->ra_winsize < reqoff) {
201 1.1.2.1 yamt
202 1.1.2.1 yamt /*
203 1.1.2.1 yamt * miss
204 1.1.2.1 yamt */
205 1.1.2.1 yamt
206 1.1.2.1 yamt goto initialize;
207 1.1.2.1 yamt }
208 1.1.2.1 yamt
209 1.1.2.1 yamt /*
210 1.1.2.1 yamt * hit
211 1.1.2.1 yamt */
212 1.1.2.1 yamt
213 1.1.2.2 yamt do_readahead:
214 1.1.2.1 yamt if (reqoff > ra->ra_next) {
215 1.1.2.1 yamt ra->ra_next = reqoff;
216 1.1.2.1 yamt }
217 1.1.2.1 yamt
218 1.1.2.1 yamt if (reqoff + ra->ra_winsize > ra->ra_next) {
219 1.1.2.1 yamt off_t raoff = MAX(reqoff, ra->ra_next);
220 1.1.2.1 yamt size_t rasize = reqoff + ra->ra_winsize - ra->ra_next;
221 1.1.2.1 yamt
222 1.1.2.1 yamt if (rasize >= RA_MINSIZE) {
223 1.1.2.1 yamt ra->ra_next = ra_startio(uobj, raoff, rasize);
224 1.1.2.1 yamt }
225 1.1.2.1 yamt }
226 1.1.2.1 yamt
227 1.1.2.1 yamt /*
228 1.1.2.1 yamt * update window
229 1.1.2.1 yamt */
230 1.1.2.1 yamt
231 1.1.2.1 yamt ra->ra_winstart = reqoff + reqsize;
232 1.1.2.1 yamt ra->ra_winsize = MIN(RA_WINSIZE_MAX, ra->ra_winsize + reqsize);
233 1.1.2.1 yamt }
234