Print this page
use NULL dump segop as a shorthand for no-op
Instead of forcing every segment driver to implement a dummy function that
does nothing, handle NULL dump segop function pointer as a no-op shorthand.
const-ify make segment ops structures
There is no reason to keep the segment ops structures writable.
use NULL setpagesize segop as a shorthand for ENOTSUP
Instead of forcing every segment driver to implement a dummp function to
return (hopefully) ENOTSUP, handle NULL setpagesize segop function pointer
as "return ENOTSUP" shorthand.
use NULL getmemid segop as a shorthand for ENODEV
Instead of forcing every segment driver to implement a dummy function to
return (hopefully) ENODEV, handle NULL getmemid segop function pointer as
"return ENODEV" shorthand.
segop_getpolicy already checks for a NULL op
no need for bad-op segment op functions
The segment drivers have a number of bad-op functions that simply panic.
Keeping the function pointer NULL will accomplish the same thing in most
cases. In other cases, keeping the function pointer NULL will result in
proper error code being returned.
use C99 initializers in segment ops structures
remove whole-process swapping
Long before Unix supported paging, it used process swapping to reclaim
memory. The code is there and in theory it runs when we get *extremely* low
on memory. In practice, it never runs since the definition of low-on-memory
is antiquated. (XXX: define what antiquated means)
You can check the number of swapout/swapin events with kstats:
$ kstat -p ::vm:swapin ::vm:swapout
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/sparc/v9/vm/seg_nf.c
+++ new/usr/src/uts/sparc/v9/vm/seg_nf.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
↓ open down ↓ |
23 lines elided |
↑ open up ↑ |
24 24 */
25 25
26 26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27 27 /* All Rights Reserved */
28 28
29 29 /*
30 30 * Portions of this source code were derived from Berkeley 4.3 BSD
31 31 * under license from the Regents of the University of California.
32 32 */
33 33
34 -#pragma ident "%Z%%M% %I% %E% SMI"
35 -
36 34 /*
37 35 * VM - segment for non-faulting loads.
38 36 */
39 37
40 38 #include <sys/types.h>
41 39 #include <sys/t_lock.h>
42 40 #include <sys/param.h>
43 41 #include <sys/mman.h>
44 42 #include <sys/errno.h>
45 43 #include <sys/kmem.h>
46 44 #include <sys/cmn_err.h>
47 45 #include <sys/vnode.h>
48 46 #include <sys/proc.h>
49 47 #include <sys/conf.h>
50 48 #include <sys/debug.h>
51 49 #include <sys/archsystm.h>
52 50 #include <sys/lgrp.h>
53 51
54 52 #include <vm/page.h>
55 53 #include <vm/hat.h>
56 54 #include <vm/as.h>
57 55 #include <vm/seg.h>
58 56 #include <vm/vpage.h>
59 57
60 58 /*
↓ open down ↓ |
15 lines elided |
↑ open up ↑ |
61 59 * Private seg op routines.
62 60 */
63 61 static int segnf_dup(struct seg *seg, struct seg *newseg);
64 62 static int segnf_unmap(struct seg *seg, caddr_t addr, size_t len);
65 63 static void segnf_free(struct seg *seg);
66 64 static faultcode_t segnf_nomap(void);
67 65 static int segnf_setprot(struct seg *seg, caddr_t addr,
68 66 size_t len, uint_t prot);
69 67 static int segnf_checkprot(struct seg *seg, caddr_t addr,
70 68 size_t len, uint_t prot);
71 -static void segnf_badop(void);
72 69 static int segnf_nop(void);
73 70 static int segnf_getprot(struct seg *seg, caddr_t addr,
74 71 size_t len, uint_t *protv);
75 72 static u_offset_t segnf_getoffset(struct seg *seg, caddr_t addr);
76 73 static int segnf_gettype(struct seg *seg, caddr_t addr);
77 74 static int segnf_getvp(struct seg *seg, caddr_t addr, struct vnode **vpp);
78 -static void segnf_dump(struct seg *seg);
79 75 static int segnf_pagelock(struct seg *seg, caddr_t addr, size_t len,
80 76 struct page ***ppp, enum lock_type type, enum seg_rw rw);
81 -static int segnf_setpagesize(struct seg *seg, caddr_t addr, size_t len,
82 - uint_t szc);
83 -static int segnf_getmemid(struct seg *seg, caddr_t addr, memid_t *memidp);
84 -static lgrp_mem_policy_info_t *segnf_getpolicy(struct seg *seg,
85 - caddr_t addr);
86 -
87 -
88 -struct seg_ops segnf_ops = {
89 - segnf_dup,
90 - segnf_unmap,
91 - segnf_free,
92 - (faultcode_t (*)(struct hat *, struct seg *, caddr_t, size_t,
93 - enum fault_type, enum seg_rw))
94 - segnf_nomap, /* fault */
95 - (faultcode_t (*)(struct seg *, caddr_t))
96 - segnf_nomap, /* faulta */
97 - segnf_setprot,
98 - segnf_checkprot,
99 - (int (*)())segnf_badop, /* kluster */
100 - (size_t (*)(struct seg *))NULL, /* swapout */
101 - (int (*)(struct seg *, caddr_t, size_t, int, uint_t))
102 - segnf_nop, /* sync */
103 - (size_t (*)(struct seg *, caddr_t, size_t, char *))
104 - segnf_nop, /* incore */
105 - (int (*)(struct seg *, caddr_t, size_t, int, int, ulong_t *, size_t))
106 - segnf_nop, /* lockop */
107 - segnf_getprot,
108 - segnf_getoffset,
109 - segnf_gettype,
110 - segnf_getvp,
111 - (int (*)(struct seg *, caddr_t, size_t, uint_t))
112 - segnf_nop, /* advise */
113 - segnf_dump,
114 - segnf_pagelock,
115 - segnf_setpagesize,
116 - segnf_getmemid,
117 - segnf_getpolicy,
77 +
78 +
79 +const struct seg_ops segnf_ops = {
80 + .dup = segnf_dup,
81 + .unmap = segnf_unmap,
82 + .free = segnf_free,
83 + .fault = (faultcode_t (*)(struct hat *, struct seg *, caddr_t,
84 + size_t, enum fault_type, enum seg_rw))segnf_nomap,
85 + .faulta = (faultcode_t (*)(struct seg *, caddr_t)) segnf_nomap,
86 + .setprot = segnf_setprot,
87 + .checkprot = segnf_checkprot,
88 + .sync = (int (*)(struct seg *, caddr_t, size_t, int, uint_t))
89 + segnf_nop,
90 + .incore = (size_t (*)(struct seg *, caddr_t, size_t, char *))
91 + segnf_nop,
92 + .lockop = (int (*)(struct seg *, caddr_t, size_t, int, int,
93 + ulong_t *, size_t))segnf_nop,
94 + .getprot = segnf_getprot,
95 + .getoffset = segnf_getoffset,
96 + .gettype = segnf_gettype,
97 + .getvp = segnf_getvp,
98 + .advise = (int (*)(struct seg *, caddr_t, size_t, uint_t))
99 + segnf_nop,
100 + .pagelock = segnf_pagelock,
118 101 };
119 102
120 103 /*
121 104 * vnode and page for the page of zeros we use for the nf mappings.
122 105 */
123 106 static kmutex_t segnf_lock;
124 107 static struct vnode nfvp;
125 108 static struct page **nfpp;
126 109
127 110 #define addr_to_vcolor(addr) \
128 111 (shm_alignment) ? \
129 112 ((int)(((uintptr_t)(addr) & (shm_alignment - 1)) >> PAGESHIFT)) : 0
130 113
131 114 /*
132 115 * We try to limit the number of Non-fault segments created.
133 116 * Non fault segments are created to optimize sparc V9 code which uses
134 117 * the sparc nonfaulting load ASI (ASI_PRIMARY_NOFAULT).
135 118 *
136 119 * There are several reasons why creating too many non-fault segments
137 120 * could cause problems.
138 121 *
139 122 * First, excessive allocation of kernel resources for the seg
140 123 * structures and the HAT data to map the zero pages.
141 124 *
142 125 * Secondly, creating nofault segments actually uses up user virtual
143 126 * address space. This makes it unavailable for subsequent mmap(0, ...)
144 127 * calls which use as_gap() to find empty va regions. Creation of too
145 128 * many nofault segments could thus interfere with the ability of the
146 129 * runtime linker to load a shared object.
147 130 */
148 131 #define MAXSEGFORNF (10000)
149 132 #define MAXNFSEARCH (5)
150 133
151 134
152 135 /*
153 136 * Must be called from startup()
154 137 */
155 138 void
156 139 segnf_init()
157 140 {
158 141 mutex_init(&segnf_lock, NULL, MUTEX_DEFAULT, NULL);
159 142 }
160 143
161 144
162 145 /*
163 146 * Create a no-fault segment.
164 147 *
165 148 * The no-fault segment is not technically necessary, as the code in
166 149 * nfload() in trap.c will emulate the SPARC instruction and load
167 150 * a value of zero in the destination register.
168 151 *
169 152 * However, this code tries to put a page of zero's at the nofault address
170 153 * so that subsequent non-faulting loads to the same page will not
171 154 * trap with a tlb miss.
172 155 *
173 156 * In order to help limit the number of segments we merge adjacent nofault
174 157 * segments into a single segment. If we get a large number of segments
175 158 * we'll also try to delete a random other nf segment.
176 159 */
177 160 /* ARGSUSED */
178 161 int
179 162 segnf_create(struct seg *seg, void *argsp)
180 163 {
181 164 uint_t prot;
182 165 pgcnt_t vacpgs;
183 166 u_offset_t off = 0;
184 167 caddr_t vaddr = NULL;
185 168 int i, color;
186 169 struct seg *s1;
187 170 struct seg *s2;
188 171 size_t size;
189 172 struct as *as = seg->s_as;
190 173
191 174 ASSERT(as && AS_WRITE_HELD(as, &as->a_lock));
192 175
193 176 /*
194 177 * Need a page per virtual color or just 1 if no vac.
195 178 */
196 179 mutex_enter(&segnf_lock);
197 180 if (nfpp == NULL) {
198 181 struct seg kseg;
199 182
200 183 vacpgs = 1;
201 184 if (shm_alignment > PAGESIZE) {
202 185 vacpgs = shm_alignment >> PAGESHIFT;
203 186 }
204 187
205 188 nfpp = kmem_alloc(sizeof (*nfpp) * vacpgs, KM_SLEEP);
206 189
207 190 kseg.s_as = &kas;
208 191 for (i = 0; i < vacpgs; i++, off += PAGESIZE,
209 192 vaddr += PAGESIZE) {
210 193 nfpp[i] = page_create_va(&nfvp, off, PAGESIZE,
211 194 PG_WAIT | PG_NORELOC, &kseg, vaddr);
212 195 page_io_unlock(nfpp[i]);
213 196 page_downgrade(nfpp[i]);
214 197 pagezero(nfpp[i], 0, PAGESIZE);
215 198 }
216 199 }
217 200 mutex_exit(&segnf_lock);
218 201
219 202 hat_map(as->a_hat, seg->s_base, seg->s_size, HAT_MAP);
220 203
221 204 /*
222 205 * s_data can't be NULL because of ASSERTS in the common vm code.
223 206 */
224 207 seg->s_ops = &segnf_ops;
225 208 seg->s_data = seg;
226 209 seg->s_flags |= S_PURGE;
227 210
228 211 mutex_enter(&as->a_contents);
229 212 as->a_flags |= AS_NEEDSPURGE;
230 213 mutex_exit(&as->a_contents);
231 214
232 215 prot = PROT_READ;
233 216 color = addr_to_vcolor(seg->s_base);
234 217 if (as != &kas)
235 218 prot |= PROT_USER;
236 219 hat_memload(as->a_hat, seg->s_base, nfpp[color],
237 220 prot | HAT_NOFAULT, HAT_LOAD);
238 221
239 222 /*
240 223 * At this point see if we can concatenate a segment to
241 224 * a non-fault segment immediately before and/or after it.
242 225 */
243 226 if ((s1 = AS_SEGPREV(as, seg)) != NULL &&
244 227 s1->s_ops == &segnf_ops &&
245 228 s1->s_base + s1->s_size == seg->s_base) {
246 229 size = s1->s_size;
247 230 seg_free(s1);
248 231 seg->s_base -= size;
249 232 seg->s_size += size;
250 233 }
251 234
252 235 if ((s2 = AS_SEGNEXT(as, seg)) != NULL &&
253 236 s2->s_ops == &segnf_ops &&
254 237 seg->s_base + seg->s_size == s2->s_base) {
255 238 size = s2->s_size;
256 239 seg_free(s2);
257 240 seg->s_size += size;
258 241 }
259 242
260 243 /*
261 244 * if we already have a lot of segments, try to delete some other
262 245 * nofault segment to reduce the probability of uncontrolled segment
263 246 * creation.
264 247 *
265 248 * the code looks around quickly (no more than MAXNFSEARCH segments
266 249 * each way) for another NF segment and then deletes it.
267 250 */
268 251 if (avl_numnodes(&as->a_segtree) > MAXSEGFORNF) {
269 252 size = 0;
270 253 s2 = NULL;
271 254 s1 = AS_SEGPREV(as, seg);
272 255 while (size++ < MAXNFSEARCH && s1 != NULL) {
273 256 if (s1->s_ops == &segnf_ops)
274 257 s2 = s1;
275 258 s1 = AS_SEGPREV(s1->s_as, seg);
276 259 }
277 260 if (s2 == NULL) {
278 261 s1 = AS_SEGNEXT(as, seg);
279 262 while (size-- > 0 && s1 != NULL) {
280 263 if (s1->s_ops == &segnf_ops)
281 264 s2 = s1;
282 265 s1 = AS_SEGNEXT(as, seg);
283 266 }
284 267 }
285 268 if (s2 != NULL)
286 269 seg_unmap(s2);
287 270 }
288 271
289 272 return (0);
290 273 }
291 274
292 275 /*
293 276 * Never really need "No fault" segments, so they aren't dup'd.
294 277 */
295 278 /* ARGSUSED */
296 279 static int
297 280 segnf_dup(struct seg *seg, struct seg *newseg)
298 281 {
299 282 panic("segnf_dup");
300 283 return (0);
301 284 }
302 285
303 286 /*
304 287 * Split a segment at addr for length len.
305 288 */
306 289 static int
307 290 segnf_unmap(struct seg *seg, caddr_t addr, size_t len)
308 291 {
309 292 ASSERT(seg->s_as && AS_WRITE_HELD(seg->s_as, &seg->s_as->a_lock));
310 293
311 294 /*
312 295 * Check for bad sizes.
313 296 */
314 297 if (addr < seg->s_base || addr + len > seg->s_base + seg->s_size ||
315 298 (len & PAGEOFFSET) || ((uintptr_t)addr & PAGEOFFSET)) {
316 299 cmn_err(CE_PANIC, "segnf_unmap: bad unmap size");
317 300 }
318 301
319 302 /*
320 303 * Unload any hardware translations in the range to be taken out.
321 304 */
322 305 hat_unload(seg->s_as->a_hat, addr, len, HAT_UNLOAD_UNMAP);
323 306
324 307 if (addr == seg->s_base && len == seg->s_size) {
325 308 /*
326 309 * Freeing entire segment.
327 310 */
328 311 seg_free(seg);
329 312 } else if (addr == seg->s_base) {
330 313 /*
331 314 * Freeing the beginning of the segment.
332 315 */
333 316 seg->s_base += len;
334 317 seg->s_size -= len;
335 318 } else if (addr + len == seg->s_base + seg->s_size) {
336 319 /*
337 320 * Freeing the end of the segment.
338 321 */
339 322 seg->s_size -= len;
340 323 } else {
341 324 /*
342 325 * The section to go is in the middle of the segment, so we
343 326 * have to cut it into two segments. We shrink the existing
344 327 * "seg" at the low end, and create "nseg" for the high end.
345 328 */
346 329 caddr_t nbase = addr + len;
347 330 size_t nsize = (seg->s_base + seg->s_size) - nbase;
348 331 struct seg *nseg;
349 332
350 333 /*
351 334 * Trim down "seg" before trying to stick "nseg" into the as.
352 335 */
353 336 seg->s_size = addr - seg->s_base;
354 337 nseg = seg_alloc(seg->s_as, nbase, nsize);
355 338 if (nseg == NULL)
356 339 cmn_err(CE_PANIC, "segnf_unmap: seg_alloc failed");
357 340
358 341 /*
359 342 * s_data can't be NULL because of ASSERTs in common VM code.
360 343 */
361 344 nseg->s_ops = seg->s_ops;
362 345 nseg->s_data = nseg;
363 346 nseg->s_flags |= S_PURGE;
364 347 mutex_enter(&seg->s_as->a_contents);
365 348 seg->s_as->a_flags |= AS_NEEDSPURGE;
366 349 mutex_exit(&seg->s_as->a_contents);
367 350 }
368 351
369 352 return (0);
370 353 }
371 354
372 355 /*
373 356 * Free a segment.
374 357 */
375 358 static void
376 359 segnf_free(struct seg *seg)
377 360 {
378 361 ASSERT(seg->s_as && AS_WRITE_HELD(seg->s_as, &seg->s_as->a_lock));
379 362 }
380 363
381 364 /*
382 365 * No faults allowed on segnf.
383 366 */
384 367 static faultcode_t
385 368 segnf_nomap(void)
386 369 {
387 370 return (FC_NOMAP);
388 371 }
389 372
390 373 /* ARGSUSED */
391 374 static int
392 375 segnf_setprot(struct seg *seg, caddr_t addr, size_t len, uint_t prot)
393 376 {
394 377 ASSERT(seg->s_as && AS_LOCK_HELD(seg->s_as, &seg->s_as->a_lock));
395 378 return (EACCES);
396 379 }
397 380
398 381 /* ARGSUSED */
↓ open down ↓ |
271 lines elided |
↑ open up ↑ |
399 382 static int
400 383 segnf_checkprot(struct seg *seg, caddr_t addr, size_t len, uint_t prot)
401 384 {
402 385 uint_t sprot;
403 386 ASSERT(seg->s_as && AS_LOCK_HELD(seg->s_as, &seg->s_as->a_lock));
404 387
405 388 sprot = seg->s_as == &kas ? PROT_READ : PROT_READ|PROT_USER;
406 389 return ((prot & sprot) == prot ? 0 : EACCES);
407 390 }
408 391
409 -static void
410 -segnf_badop(void)
411 -{
412 - panic("segnf_badop");
413 - /*NOTREACHED*/
414 -}
415 -
416 392 static int
417 393 segnf_nop(void)
418 394 {
419 395 return (0);
420 396 }
421 397
422 398 static int
423 399 segnf_getprot(struct seg *seg, caddr_t addr, size_t len, uint_t *protv)
424 400 {
425 401 size_t pgno = seg_page(seg, addr + len) - seg_page(seg, addr) + 1;
426 402 size_t p;
427 403 ASSERT(seg->s_as && AS_LOCK_HELD(seg->s_as, &seg->s_as->a_lock));
428 404
429 405 for (p = 0; p < pgno; ++p)
430 406 protv[p] = PROT_READ;
431 407 return (0);
432 408 }
433 409
434 410 /* ARGSUSED */
435 411 static u_offset_t
436 412 segnf_getoffset(struct seg *seg, caddr_t addr)
437 413 {
438 414 ASSERT(seg->s_as && AS_LOCK_HELD(seg->s_as, &seg->s_as->a_lock));
439 415
440 416 return ((u_offset_t)0);
441 417 }
442 418
443 419 /* ARGSUSED */
444 420 static int
445 421 segnf_gettype(struct seg *seg, caddr_t addr)
446 422 {
447 423 ASSERT(seg->s_as && AS_LOCK_HELD(seg->s_as, &seg->s_as->a_lock));
448 424
449 425 return (MAP_SHARED);
450 426 }
451 427
↓ open down ↓ |
26 lines elided |
↑ open up ↑ |
452 428 /* ARGSUSED */
453 429 static int
454 430 segnf_getvp(struct seg *seg, caddr_t addr, struct vnode **vpp)
455 431 {
456 432 ASSERT(seg->s_as && AS_LOCK_HELD(seg->s_as, &seg->s_as->a_lock));
457 433
458 434 *vpp = &nfvp;
459 435 return (0);
460 436 }
461 437
462 -/*
463 - * segnf pages are not dumped, so we just return
464 - */
465 -/* ARGSUSED */
466 -static void
467 -segnf_dump(struct seg *seg)
468 -{}
469 -
470 438 /*ARGSUSED*/
471 439 static int
472 440 segnf_pagelock(struct seg *seg, caddr_t addr, size_t len,
473 441 struct page ***ppp, enum lock_type type, enum seg_rw rw)
474 442 {
475 443 return (ENOTSUP);
476 -}
477 -
478 -/*ARGSUSED*/
479 -static int
480 -segnf_setpagesize(struct seg *seg, caddr_t addr, size_t len,
481 - uint_t szc)
482 -{
483 - return (ENOTSUP);
484 -}
485 -
486 -/*ARGSUSED*/
487 -static int
488 -segnf_getmemid(struct seg *seg, caddr_t addr, memid_t *memidp)
489 -{
490 - return (ENODEV);
491 -}
492 -
493 -/*ARGSUSED*/
494 -static lgrp_mem_policy_info_t *
495 -segnf_getpolicy(struct seg *seg, caddr_t addr)
496 -{
497 - return (NULL);
498 444 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX