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