Print this page
re #13613 rb4516 Tunables needs volatile keyword
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/fs/swapfs/swap_subr.c
+++ new/usr/src/uts/common/fs/swapfs/swap_subr.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.
|
↓ open down ↓ |
14 lines elided |
↑ open up ↑ |
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 2009 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 +/*
26 + * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
27 + */
25 28
26 29 #include <sys/types.h>
27 30 #include <sys/param.h>
28 31 #include <sys/systm.h>
29 32 #include <sys/errno.h>
30 33 #include <sys/kmem.h>
31 34 #include <sys/vnode.h>
32 35 #include <sys/vfs_opreg.h>
33 36 #include <sys/swap.h>
34 37 #include <sys/sysmacros.h>
35 38 #include <sys/buf.h>
36 39 #include <sys/callb.h>
37 40 #include <sys/debug.h>
38 41 #include <vm/seg.h>
39 42 #include <sys/fs/swapnode.h>
40 43 #include <fs/fs_subr.h>
41 44 #include <sys/cmn_err.h>
42 45 #include <sys/mem_config.h>
43 46 #include <sys/atomic.h>
44 47
45 48 extern const fs_operation_def_t swap_vnodeops_template[];
46 49
47 50 /*
48 51 * swapfs_minfree is the amount of physical memory (actually remaining
49 52 * availrmem) that we want to keep free for the rest of the system. This
|
↓ open down ↓ |
15 lines elided |
↑ open up ↑ |
50 53 * means that swapfs can only grow to availrmem - swapfs_minfree. This
51 54 * can be set as just constant value or a certain percentage of installed
52 55 * physical memory. It is set in swapinit().
53 56 *
54 57 * Users who want to change the amount of memory that can be used as swap
55 58 * space should do so by setting swapfs_desfree at boot time,
56 59 * not swapfs_minfree.
57 60 */
58 61
59 62 pgcnt_t swapfs_desfree = 0;
60 -pgcnt_t swapfs_minfree = 0;
61 -pgcnt_t swapfs_reserve = 0;
63 +volatile pgcnt_t swapfs_minfree = 0;
64 +volatile pgcnt_t swapfs_reserve = 0;
62 65
63 66 #ifdef SWAPFS_DEBUG
64 67 int swapfs_debug;
65 68 #endif /* SWAPFS_DEBUG */
66 69
67 70
68 71 static int swapfs_vpcount;
69 72 static kmutex_t swapfs_lock;
70 73 static struct async_reqs *sw_ar, *sw_pendlist, *sw_freelist;
71 74
72 75 static struct vnode **swap_vnodes; /* ptr's to swap vnodes */
73 76
74 77 static void swap_init_mem_config(void);
75 78
76 79 static pgcnt_t initial_swapfs_desfree;
77 80 static pgcnt_t initial_swapfs_minfree;
78 81 static pgcnt_t initial_swapfs_reserve;
79 82
80 83 static int swap_sync(struct vfs *vfsp, short flag, struct cred *cr);
81 84
82 85 static void
83 86 swapfs_recalc_save_initial(void)
84 87 {
85 88 initial_swapfs_desfree = swapfs_desfree;
86 89 initial_swapfs_minfree = swapfs_minfree;
87 90 initial_swapfs_reserve = swapfs_reserve;
88 91 }
89 92
90 93 static int
91 94 swapfs_recalc(pgcnt_t pgs)
92 95 {
93 96 pgcnt_t new_swapfs_desfree;
94 97 pgcnt_t new_swapfs_minfree;
95 98 pgcnt_t new_swapfs_reserve;
96 99
97 100 new_swapfs_desfree = initial_swapfs_desfree;
98 101 new_swapfs_minfree = initial_swapfs_minfree;
99 102 new_swapfs_reserve = initial_swapfs_reserve;
100 103
101 104 if (new_swapfs_desfree == 0)
102 105 new_swapfs_desfree = btopr(7 * 512 * 1024); /* 3-1/2Mb */;
103 106
104 107 if (new_swapfs_minfree == 0) {
105 108 /*
106 109 * We set this lower than we'd like here, 2Mb, because we
107 110 * always boot on swapfs. It's up to a safer value,
108 111 * swapfs_desfree, when/if we add physical swap devices
109 112 * in swapadd(). Users who want to change the amount of
110 113 * memory that can be used as swap space should do so by
111 114 * setting swapfs_desfree at boot time, not swapfs_minfree.
112 115 * However, swapfs_minfree is tunable by install as a
113 116 * workaround for bugid 1147463.
114 117 */
115 118 new_swapfs_minfree = MAX(btopr(2 * 1024 * 1024), pgs >> 3);
116 119 }
117 120
118 121 /*
119 122 * priv processes can reserve memory as swap as long as availrmem
120 123 * remains greater than swapfs_minfree; in the case of non-priv
121 124 * processes, memory can be reserved as swap only if availrmem
122 125 * doesn't fall below (swapfs_minfree + swapfs_reserve). Thus,
123 126 * swapfs_reserve amount of memswap is not available to non-priv
124 127 * processes. This protects daemons such as automounter dying
125 128 * as a result of application processes eating away almost entire
126 129 * membased swap. This safeguard becomes useless if apps are run
127 130 * with root access.
128 131 *
129 132 * set swapfs_reserve to a minimum of 4Mb or 1/128 of physmem whichever
130 133 * is greater up to the limit of 128 MB.
131 134 */
132 135 if (new_swapfs_reserve == 0)
133 136 new_swapfs_reserve = MIN(btopr(128 * 1024 * 1024),
134 137 MAX(btopr(4 * 1024 * 1024), pgs >> 7));
135 138
136 139 /* Test basic numeric viability. */
137 140 if (new_swapfs_minfree > pgs)
138 141 return (0);
139 142
140 143 /* Equivalent test to anon_resvmem() check. */
141 144 if (availrmem < new_swapfs_minfree) {
142 145 /*
143 146 * If ism pages are being used, then there must be agreement
144 147 * between these two policies.
145 148 */
146 149 if ((availrmem > segspt_minfree) && (segspt_minfree > 0)) {
147 150 new_swapfs_minfree = segspt_minfree;
148 151 } else {
149 152 return (0);
150 153 }
151 154 }
152 155
153 156 swapfs_desfree = new_swapfs_desfree;
154 157 swapfs_minfree = new_swapfs_minfree;
155 158 swapfs_reserve = new_swapfs_reserve;
156 159
157 160 return (1);
158 161 }
159 162
160 163 /*ARGSUSED1*/
161 164 int
162 165 swapinit(int fstype, char *name)
163 166 { /* reserve for mp */
164 167 ssize_t sw_freelist_size = klustsize / PAGESIZE * 2;
165 168 int i, error;
166 169
167 170 static const fs_operation_def_t swap_vfsops[] = {
168 171 VFSNAME_SYNC, { .vfs_sync = swap_sync },
169 172 NULL, NULL
170 173 };
171 174
172 175 SWAPFS_PRINT(SWAP_SUBR, "swapinit\n", 0, 0, 0, 0, 0);
173 176 mutex_init(&swapfs_lock, NULL, MUTEX_DEFAULT, NULL);
174 177
175 178 swap_vnodes = kmem_zalloc(MAX_SWAP_VNODES * sizeof (struct vnode *),
176 179 KM_SLEEP);
177 180
178 181 swapfs_recalc_save_initial();
179 182 if (!swapfs_recalc(physmem))
180 183 cmn_err(CE_PANIC, "swapfs_minfree(%lu) > physmem(%lu)",
181 184 swapfs_minfree, physmem);
182 185
183 186 /*
184 187 * Arrange for a callback on memory size change.
185 188 */
186 189 swap_init_mem_config();
187 190
188 191 sw_ar = (struct async_reqs *)
189 192 kmem_zalloc(sw_freelist_size*sizeof (struct async_reqs), KM_SLEEP);
190 193
191 194 error = vfs_setfsops(fstype, swap_vfsops, NULL);
192 195 if (error != 0) {
193 196 cmn_err(CE_WARN, "swapinit: bad vfs ops template");
194 197 return (error);
195 198 }
196 199
197 200 error = vn_make_ops(name, swap_vnodeops_template, &swap_vnodeops);
198 201 if (error != 0) {
199 202 (void) vfs_freevfsops_by_type(fstype);
200 203 cmn_err(CE_WARN, "swapinit: bad vnode ops template");
201 204 return (error);
202 205 }
203 206 sw_freelist = sw_ar;
204 207 for (i = 0; i < sw_freelist_size - 1; i++)
205 208 sw_ar[i].a_next = &sw_ar[i + 1];
206 209
207 210 return (0);
208 211 }
209 212
210 213 /*
211 214 * Get a swapfs vnode corresponding to the specified identifier.
212 215 */
213 216 struct vnode *
214 217 swapfs_getvp(ulong_t vidx)
215 218 {
216 219 struct vnode *vp;
217 220
218 221 vp = swap_vnodes[vidx];
219 222 if (vp) {
220 223 return (vp);
221 224 }
222 225
223 226 mutex_enter(&swapfs_lock);
224 227 vp = swap_vnodes[vidx];
225 228 if (vp == NULL) {
226 229 vp = vn_alloc(KM_SLEEP);
227 230 vn_setops(vp, swap_vnodeops);
228 231 vp->v_type = VREG;
229 232 vp->v_flag |= (VISSWAP|VISSWAPFS);
230 233 swap_vnodes[vidx] = vp;
231 234 swapfs_vpcount++;
232 235 }
233 236 mutex_exit(&swapfs_lock);
234 237 return (vp);
235 238 }
236 239
237 240 int swap_lo;
238 241
239 242 /*ARGSUSED*/
240 243 static int
241 244 swap_sync(struct vfs *vfsp, short flag, struct cred *cr)
242 245 {
243 246 struct vnode *vp;
244 247 int i;
245 248
246 249 if (!(flag & SYNC_ALL))
247 250 return (1);
248 251
249 252 /*
250 253 * assumes that we are the only one left to access this so that
251 254 * no need to use swapfs_lock (since it's staticly defined)
252 255 */
253 256 for (i = 0; i < MAX_SWAP_VNODES; i++) {
254 257 vp = swap_vnodes[i];
255 258 if (vp) {
256 259 VN_HOLD(vp);
257 260 (void) VOP_PUTPAGE(vp, (offset_t)0, 0,
258 261 (B_ASYNC | B_FREE), kcred, NULL);
259 262 VN_RELE(vp);
260 263 }
261 264 }
262 265 return (0);
263 266 }
264 267
265 268 extern int sw_pending_size;
266 269
267 270 /*
268 271 * Take an async request off the pending queue
269 272 */
270 273 struct async_reqs *
271 274 sw_getreq()
272 275 {
273 276 struct async_reqs *arg;
274 277
275 278 mutex_enter(&swapfs_lock);
276 279 arg = sw_pendlist;
277 280 if (arg) {
278 281 sw_pendlist = arg->a_next;
279 282 arg->a_next = NULL;
280 283 sw_pending_size -= PAGESIZE;
281 284 }
282 285 ASSERT(sw_pending_size >= 0);
283 286 mutex_exit(&swapfs_lock);
284 287 return (arg);
285 288 }
286 289
287 290 /*
288 291 * Put an async request on the pending queue
289 292 */
290 293 void
291 294 sw_putreq(struct async_reqs *arg)
292 295 {
293 296 /* Hold onto it */
294 297 VN_HOLD(arg->a_vp);
295 298
296 299 mutex_enter(&swapfs_lock);
297 300 arg->a_next = sw_pendlist;
298 301 sw_pendlist = arg;
299 302 sw_pending_size += PAGESIZE;
300 303 mutex_exit(&swapfs_lock);
301 304 }
302 305
303 306 /*
304 307 * Put an async request back on the pending queue
305 308 */
306 309 void
307 310 sw_putbackreq(struct async_reqs *arg)
308 311 {
309 312 mutex_enter(&swapfs_lock);
310 313 arg->a_next = sw_pendlist;
311 314 sw_pendlist = arg;
312 315 sw_pending_size += PAGESIZE;
313 316 mutex_exit(&swapfs_lock);
314 317 }
315 318
316 319 /*
317 320 * Take an async request structure off the free list
318 321 */
319 322 struct async_reqs *
320 323 sw_getfree()
321 324 {
322 325 struct async_reqs *arg;
323 326
324 327 mutex_enter(&swapfs_lock);
325 328 arg = sw_freelist;
326 329 if (arg) {
327 330 sw_freelist = arg->a_next;
328 331 arg->a_next = NULL;
329 332 }
330 333 mutex_exit(&swapfs_lock);
331 334 return (arg);
332 335 }
333 336
334 337 /*
335 338 * Put an async request structure on the free list
336 339 */
337 340 void
338 341 sw_putfree(struct async_reqs *arg)
339 342 {
340 343 /* Release our hold - should have locked the page by now */
341 344 VN_RELE(arg->a_vp);
342 345
343 346 mutex_enter(&swapfs_lock);
344 347 arg->a_next = sw_freelist;
345 348 sw_freelist = arg;
346 349 mutex_exit(&swapfs_lock);
347 350 }
348 351
349 352 static pgcnt_t swapfs_pending_delete;
350 353
351 354 /*ARGSUSED*/
352 355 static void
353 356 swap_mem_config_post_add(
354 357 void *arg,
355 358 pgcnt_t delta_swaps)
356 359 {
357 360 (void) swapfs_recalc(physmem - swapfs_pending_delete);
358 361 }
359 362
360 363 /*ARGSUSED*/
361 364 static int
362 365 swap_mem_config_pre_del(
363 366 void *arg,
364 367 pgcnt_t delta_swaps)
365 368 {
366 369 pgcnt_t nv;
367 370
368 371 nv = atomic_add_long_nv(&swapfs_pending_delete, (spgcnt_t)delta_swaps);
369 372 if (!swapfs_recalc(physmem - nv)) {
370 373 /*
371 374 * Tidy-up is done by the call to post_del which
372 375 * is always made.
373 376 */
374 377 cmn_err(CE_NOTE, "Memory operation refused to ensure system "
375 378 "doesn't deadlock due to excessive consumption by swapfs.");
376 379 return (EBUSY);
377 380 }
378 381 return (0);
379 382 }
380 383
381 384 /*ARGSUSED*/
382 385 static void
383 386 swap_mem_config_post_del(
384 387 void *arg,
385 388 pgcnt_t delta_swaps,
386 389 int cancelled)
387 390 {
388 391 pgcnt_t nv;
389 392
390 393 nv = atomic_add_long_nv(&swapfs_pending_delete, -(spgcnt_t)delta_swaps);
391 394 (void) swapfs_recalc(physmem - nv);
392 395 }
393 396
394 397 static kphysm_setup_vector_t swap_mem_config_vec = {
395 398 KPHYSM_SETUP_VECTOR_VERSION,
396 399 swap_mem_config_post_add,
397 400 swap_mem_config_pre_del,
398 401 swap_mem_config_post_del,
399 402 };
400 403
401 404 static void
402 405 swap_init_mem_config(void)
403 406 {
404 407 int ret;
405 408
406 409 ret = kphysm_setup_func_register(&swap_mem_config_vec, (void *)NULL);
407 410 ASSERT(ret == 0);
408 411 }
|
↓ open down ↓ |
337 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX