| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: uvm_aobj.c,v 1.116 2011/09/06 16:41:55 matt Exp $ */ | | 1 | /* $NetBSD: uvm_aobj.c,v 1.117 2012/09/14 18:56:15 rmind Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1998 Chuck Silvers, Charles D. Cranor and | | 4 | * Copyright (c) 1998 Chuck Silvers, Charles D. Cranor and |
5 | * Washington University. | | 5 | * Washington University. |
6 | * All rights reserved. | | 6 | * All rights reserved. |
7 | * | | 7 | * |
8 | * Redistribution and use in source and binary forms, with or without | | 8 | * Redistribution and use in source and binary forms, with or without |
9 | * modification, are permitted provided that the following conditions | | 9 | * modification, are permitted provided that the following conditions |
10 | * are met: | | 10 | * are met: |
11 | * 1. Redistributions of source code must retain the above copyright | | 11 | * 1. Redistributions of source code must retain the above copyright |
12 | * notice, this list of conditions and the following disclaimer. | | 12 | * notice, this list of conditions and the following disclaimer. |
13 | * 2. Redistributions in binary form must reproduce the above copyright | | 13 | * 2. Redistributions in binary form must reproduce the above copyright |
14 | * notice, this list of conditions and the following disclaimer in the | | 14 | * notice, this list of conditions and the following disclaimer in the |
| @@ -28,191 +28,171 @@ | | | @@ -28,191 +28,171 @@ |
28 | * from: Id: uvm_aobj.c,v 1.1.2.5 1998/02/06 05:14:38 chs Exp | | 28 | * from: Id: uvm_aobj.c,v 1.1.2.5 1998/02/06 05:14:38 chs Exp |
29 | */ | | 29 | */ |
30 | | | 30 | |
31 | /* | | 31 | /* |
32 | * uvm_aobj.c: anonymous memory uvm_object pager | | 32 | * uvm_aobj.c: anonymous memory uvm_object pager |
33 | * | | 33 | * |
34 | * author: Chuck Silvers <chuq@chuq.com> | | 34 | * author: Chuck Silvers <chuq@chuq.com> |
35 | * started: Jan-1998 | | 35 | * started: Jan-1998 |
36 | * | | 36 | * |
37 | * - design mostly from Chuck Cranor | | 37 | * - design mostly from Chuck Cranor |
38 | */ | | 38 | */ |
39 | | | 39 | |
40 | #include <sys/cdefs.h> | | 40 | #include <sys/cdefs.h> |
41 | __KERNEL_RCSID(0, "$NetBSD: uvm_aobj.c,v 1.116 2011/09/06 16:41:55 matt Exp $"); | | 41 | __KERNEL_RCSID(0, "$NetBSD: uvm_aobj.c,v 1.117 2012/09/14 18:56:15 rmind Exp $"); |
42 | | | 42 | |
43 | #include "opt_uvmhist.h" | | 43 | #include "opt_uvmhist.h" |
44 | | | 44 | |
45 | #include <sys/param.h> | | 45 | #include <sys/param.h> |
46 | #include <sys/systm.h> | | 46 | #include <sys/systm.h> |
47 | #include <sys/proc.h> | | 47 | #include <sys/proc.h> |
48 | #include <sys/kernel.h> | | 48 | #include <sys/kernel.h> |
49 | #include <sys/kmem.h> | | 49 | #include <sys/kmem.h> |
50 | #include <sys/pool.h> | | 50 | #include <sys/pool.h> |
51 | | | 51 | |
52 | #include <uvm/uvm.h> | | 52 | #include <uvm/uvm.h> |
53 | | | 53 | |
54 | /* | | 54 | /* |
55 | * an aobj manages anonymous-memory backed uvm_objects. in addition | | 55 | * An anonymous UVM object (aobj) manages anonymous-memory. In addition to |
56 | * to keeping the list of resident pages, it also keeps a list of | | 56 | * keeping the list of resident pages, it may also keep a list of allocated |
57 | * allocated swap blocks. depending on the size of the aobj this list | | 57 | * swap blocks. Depending on the size of the object, this list is either |
58 | * of allocated swap blocks is either stored in an array (small objects) | | 58 | * stored in an array (small objects) or in a hash table (large objects). |
59 | * or in a hash table (large objects). | | 59 | * |
60 | */ | | 60 | * Lock order |
61 | | | 61 | * |
62 | /* | | 62 | * uvm_object::vmobjlock -> |
63 | * local structures | | 63 | * uao_list_lock |
64 | */ | | 64 | */ |
65 | | | 65 | |
66 | /* | | 66 | /* |
67 | * for hash tables, we break the address space of the aobj into blocks | | 67 | * Note: for hash tables, we break the address space of the aobj into blocks |
68 | * of UAO_SWHASH_CLUSTER_SIZE pages. we require the cluster size to | | 68 | * of UAO_SWHASH_CLUSTER_SIZE pages, which shall be a power of two. |
69 | * be a power of two. | | | |
70 | */ | | 69 | */ |
71 | | | 70 | |
72 | #define UAO_SWHASH_CLUSTER_SHIFT 4 | | 71 | #define UAO_SWHASH_CLUSTER_SHIFT 4 |
73 | #define UAO_SWHASH_CLUSTER_SIZE (1 << UAO_SWHASH_CLUSTER_SHIFT) | | 72 | #define UAO_SWHASH_CLUSTER_SIZE (1 << UAO_SWHASH_CLUSTER_SHIFT) |
74 | | | 73 | |
75 | /* get the "tag" for this page index */ | | 74 | /* Get the "tag" for this page index. */ |
76 | #define UAO_SWHASH_ELT_TAG(PAGEIDX) \ | | 75 | #define UAO_SWHASH_ELT_TAG(idx) ((idx) >> UAO_SWHASH_CLUSTER_SHIFT) |
77 | ((PAGEIDX) >> UAO_SWHASH_CLUSTER_SHIFT) | | 76 | #define UAO_SWHASH_ELT_PAGESLOT_IDX(idx) \ |
| | | 77 | ((idx) & (UAO_SWHASH_CLUSTER_SIZE - 1)) |
78 | | | 78 | |
79 | #define UAO_SWHASH_ELT_PAGESLOT_IDX(PAGEIDX) \ | | 79 | /* Given an ELT and a page index, find the swap slot. */ |
80 | ((PAGEIDX) & (UAO_SWHASH_CLUSTER_SIZE - 1)) | | 80 | #define UAO_SWHASH_ELT_PAGESLOT(elt, idx) \ |
| | | 81 | ((elt)->slots[UAO_SWHASH_ELT_PAGESLOT_IDX(idx)]) |
81 | | | 82 | |
82 | /* given an ELT and a page index, find the swap slot */ | | 83 | /* Given an ELT, return its pageidx base. */ |
83 | #define UAO_SWHASH_ELT_PAGESLOT(ELT, PAGEIDX) \ | | 84 | #define UAO_SWHASH_ELT_PAGEIDX_BASE(ELT) \ |
84 | ((ELT)->slots[UAO_SWHASH_ELT_PAGESLOT_IDX(PAGEIDX)]) | | 85 | ((elt)->tag << UAO_SWHASH_CLUSTER_SHIFT) |
85 | | | 86 | |
86 | /* given an ELT, return its pageidx base */ | | 87 | /* The hash function. */ |
87 | #define UAO_SWHASH_ELT_PAGEIDX_BASE(ELT) \ | | 88 | #define UAO_SWHASH_HASH(aobj, idx) \ |
88 | ((ELT)->tag << UAO_SWHASH_CLUSTER_SHIFT) | | 89 | (&(aobj)->u_swhash[(((idx) >> UAO_SWHASH_CLUSTER_SHIFT) \ |
| | | 90 | & (aobj)->u_swhashmask)]) |
89 | | | 91 | |
90 | /* | | 92 | /* |
91 | * the swhash hash function | | 93 | * The threshold which determines whether we will use an array or a |
92 | */ | | | |
93 | | | | |
94 | #define UAO_SWHASH_HASH(AOBJ, PAGEIDX) \ | | | |
95 | (&(AOBJ)->u_swhash[(((PAGEIDX) >> UAO_SWHASH_CLUSTER_SHIFT) \ | | | |
96 | & (AOBJ)->u_swhashmask)]) | | | |
97 | | | | |
98 | /* | | | |
99 | * the swhash threshhold determines if we will use an array or a | | | |
100 | * hash table to store the list of allocated swap blocks. | | 94 | * hash table to store the list of allocated swap blocks. |
101 | */ | | 95 | */ |
102 | | | 96 | #define UAO_SWHASH_THRESHOLD (UAO_SWHASH_CLUSTER_SIZE * 4) |
103 | #define UAO_SWHASH_THRESHOLD (UAO_SWHASH_CLUSTER_SIZE * 4) | | 97 | #define UAO_USES_SWHASH(aobj) \ |
104 | #define UAO_USES_SWHASH(AOBJ) \ | | 98 | ((aobj)->u_pages > UAO_SWHASH_THRESHOLD) |
105 | ((AOBJ)->u_pages > UAO_SWHASH_THRESHOLD) /* use hash? */ | | 99 | |
106 | | | 100 | /* The number of buckets in a hash, with an upper bound. */ |
107 | /* | | 101 | #define UAO_SWHASH_MAXBUCKETS 256 |
108 | * the number of buckets in a swhash, with an upper bound | | 102 | #define UAO_SWHASH_BUCKETS(aobj) \ |
109 | */ | | 103 | (MIN((aobj)->u_pages >> UAO_SWHASH_CLUSTER_SHIFT, UAO_SWHASH_MAXBUCKETS)) |
110 | | | | |
111 | #define UAO_SWHASH_MAXBUCKETS 256 | | | |
112 | #define UAO_SWHASH_BUCKETS(AOBJ) \ | | | |
113 | (MIN((AOBJ)->u_pages >> UAO_SWHASH_CLUSTER_SHIFT, \ | | | |
114 | UAO_SWHASH_MAXBUCKETS)) | | | |
115 | | | 104 | |
116 | /* | | 105 | /* |
117 | * uao_swhash_elt: when a hash table is being used, this structure defines | | 106 | * uao_swhash_elt: when a hash table is being used, this structure defines |
118 | * the format of an entry in the bucket list. | | 107 | * the format of an entry in the bucket list. |
119 | */ | | 108 | */ |
120 | | | 109 | |
121 | struct uao_swhash_elt { | | 110 | struct uao_swhash_elt { |
122 | LIST_ENTRY(uao_swhash_elt) list; /* the hash list */ | | 111 | LIST_ENTRY(uao_swhash_elt) list; /* the hash list */ |
123 | voff_t tag; /* our 'tag' */ | | 112 | voff_t tag; /* our 'tag' */ |
124 | int count; /* our number of active slots */ | | 113 | int count; /* our number of active slots */ |
125 | int slots[UAO_SWHASH_CLUSTER_SIZE]; /* the slots */ | | 114 | int slots[UAO_SWHASH_CLUSTER_SIZE]; /* the slots */ |
126 | }; | | 115 | }; |
127 | | | 116 | |
128 | /* | | 117 | /* |
129 | * uao_swhash: the swap hash table structure | | 118 | * uao_swhash: the swap hash table structure |
130 | */ | | 119 | */ |
131 | | | 120 | |
132 | LIST_HEAD(uao_swhash, uao_swhash_elt); | | 121 | LIST_HEAD(uao_swhash, uao_swhash_elt); |
133 | | | 122 | |
134 | /* | | 123 | /* |
135 | * uao_swhash_elt_pool: pool of uao_swhash_elt structures. | | 124 | * uao_swhash_elt_pool: pool of uao_swhash_elt structures. |
136 | * Note: pages for this pool must not come from a pageable kernel map. | | 125 | * Note: pages for this pool must not come from a pageable kernel map. |
137 | */ | | 126 | */ |
138 | static struct pool uao_swhash_elt_pool; | | 127 | static struct pool uao_swhash_elt_pool __cacheline_aligned; |
139 | | | 128 | |
140 | /* | | 129 | /* |
141 | * uvm_aobj: the actual anon-backed uvm_object | | 130 | * uvm_aobj: the actual anon-backed uvm_object |
142 | * | | 131 | * |
143 | * => the uvm_object is at the top of the structure, this allows | | 132 | * => the uvm_object is at the top of the structure, this allows |
144 | * (struct uvm_aobj *) == (struct uvm_object *) | | 133 | * (struct uvm_aobj *) == (struct uvm_object *) |
145 | * => only one of u_swslots and u_swhash is used in any given aobj | | 134 | * => only one of u_swslots and u_swhash is used in any given aobj |
146 | */ | | 135 | */ |
147 | | | 136 | |
148 | struct uvm_aobj { | | 137 | struct uvm_aobj { |
149 | struct uvm_object u_obj; /* has: lock, pgops, memq, #pages, #refs */ | | 138 | struct uvm_object u_obj; /* has: lock, pgops, memq, #pages, #refs */ |
150 | pgoff_t u_pages; /* number of pages in entire object */ | | 139 | pgoff_t u_pages; /* number of pages in entire object */ |
151 | int u_flags; /* the flags (see uvm_aobj.h) */ | | 140 | int u_flags; /* the flags (see uvm_aobj.h) */ |
152 | int *u_swslots; /* array of offset->swapslot mappings */ | | 141 | int *u_swslots; /* array of offset->swapslot mappings */ |
153 | /* | | 142 | /* |
154 | * hashtable of offset->swapslot mappings | | 143 | * hashtable of offset->swapslot mappings |
155 | * (u_swhash is an array of bucket heads) | | 144 | * (u_swhash is an array of bucket heads) |
156 | */ | | 145 | */ |
157 | struct uao_swhash *u_swhash; | | 146 | struct uao_swhash *u_swhash; |
158 | u_long u_swhashmask; /* mask for hashtable */ | | 147 | u_long u_swhashmask; /* mask for hashtable */ |
159 | LIST_ENTRY(uvm_aobj) u_list; /* global list of aobjs */ | | 148 | LIST_ENTRY(uvm_aobj) u_list; /* global list of aobjs */ |
160 | }; | | 149 | }; |
161 | | | 150 | |
162 | /* | | | |
163 | * local functions | | | |
164 | */ | | | |
165 | | | | |
166 | static void uao_free(struct uvm_aobj *); | | 151 | static void uao_free(struct uvm_aobj *); |
167 | static int uao_get(struct uvm_object *, voff_t, struct vm_page **, | | 152 | static int uao_get(struct uvm_object *, voff_t, struct vm_page **, |
168 | int *, int, vm_prot_t, int, int); | | 153 | int *, int, vm_prot_t, int, int); |
169 | static int uao_put(struct uvm_object *, voff_t, voff_t, int); | | 154 | static int uao_put(struct uvm_object *, voff_t, voff_t, int); |
170 | | | 155 | |
171 | static void uao_detach_locked(struct uvm_object *); | | 156 | static void uao_detach_locked(struct uvm_object *); |
172 | static void uao_reference_locked(struct uvm_object *); | | 157 | static void uao_reference_locked(struct uvm_object *); |
173 | | | 158 | |
174 | #if defined(VMSWAP) | | 159 | #if defined(VMSWAP) |
175 | static struct uao_swhash_elt *uao_find_swhash_elt | | 160 | static struct uao_swhash_elt *uao_find_swhash_elt |
176 | (struct uvm_aobj *, int, bool); | | 161 | (struct uvm_aobj *, int, bool); |
177 | | | 162 | |
178 | static bool uao_pagein(struct uvm_aobj *, int, int); | | 163 | static bool uao_pagein(struct uvm_aobj *, int, int); |
179 | static bool uao_pagein_page(struct uvm_aobj *, int); | | 164 | static bool uao_pagein_page(struct uvm_aobj *, int); |
180 | static void uao_dropswap_range1(struct uvm_aobj *, voff_t, voff_t); | | | |
181 | #endif /* defined(VMSWAP) */ | | 165 | #endif /* defined(VMSWAP) */ |
182 | | | 166 | |
183 | /* | | 167 | /* |
184 | * aobj_pager | | 168 | * aobj_pager |
185 | * | | 169 | * |
186 | * note that some functions (e.g. put) are handled elsewhere | | 170 | * note that some functions (e.g. put) are handled elsewhere |
187 | */ | | 171 | */ |
188 | | | 172 | |
189 | const struct uvm_pagerops aobj_pager = { | | 173 | const struct uvm_pagerops aobj_pager = { |
190 | .pgo_reference = uao_reference, | | 174 | .pgo_reference = uao_reference, |
191 | .pgo_detach = uao_detach, | | 175 | .pgo_detach = uao_detach, |
192 | .pgo_get = uao_get, | | 176 | .pgo_get = uao_get, |
193 | .pgo_put = uao_put, | | 177 | .pgo_put = uao_put, |
194 | }; | | 178 | }; |
195 | | | 179 | |
196 | /* | | 180 | /* |
197 | * uao_list: global list of active aobjs, locked by uao_list_lock | | 181 | * uao_list: global list of active aobjs, locked by uao_list_lock |
198 | */ | | 182 | */ |
199 | | | 183 | |
200 | static LIST_HEAD(aobjlist, uvm_aobj) uao_list; | | 184 | static LIST_HEAD(aobjlist, uvm_aobj) uao_list __cacheline_aligned; |
201 | static kmutex_t uao_list_lock; | | 185 | static kmutex_t uao_list_lock __cacheline_aligned; |
202 | | | | |
203 | /* | | | |
204 | * functions | | | |
205 | */ | | | |
206 | | | 186 | |
207 | /* | | 187 | /* |
208 | * hash table/array related functions | | 188 | * hash table/array related functions |
209 | */ | | 189 | */ |
210 | | | 190 | |
211 | #if defined(VMSWAP) | | 191 | #if defined(VMSWAP) |
212 | | | 192 | |
213 | /* | | 193 | /* |
214 | * uao_find_swhash_elt: find (or create) a hash table entry for a page | | 194 | * uao_find_swhash_elt: find (or create) a hash table entry for a page |
215 | * offset. | | 195 | * offset. |
216 | * | | 196 | * |
217 | * => the object should be locked by the caller | | 197 | * => the object should be locked by the caller |
218 | */ | | 198 | */ |
| @@ -262,45 +242,42 @@ uao_find_swhash_elt(struct uvm_aobj *aob | | | @@ -262,45 +242,42 @@ uao_find_swhash_elt(struct uvm_aobj *aob |
262 | */ | | 242 | */ |
263 | | | 243 | |
264 | int | | 244 | int |
265 | uao_find_swslot(struct uvm_object *uobj, int pageidx) | | 245 | uao_find_swslot(struct uvm_object *uobj, int pageidx) |
266 | { | | 246 | { |
267 | struct uvm_aobj *aobj = (struct uvm_aobj *)uobj; | | 247 | struct uvm_aobj *aobj = (struct uvm_aobj *)uobj; |
268 | struct uao_swhash_elt *elt; | | 248 | struct uao_swhash_elt *elt; |
269 | | | 249 | |
270 | /* | | 250 | /* |
271 | * if noswap flag is set, then we never return a slot | | 251 | * if noswap flag is set, then we never return a slot |
272 | */ | | 252 | */ |
273 | | | 253 | |
274 | if (aobj->u_flags & UAO_FLAG_NOSWAP) | | 254 | if (aobj->u_flags & UAO_FLAG_NOSWAP) |
275 | return(0); | | 255 | return 0; |
276 | | | 256 | |
277 | /* | | 257 | /* |
278 | * if hashing, look in hash table. | | 258 | * if hashing, look in hash table. |
279 | */ | | 259 | */ |
280 | | | 260 | |
281 | if (UAO_USES_SWHASH(aobj)) { | | 261 | if (UAO_USES_SWHASH(aobj)) { |
282 | elt = uao_find_swhash_elt(aobj, pageidx, false); | | 262 | elt = uao_find_swhash_elt(aobj, pageidx, false); |
283 | if (elt) | | 263 | return elt ? UAO_SWHASH_ELT_PAGESLOT(elt, pageidx) : 0; |
284 | return(UAO_SWHASH_ELT_PAGESLOT(elt, pageidx)); | | | |
285 | else | | | |
286 | return(0); | | | |
287 | } | | 264 | } |
288 | | | 265 | |
289 | /* | | 266 | /* |
290 | * otherwise, look in the array | | 267 | * otherwise, look in the array |
291 | */ | | 268 | */ |
292 | | | 269 | |
293 | return(aobj->u_swslots[pageidx]); | | 270 | return aobj->u_swslots[pageidx]; |
294 | } | | 271 | } |
295 | | | 272 | |
296 | /* | | 273 | /* |
297 | * uao_set_swslot: set the swap slot for a page in an aobj. | | 274 | * uao_set_swslot: set the swap slot for a page in an aobj. |
298 | * | | 275 | * |
299 | * => setting a slot to zero frees the slot | | 276 | * => setting a slot to zero frees the slot |
300 | * => object must be locked by caller | | 277 | * => object must be locked by caller |
301 | * => we return the old slot number, or -1 if we failed to allocate | | 278 | * => we return the old slot number, or -1 if we failed to allocate |
302 | * memory to record the new slot number | | 279 | * memory to record the new slot number |
303 | */ | | 280 | */ |
304 | | | 281 | |
305 | int | | 282 | int |
306 | uao_set_swslot(struct uvm_object *uobj, int pageidx, int slot) | | 283 | uao_set_swslot(struct uvm_object *uobj, int pageidx, int slot) |
| @@ -309,31 +286,28 @@ uao_set_swslot(struct uvm_object *uobj, | | | @@ -309,31 +286,28 @@ uao_set_swslot(struct uvm_object *uobj, |
309 | struct uao_swhash_elt *elt; | | 286 | struct uao_swhash_elt *elt; |
310 | int oldslot; | | 287 | int oldslot; |
311 | UVMHIST_FUNC("uao_set_swslot"); UVMHIST_CALLED(pdhist); | | 288 | UVMHIST_FUNC("uao_set_swslot"); UVMHIST_CALLED(pdhist); |
312 | UVMHIST_LOG(pdhist, "aobj %p pageidx %d slot %d", | | 289 | UVMHIST_LOG(pdhist, "aobj %p pageidx %d slot %d", |
313 | aobj, pageidx, slot, 0); | | 290 | aobj, pageidx, slot, 0); |
314 | | | 291 | |
315 | KASSERT(mutex_owned(uobj->vmobjlock) || uobj->uo_refs == 0); | | 292 | KASSERT(mutex_owned(uobj->vmobjlock) || uobj->uo_refs == 0); |
316 | | | 293 | |
317 | /* | | 294 | /* |
318 | * if noswap flag is set, then we can't set a non-zero slot. | | 295 | * if noswap flag is set, then we can't set a non-zero slot. |
319 | */ | | 296 | */ |
320 | | | 297 | |
321 | if (aobj->u_flags & UAO_FLAG_NOSWAP) { | | 298 | if (aobj->u_flags & UAO_FLAG_NOSWAP) { |
322 | if (slot == 0) | | 299 | KASSERTMSG(slot == 0, "uao_set_swslot: no swap object"); |
323 | return(0); | | 300 | return 0; |
324 | | | | |
325 | printf("uao_set_swslot: uobj = %p\n", uobj); | | | |
326 | panic("uao_set_swslot: NOSWAP object"); | | | |
327 | } | | 301 | } |
328 | | | 302 | |
329 | /* | | 303 | /* |
330 | * are we using a hash table? if so, add it in the hash. | | 304 | * are we using a hash table? if so, add it in the hash. |
331 | */ | | 305 | */ |
332 | | | 306 | |
333 | if (UAO_USES_SWHASH(aobj)) { | | 307 | if (UAO_USES_SWHASH(aobj)) { |
334 | | | 308 | |
335 | /* | | 309 | /* |
336 | * Avoid allocating an entry just to free it again if | | 310 | * Avoid allocating an entry just to free it again if |
337 | * the page had not swap slot in the first place, and | | 311 | * the page had not swap slot in the first place, and |
338 | * we are freeing. | | 312 | * we are freeing. |
339 | */ | | 313 | */ |
| @@ -358,74 +332,72 @@ uao_set_swslot(struct uvm_object *uobj, | | | @@ -358,74 +332,72 @@ uao_set_swslot(struct uvm_object *uobj, |
358 | if (oldslot) | | 332 | if (oldslot) |
359 | elt->count--; | | 333 | elt->count--; |
360 | | | 334 | |
361 | if (elt->count == 0) { | | 335 | if (elt->count == 0) { |
362 | LIST_REMOVE(elt, list); | | 336 | LIST_REMOVE(elt, list); |
363 | pool_put(&uao_swhash_elt_pool, elt); | | 337 | pool_put(&uao_swhash_elt_pool, elt); |
364 | } | | 338 | } |
365 | } | | 339 | } |
366 | } else { | | 340 | } else { |
367 | /* we are using an array */ | | 341 | /* we are using an array */ |
368 | oldslot = aobj->u_swslots[pageidx]; | | 342 | oldslot = aobj->u_swslots[pageidx]; |
369 | aobj->u_swslots[pageidx] = slot; | | 343 | aobj->u_swslots[pageidx] = slot; |
370 | } | | 344 | } |
371 | return (oldslot); | | 345 | return oldslot; |
372 | } | | 346 | } |
373 | | | 347 | |
374 | #endif /* defined(VMSWAP) */ | | 348 | #endif /* defined(VMSWAP) */ |
375 | | | 349 | |
376 | /* | | 350 | /* |
377 | * end of hash/array functions | | 351 | * end of hash/array functions |
378 | */ | | 352 | */ |
379 | | | 353 | |
380 | /* | | 354 | /* |
381 | * uao_free: free all resources held by an aobj, and then free the aobj | | 355 | * uao_free: free all resources held by an aobj, and then free the aobj |
382 | * | | 356 | * |
383 | * => the aobj should be dead | | 357 | * => the aobj should be dead |
384 | */ | | 358 | */ |
385 | | | 359 | |
386 | static void | | 360 | static void |
387 | uao_free(struct uvm_aobj *aobj) | | 361 | uao_free(struct uvm_aobj *aobj) |
388 | { | | 362 | { |
| | | 363 | struct uvm_object *uobj = &aobj->u_obj; |
389 | | | 364 | |
390 | #if defined(VMSWAP) | | 365 | uao_dropswap_range(aobj, 0, 0); |
391 | uao_dropswap_range1(aobj, 0, 0); | | 366 | mutex_exit(uobj->vmobjlock); |
392 | #endif /* defined(VMSWAP) */ | | | |
393 | | | | |
394 | mutex_exit(aobj->u_obj.vmobjlock); | | | |
395 | | | 367 | |
396 | #if defined(VMSWAP) | | 368 | #if defined(VMSWAP) |
397 | if (UAO_USES_SWHASH(aobj)) { | | 369 | if (UAO_USES_SWHASH(aobj)) { |
398 | | | 370 | |
399 | /* | | 371 | /* |
400 | * free the hash table itself. | | 372 | * free the hash table itself. |
401 | */ | | 373 | */ |
402 | | | 374 | |
403 | hashdone(aobj->u_swhash, HASH_LIST, aobj->u_swhashmask); | | 375 | hashdone(aobj->u_swhash, HASH_LIST, aobj->u_swhashmask); |
404 | } else { | | 376 | } else { |
405 | | | 377 | |
406 | /* | | 378 | /* |
407 | * free the array itsself. | | 379 | * free the array itsself. |
408 | */ | | 380 | */ |
409 | | | 381 | |
410 | kmem_free(aobj->u_swslots, aobj->u_pages * sizeof(int)); | | 382 | kmem_free(aobj->u_swslots, aobj->u_pages * sizeof(int)); |
411 | } | | 383 | } |
412 | #endif /* defined(VMSWAP) */ | | 384 | #endif /* defined(VMSWAP) */ |
413 | | | 385 | |
414 | /* | | 386 | /* |
415 | * finally free the aobj itself | | 387 | * finally free the aobj itself |
416 | */ | | 388 | */ |
417 | | | 389 | |
418 | uvm_obj_destroy(&aobj->u_obj, true); | | 390 | uvm_obj_destroy(uobj, true); |
419 | kmem_free(aobj, sizeof(struct uvm_aobj)); | | 391 | kmem_free(aobj, sizeof(struct uvm_aobj)); |
420 | } | | 392 | } |
421 | | | 393 | |
422 | /* | | 394 | /* |
423 | * pager functions | | 395 | * pager functions |
424 | */ | | 396 | */ |
425 | | | 397 | |
426 | /* | | 398 | /* |
427 | * uao_create: create an aobj of the given size and return its uvm_object. | | 399 | * uao_create: create an aobj of the given size and return its uvm_object. |
428 | * | | 400 | * |
429 | * => for normal use, flags are always zero | | 401 | * => for normal use, flags are always zero |
430 | * => for the kernel object, the flags are: | | 402 | * => for the kernel object, the flags are: |
431 | * UAO_FLAG_KERNOBJ - allocate the kernel object (can only happen once) | | 403 | * UAO_FLAG_KERNOBJ - allocate the kernel object (can only happen once) |
| @@ -483,54 +455,52 @@ uao_create(vsize_t size, int flags) | | | @@ -483,54 +455,52 @@ uao_create(vsize_t size, int flags) |
483 | &aobj->u_swhashmask); | | 455 | &aobj->u_swhashmask); |
484 | if (aobj->u_swhash == NULL) | | 456 | if (aobj->u_swhash == NULL) |
485 | panic("uao_create: hashinit swhash failed"); | | 457 | panic("uao_create: hashinit swhash failed"); |
486 | } else { | | 458 | } else { |
487 | aobj->u_swslots = kmem_zalloc(pages * sizeof(int), | | 459 | aobj->u_swslots = kmem_zalloc(pages * sizeof(int), |
488 | kernswap ? KM_NOSLEEP : KM_SLEEP); | | 460 | kernswap ? KM_NOSLEEP : KM_SLEEP); |
489 | if (aobj->u_swslots == NULL) | | 461 | if (aobj->u_swslots == NULL) |
490 | panic("uao_create: swslots allocation failed"); | | 462 | panic("uao_create: swslots allocation failed"); |
491 | } | | 463 | } |
492 | #endif /* defined(VMSWAP) */ | | 464 | #endif /* defined(VMSWAP) */ |
493 | | | 465 | |
494 | if (flags) { | | 466 | if (flags) { |
495 | aobj->u_flags &= ~UAO_FLAG_NOSWAP; /* clear noswap */ | | 467 | aobj->u_flags &= ~UAO_FLAG_NOSWAP; /* clear noswap */ |
496 | return(&aobj->u_obj); | | 468 | return &aobj->u_obj; |
497 | } | | 469 | } |
498 | } | | 470 | } |
499 | | | 471 | |
500 | /* | | 472 | /* |
501 | * Initialise UVM object. | | 473 | * Initialise UVM object. |
502 | */ | | 474 | */ |
503 | | | 475 | |
504 | const bool kernobj = (flags & UAO_FLAG_KERNOBJ) != 0; | | 476 | const bool kernobj = (flags & UAO_FLAG_KERNOBJ) != 0; |
505 | uvm_obj_init(&aobj->u_obj, &aobj_pager, !kernobj, refs); | | 477 | uvm_obj_init(&aobj->u_obj, &aobj_pager, !kernobj, refs); |
506 | if (__predict_false(kernobj)) { | | 478 | if (__predict_false(kernobj)) { |
507 | /* Initialisation only once, for UAO_FLAG_KERNOBJ. */ | | 479 | /* Initialisation only once, for UAO_FLAG_KERNOBJ. */ |
508 | mutex_init(&kernel_object_lock, MUTEX_DEFAULT, IPL_NONE); | | 480 | mutex_init(&kernel_object_lock, MUTEX_DEFAULT, IPL_NONE); |
509 | uvm_obj_setlock(&aobj->u_obj, &kernel_object_lock); | | 481 | uvm_obj_setlock(&aobj->u_obj, &kernel_object_lock); |
510 | } | | 482 | } |
511 | | | 483 | |
512 | /* | | 484 | /* |
513 | * now that aobj is ready, add it to the global list | | 485 | * now that aobj is ready, add it to the global list |
514 | */ | | 486 | */ |
515 | | | 487 | |
516 | mutex_enter(&uao_list_lock); | | 488 | mutex_enter(&uao_list_lock); |
517 | LIST_INSERT_HEAD(&uao_list, aobj, u_list); | | 489 | LIST_INSERT_HEAD(&uao_list, aobj, u_list); |
518 | mutex_exit(&uao_list_lock); | | 490 | mutex_exit(&uao_list_lock); |
519 | return(&aobj->u_obj); | | 491 | return(&aobj->u_obj); |
520 | } | | 492 | } |
521 | | | 493 | |
522 | | | | |
523 | | | | |
524 | /* | | 494 | /* |
525 | * uao_init: set up aobj pager subsystem | | 495 | * uao_init: set up aobj pager subsystem |
526 | * | | 496 | * |
527 | * => called at boot time from uvm_pager_init() | | 497 | * => called at boot time from uvm_pager_init() |
528 | */ | | 498 | */ |
529 | | | 499 | |
530 | void | | 500 | void |
531 | uao_init(void) | | 501 | uao_init(void) |
532 | { | | 502 | { |
533 | static int uao_initialized; | | 503 | static int uao_initialized; |
534 | | | 504 | |
535 | if (uao_initialized) | | 505 | if (uao_initialized) |
536 | return; | | 506 | return; |
| @@ -905,29 +875,26 @@ uao_put(struct uvm_object *uobj, voff_t | | | @@ -905,29 +875,26 @@ uao_put(struct uvm_object *uobj, voff_t |
905 | * | | 875 | * |
906 | * => prefer map unlocked (not required) | | 876 | * => prefer map unlocked (not required) |
907 | * => object must be locked! we will _unlock_ it before starting any I/O. | | 877 | * => object must be locked! we will _unlock_ it before starting any I/O. |
908 | * => flags: PGO_ALLPAGES: get all of the pages | | 878 | * => flags: PGO_ALLPAGES: get all of the pages |
909 | * PGO_LOCKED: fault data structures are locked | | 879 | * PGO_LOCKED: fault data structures are locked |
910 | * => NOTE: offset is the offset of pps[0], _NOT_ pps[centeridx] | | 880 | * => NOTE: offset is the offset of pps[0], _NOT_ pps[centeridx] |
911 | * => NOTE: caller must check for released pages!! | | 881 | * => NOTE: caller must check for released pages!! |
912 | */ | | 882 | */ |
913 | | | 883 | |
914 | static int | | 884 | static int |
915 | uao_get(struct uvm_object *uobj, voff_t offset, struct vm_page **pps, | | 885 | uao_get(struct uvm_object *uobj, voff_t offset, struct vm_page **pps, |
916 | int *npagesp, int centeridx, vm_prot_t access_type, int advice, int flags) | | 886 | int *npagesp, int centeridx, vm_prot_t access_type, int advice, int flags) |
917 | { | | 887 | { |
918 | #if defined(VMSWAP) | | | |
919 | struct uvm_aobj *aobj = (struct uvm_aobj *)uobj; | | | |
920 | #endif /* defined(VMSWAP) */ | | | |
921 | voff_t current_offset; | | 888 | voff_t current_offset; |
922 | struct vm_page *ptmp = NULL; /* Quell compiler warning */ | | 889 | struct vm_page *ptmp = NULL; /* Quell compiler warning */ |
923 | int lcv, gotpages, maxpages, swslot, pageidx; | | 890 | int lcv, gotpages, maxpages, swslot, pageidx; |
924 | bool done; | | 891 | bool done; |
925 | UVMHIST_FUNC("uao_get"); UVMHIST_CALLED(pdhist); | | 892 | UVMHIST_FUNC("uao_get"); UVMHIST_CALLED(pdhist); |
926 | | | 893 | |
927 | UVMHIST_LOG(pdhist, "aobj=%p offset=%d, flags=%d", | | 894 | UVMHIST_LOG(pdhist, "aobj=%p offset=%d, flags=%d", |
928 | (struct uvm_aobj *)uobj, offset, flags,0); | | 895 | (struct uvm_aobj *)uobj, offset, flags,0); |
929 | | | 896 | |
930 | /* | | 897 | /* |
931 | * get number of pages | | 898 | * get number of pages |
932 | */ | | 899 | */ |
933 | | | 900 | |
| @@ -949,27 +916,27 @@ uao_get(struct uvm_object *uobj, voff_t | | | @@ -949,27 +916,27 @@ uao_get(struct uvm_object *uobj, voff_t |
949 | gotpages = 0; /* # of pages we got so far */ | | 916 | gotpages = 0; /* # of pages we got so far */ |
950 | for (lcv = 0, current_offset = offset ; lcv < maxpages ; | | 917 | for (lcv = 0, current_offset = offset ; lcv < maxpages ; |
951 | lcv++, current_offset += PAGE_SIZE) { | | 918 | lcv++, current_offset += PAGE_SIZE) { |
952 | /* do we care about this page? if not, skip it */ | | 919 | /* do we care about this page? if not, skip it */ |
953 | if (pps[lcv] == PGO_DONTCARE) | | 920 | if (pps[lcv] == PGO_DONTCARE) |
954 | continue; | | 921 | continue; |
955 | ptmp = uvm_pagelookup(uobj, current_offset); | | 922 | ptmp = uvm_pagelookup(uobj, current_offset); |
956 | | | 923 | |
957 | /* | | 924 | /* |
958 | * if page is new, attempt to allocate the page, | | 925 | * if page is new, attempt to allocate the page, |
959 | * zero-fill'd. | | 926 | * zero-fill'd. |
960 | */ | | 927 | */ |
961 | | | 928 | |
962 | if (ptmp == NULL && uao_find_swslot(&aobj->u_obj, | | 929 | if (ptmp == NULL && uao_find_swslot(uobj, |
963 | current_offset >> PAGE_SHIFT) == 0) { | | 930 | current_offset >> PAGE_SHIFT) == 0) { |
964 | ptmp = uvm_pagealloc(uobj, current_offset, | | 931 | ptmp = uvm_pagealloc(uobj, current_offset, |
965 | NULL, UVM_FLAG_COLORMATCH|UVM_PGA_ZERO); | | 932 | NULL, UVM_FLAG_COLORMATCH|UVM_PGA_ZERO); |
966 | if (ptmp) { | | 933 | if (ptmp) { |
967 | /* new page */ | | 934 | /* new page */ |
968 | ptmp->flags &= ~(PG_FAKE); | | 935 | ptmp->flags &= ~(PG_FAKE); |
969 | ptmp->pqflags |= PQ_AOBJ; | | 936 | ptmp->pqflags |= PQ_AOBJ; |
970 | goto gotpage; | | 937 | goto gotpage; |
971 | } | | 938 | } |
972 | } | | 939 | } |
973 | | | 940 | |
974 | /* | | 941 | /* |
975 | * to be useful must get a non-busy page | | 942 | * to be useful must get a non-busy page |
| @@ -1112,27 +1079,27 @@ gotpage: | | | @@ -1112,27 +1079,27 @@ gotpage: |
1112 | /* | | 1079 | /* |
1113 | * if we own the valid page at the correct offset, pps[lcv] will | | 1080 | * if we own the valid page at the correct offset, pps[lcv] will |
1114 | * point to it. nothing more to do except go to the next page. | | 1081 | * point to it. nothing more to do except go to the next page. |
1115 | */ | | 1082 | */ |
1116 | | | 1083 | |
1117 | if (pps[lcv]) | | 1084 | if (pps[lcv]) |
1118 | continue; /* next lcv */ | | 1085 | continue; /* next lcv */ |
1119 | | | 1086 | |
1120 | /* | | 1087 | /* |
1121 | * we have a "fake/busy/clean" page that we just allocated. | | 1088 | * we have a "fake/busy/clean" page that we just allocated. |
1122 | * do the needed "i/o", either reading from swap or zeroing. | | 1089 | * do the needed "i/o", either reading from swap or zeroing. |
1123 | */ | | 1090 | */ |
1124 | | | 1091 | |
1125 | swslot = uao_find_swslot(&aobj->u_obj, pageidx); | | 1092 | swslot = uao_find_swslot(uobj, pageidx); |
1126 | | | 1093 | |
1127 | /* | | 1094 | /* |
1128 | * just zero the page if there's nothing in swap. | | 1095 | * just zero the page if there's nothing in swap. |
1129 | */ | | 1096 | */ |
1130 | | | 1097 | |
1131 | if (swslot == 0) { | | 1098 | if (swslot == 0) { |
1132 | | | 1099 | |
1133 | /* | | 1100 | /* |
1134 | * page hasn't existed before, just zero it. | | 1101 | * page hasn't existed before, just zero it. |
1135 | */ | | 1102 | */ |
1136 | | | 1103 | |
1137 | uvm_pagezero(ptmp); | | 1104 | uvm_pagezero(ptmp); |
1138 | } else { | | 1105 | } else { |
| @@ -1381,50 +1348,51 @@ restart: | | | @@ -1381,50 +1348,51 @@ restart: |
1381 | */ | | 1348 | */ |
1382 | | | 1349 | |
1383 | rv = uao_pagein_page(aobj, i); | | 1350 | rv = uao_pagein_page(aobj, i); |
1384 | if (rv) { | | 1351 | if (rv) { |
1385 | return rv; | | 1352 | return rv; |
1386 | } | | 1353 | } |
1387 | } | | 1354 | } |
1388 | } | | 1355 | } |
1389 | | | 1356 | |
1390 | return false; | | 1357 | return false; |
1391 | } | | 1358 | } |
1392 | | | 1359 | |
1393 | /* | | 1360 | /* |
1394 | * page in a page from an aobj. used for swap_off. | | 1361 | * uao_pagein_page: page in a single page from an anonymous UVM object. |
1395 | * returns true if pagein was aborted due to lack of memory. | | | |
1396 | * | | 1362 | * |
1397 | * => aobj must be locked and is returned locked. | | 1363 | * => Returns true if pagein was aborted due to lack of memory. |
| | | 1364 | * => Object must be locked and is returned locked. |
1398 | */ | | 1365 | */ |
1399 | | | 1366 | |
1400 | static bool | | 1367 | static bool |
1401 | uao_pagein_page(struct uvm_aobj *aobj, int pageidx) | | 1368 | uao_pagein_page(struct uvm_aobj *aobj, int pageidx) |
1402 | { | | 1369 | { |
| | | 1370 | struct uvm_object *uobj = &aobj->u_obj; |
1403 | struct vm_page *pg; | | 1371 | struct vm_page *pg; |
1404 | int rv, npages; | | 1372 | int rv, npages; |
1405 | | | 1373 | |
1406 | pg = NULL; | | 1374 | pg = NULL; |
1407 | npages = 1; | | 1375 | npages = 1; |
1408 | /* locked: aobj */ | | 1376 | |
1409 | rv = uao_get(&aobj->u_obj, pageidx << PAGE_SHIFT, | | 1377 | KASSERT(mutex_owned(uobj->vmobjlock)); |
1410 | &pg, &npages, 0, VM_PROT_READ|VM_PROT_WRITE, 0, PGO_SYNCIO); | | 1378 | rv = uao_get(uobj, pageidx << PAGE_SHIFT, &pg, &npages, |
1411 | /* unlocked: aobj */ | | 1379 | 0, VM_PROT_READ | VM_PROT_WRITE, 0, PGO_SYNCIO); |
1412 | | | 1380 | |
1413 | /* | | 1381 | /* |
1414 | * relock and finish up. | | 1382 | * relock and finish up. |
1415 | */ | | 1383 | */ |
1416 | | | 1384 | |
1417 | mutex_enter(aobj->u_obj.vmobjlock); | | 1385 | mutex_enter(uobj->vmobjlock); |
1418 | switch (rv) { | | 1386 | switch (rv) { |
1419 | case 0: | | 1387 | case 0: |
1420 | break; | | 1388 | break; |
1421 | | | 1389 | |
1422 | case EIO: | | 1390 | case EIO: |
1423 | case ERESTART: | | 1391 | case ERESTART: |
1424 | | | 1392 | |
1425 | /* | | 1393 | /* |
1426 | * nothing more to do on errors. | | 1394 | * nothing more to do on errors. |
1427 | * ERESTART can only mean that the anon was freed, | | 1395 | * ERESTART can only mean that the anon was freed, |
1428 | * so again there's nothing to do. | | 1396 | * so again there's nothing to do. |
1429 | */ | | 1397 | */ |
1430 | | | 1398 | |
| @@ -1458,37 +1426,30 @@ uao_pagein_page(struct uvm_aobj *aobj, i | | | @@ -1458,37 +1426,30 @@ uao_pagein_page(struct uvm_aobj *aobj, i |
1458 | } | | 1426 | } |
1459 | | | 1427 | |
1460 | /* | | 1428 | /* |
1461 | * uao_dropswap_range: drop swapslots in the range. | | 1429 | * uao_dropswap_range: drop swapslots in the range. |
1462 | * | | 1430 | * |
1463 | * => aobj must be locked and is returned locked. | | 1431 | * => aobj must be locked and is returned locked. |
1464 | * => start is inclusive. end is exclusive. | | 1432 | * => start is inclusive. end is exclusive. |
1465 | */ | | 1433 | */ |
1466 | | | 1434 | |
1467 | void | | 1435 | void |
1468 | uao_dropswap_range(struct uvm_object *uobj, voff_t start, voff_t end) | | 1436 | uao_dropswap_range(struct uvm_object *uobj, voff_t start, voff_t end) |
1469 | { | | 1437 | { |
1470 | struct uvm_aobj *aobj = (struct uvm_aobj *)uobj; | | 1438 | struct uvm_aobj *aobj = (struct uvm_aobj *)uobj; |
| | | 1439 | int swpgonlydelta = 0; |
1471 | | | 1440 | |
1472 | KASSERT(mutex_owned(uobj->vmobjlock)); | | 1441 | KASSERT(mutex_owned(uobj->vmobjlock)); |
1473 | | | 1442 | |
1474 | uao_dropswap_range1(aobj, start, end); | | | |
1475 | } | | | |
1476 | | | | |
1477 | static void | | | |
1478 | uao_dropswap_range1(struct uvm_aobj *aobj, voff_t start, voff_t end) | | | |
1479 | { | | | |
1480 | int swpgonlydelta = 0; | | | |
1481 | | | | |
1482 | if (end == 0) { | | 1443 | if (end == 0) { |
1483 | end = INT64_MAX; | | 1444 | end = INT64_MAX; |
1484 | } | | 1445 | } |
1485 | | | 1446 | |
1486 | if (UAO_USES_SWHASH(aobj)) { | | 1447 | if (UAO_USES_SWHASH(aobj)) { |
1487 | int i, hashbuckets = aobj->u_swhashmask + 1; | | 1448 | int i, hashbuckets = aobj->u_swhashmask + 1; |
1488 | voff_t taghi; | | 1449 | voff_t taghi; |
1489 | voff_t taglo; | | 1450 | voff_t taglo; |
1490 | | | 1451 | |
1491 | taglo = UAO_SWHASH_ELT_TAG(start); | | 1452 | taglo = UAO_SWHASH_ELT_TAG(start); |
1492 | taghi = UAO_SWHASH_ELT_TAG(end); | | 1453 | taghi = UAO_SWHASH_ELT_TAG(end); |
1493 | | | 1454 | |
1494 | for (i = 0; i < hashbuckets; i++) { | | 1455 | for (i = 0; i < hashbuckets; i++) { |