TRIM support
[dragonfly.git] / sbin / swapon / swapon.c
CommitLineData
984263bc
MD
1/*
2 * Copyright (c) 1980, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
1de703da
MD
32 *
33 * @(#) Copyright (c) 1980, 1993 The Regents of the University of California. All rights reserved.
34 * @(#)swapon.c 8.1 (Berkeley) 6/5/93
35 * $FreeBSD: src/sbin/swapon/swapon.c,v 1.8.2.2 2001/07/30 10:30:11 dd Exp $
984263bc
MD
36 */
37
9f3543c6
MD
38#include <sys/param.h>
39#include <sys/stat.h>
40#include <sys/sysctl.h>
e0fb398b
T
41#include <sys/diskslice.h>
42#include <sys/ioctl_compat.h>
9f3543c6
MD
43#include <vm/vm_param.h>
44
984263bc
MD
45#include <err.h>
46#include <errno.h>
47#include <fstab.h>
48#include <stdio.h>
49#include <stdlib.h>
50#include <string.h>
51#include <unistd.h>
9f3543c6
MD
52#include <fcntl.h>
53#include <libutil.h>
984263bc 54
9a76cd75 55static void usage(void);
e0fb398b 56static int swap_on_off(char *name, int doingall, int trim);
9f3543c6
MD
57static void swaplist(int lflag, int sflag, int hflag);
58
59enum { SWAPON, SWAPOFF, SWAPCTL } orig_prog, which_prog = SWAPCTL;
984263bc
MD
60
61int
62main(int argc, char **argv)
63{
b942f274 64 struct fstab *fsp;
9f3543c6
MD
65 char *ptr;
66 int ret;
67 int ch;
e0fb398b 68 int doall, sflag, lflag, hflag, qflag, eflag;
984263bc 69
9f3543c6
MD
70 if ((ptr = strrchr(argv[0], '/')) == NULL)
71 ptr = argv[0];
72 if (strstr(ptr, "swapon"))
73 which_prog = SWAPON;
74 else if (strstr(ptr, "swapoff"))
75 which_prog = SWAPOFF;
76 orig_prog = which_prog;
77
e0fb398b
T
78 sflag = lflag = hflag = qflag = doall = eflag = 0;
79 while ((ch = getopt(argc, argv, "AadeghklmqsU")) != -1) {
984263bc 80 switch((char)ch) {
9f3543c6
MD
81 case 'A':
82 if (which_prog == SWAPCTL) {
83 doall = 1;
84 which_prog = SWAPON;
85 } else {
86 usage();
87 }
88 break;
984263bc 89 case 'a':
9f3543c6
MD
90 if (which_prog == SWAPON || which_prog == SWAPOFF)
91 doall = 1;
92 else
93 which_prog = SWAPON;
94 break;
95 case 'd':
96 if (which_prog == SWAPCTL)
97 which_prog = SWAPOFF;
98 else
99 usage();
100 break;
e0fb398b
T
101 case 'e':
102 eflag = 1;
103 break;
9f3543c6
MD
104 case 'g':
105 hflag = 'G';
106 break;
107 case 'h':
108 hflag = 'H';
109 break;
110 case 'k':
111 hflag = 'K';
112 break;
113 case 'l':
114 lflag = 1;
115 break;
116 case 'm':
117 hflag = 'M';
118 break;
119 case 'q':
120 if (which_prog == SWAPON || which_prog == SWAPOFF)
121 qflag = 1;
122 break;
123 case 's':
124 sflag = 1;
125 break;
126 case 'U':
127 if (which_prog == SWAPCTL) {
128 doall = 1;
129 which_prog = SWAPOFF;
130 } else {
131 usage();
132 }
984263bc
MD
133 break;
134 case '?':
135 default:
136 usage();
137 }
9f3543c6 138 }
984263bc
MD
139 argv += optind;
140
9f3543c6
MD
141 ret = 0;
142 if (which_prog == SWAPON || which_prog == SWAPOFF) {
143 if (doall) {
144 while ((fsp = getfsent()) != NULL) {
145 if (strcmp(fsp->fs_type, FSTAB_SW))
146 continue;
147 if (strstr(fsp->fs_mntops, "noauto"))
148 continue;
e0fb398b 149 if (swap_on_off(fsp->fs_spec, 1, eflag)) {
9f3543c6
MD
150 ret = 1;
151 } else {
152 if (!qflag) {
153 printf("%s: %sing %s as swap device\n",
154 getprogname(),
155 which_prog == SWAPOFF ? "remov" : "add",
156 fsp->fs_spec);
157 }
158 }
159 }
160 } else if (*argv == NULL) {
161 usage();
984263bc 162 }
9f3543c6 163 for (; *argv; ++argv) {
e0fb398b 164 if (swap_on_off(getdevpath(*argv, 0), 0, eflag)) {
9f3543c6
MD
165 ret = 1;
166 } else if (orig_prog == SWAPCTL) {
167 printf("%s: %sing %s as swap device\n",
168 getprogname(),
169 which_prog == SWAPOFF ? "remov" : "add",
170 *argv);
171 }
172 }
173 } else {
174 if (lflag || sflag)
175 swaplist(lflag, sflag, hflag);
176 else
177 usage();
c4d5a9b3 178 }
9f3543c6 179 exit(ret);
984263bc
MD
180}
181
e0fb398b
T
182/*
183 * TRIM the device
184 */
185static
186void
187trim_volume(char * name)
188{
189 struct partinfo pinfo;
190 int fd,i,n;
191 size_t bytes = 0,ksize;
192 char *xswbuf;
193 struct xswdev *xsw;
194
195
196 /*
197 * Determine if this device is already being used by swap without
198 * calling swapon().
199 */
200 if ((sysctlbyname("vm.swap_info_array", NULL, &bytes, NULL, 0) < 0) ||
201 bytes == 0) {
202 err(1, "sysctlbyname()");
203 }
204
205 xswbuf = malloc(bytes);
206 if ((sysctlbyname("vm.swap_info_array", xswbuf, &bytes, NULL, 0) < 0) ||
207 bytes == 0) {
208 free(xswbuf);
209 err(1, "sysctlbyname()");
210 }
211
212 ksize = ((struct xswdev *)xswbuf)->xsw_size;
213 n = (int)(bytes / ksize);
214 for (i = 0; i < n; ++i) {
215 xsw = (void *)((char *)xswbuf + i * ksize);
216
217 if (xsw->xsw_dev == NODEV )
218 continue;
219 if(!strcmp(devname(xsw->xsw_dev, S_IFCHR),
220 name + strlen("/dev/"))) {
221 warnx("%s: device already a swap device", name);
222 exit(1);
223 }
224 }
225
226 /*
227 * Get the size and offset of this parititon/device
228 */
229 fd = open(name, O_RDWR);
230 if (fd < 0)
231 err(1, "Unable to open %s R+W", name);
232 if (ioctl(fd, DIOCGPART, &pinfo) < 0) {
233 printf("Cannot trim regular file\n");
234 usage ();
235 }
236 off_t ioarg[2];
237
238 /*Trim the Device*/
239 ioarg[0] = pinfo.media_offset;
240 ioarg[1] = pinfo.media_size;
241 printf("Trimming Device:%s, sectors (%llu -%llu)\n",name,
242 (unsigned long long)ioarg[0]/512,
243 (unsigned long long)ioarg[1]/512);
244 if (ioctl(fd, IOCTLTRIM, ioarg) < 0) {
245 printf("Device trim failed\n");
246 usage ();
247 }
248 close(fd);
249}
250
9f3543c6 251static int
e0fb398b 252swap_on_off(char *name, int doingall, int trim)
984263bc 253{
e0fb398b
T
254 if (which_prog == SWAPON && trim){
255 char sysctl_name[64];
256 int trim_enabled = 0;
257 size_t olen = sizeof(trim_enabled);
258 char *dev_name = strdup(name);
259 dev_name = strtok(dev_name + strlen("/dev/da"),"s");
260 sprintf(sysctl_name, "kern.cam.da.%s.trim_enabled", dev_name);
261 sysctlbyname(sysctl_name, &trim_enabled, &olen, NULL, 0);
262 if(errno == ENOENT) {
263 printf("Device:%s does not support the TRIM command\n",
264 name);
265 usage();
266 }
267 if(!trim_enabled) {
268 printf("Erase device option selected, but sysctl (%s) "
269 "is not enabled\n",sysctl_name);
270 usage();
271 }
272
273 trim_volume(name);
274
275 }
9f3543c6
MD
276 if ((which_prog == SWAPOFF ? swapoff(name) : swapon(name)) == -1) {
277 switch(errno) {
984263bc 278 case EBUSY:
9f3543c6 279 if (!doingall)
984263bc
MD
280 warnx("%s: device already in use", name);
281 break;
9f3543c6
MD
282 case EINVAL:
283 if (which_prog == SWAPON)
284 warnx("%s: NSWAPDEV limit reached", name);
285 else if (!doingall)
286 warn("%s", name);
287 break;
984263bc
MD
288 default:
289 warn("%s", name);
290 break;
291 }
292 return(1);
293 }
294 return(0);
295}
296
297static void
b5744197 298usage(void)
984263bc 299{
9f3543c6
MD
300 fprintf(stderr, "usage: %s ", getprogname());
301 switch (orig_prog) {
302 case SWAPON:
303 case SWAPOFF:
e0fb398b 304 fprintf(stderr, "-aeq | file ...\n");
9f3543c6
MD
305 break;
306 case SWAPCTL:
e0fb398b 307 fprintf(stderr, "[-AeghklmsU] [-a file ... | -d file ...]\n");
9f3543c6
MD
308 break;
309 }
984263bc
MD
310 exit(1);
311}
9f3543c6
MD
312
313static void
314sizetobuf(char *buf, size_t bufsize, int hflag, long long val, int hlen,
315 long blocksize)
316{
317 if (hflag == 'H') {
318 char tmp[16];
319
320 humanize_number(tmp, 5, (int64_t)val, "", HN_AUTOSCALE,
321 HN_B | HN_NOSPACE | HN_DECIMAL);
322 snprintf(buf, bufsize, "%*s", hlen, tmp);
323 } else {
324 snprintf(buf, bufsize, "%*lld", hlen, val / blocksize);
325 }
326}
327
328static void
329swaplist(int lflag, int sflag, int hflag)
330{
331 size_t ksize, bytes = 0;
332 char *xswbuf;
333 struct xswdev *xsw;
334 int hlen, pagesize;
335 int i, n;
336 long blocksize;
337 long long total, used, tmp_total, tmp_used;
338 char buf[32];
339
340 pagesize = getpagesize();
341 switch(hflag) {
342 case 'G':
343 blocksize = 1024 * 1024 * 1024;
344 strlcpy(buf, "1GB-blocks", sizeof(buf));
345 hlen = 10;
346 break;
347 case 'H':
348 blocksize = -1;
349 strlcpy(buf, "Bytes", sizeof(buf));
350 hlen = 10;
351 break;
352 case 'K':
353 blocksize = 1024;
354 strlcpy(buf, "1kB-blocks", sizeof(buf));
355 hlen = 10;
356 break;
357 case 'M':
358 blocksize = 1024 * 1024;
359 strlcpy(buf, "1MB-blocks", sizeof(buf));
360 hlen = 10;
361 break;
362 default:
363 getbsize(&hlen, &blocksize);
364 snprintf(buf, sizeof(buf), "%ld-blocks", blocksize);
365 break;
366 }
367
368 if (sysctlbyname("vm.swap_info_array", NULL, &bytes, NULL, 0) < 0)
369 err(1, "sysctlbyname()");
370 if (bytes == 0)
371 err(1, "sysctlbyname()");
372
373 xswbuf = malloc(bytes);
374 if (sysctlbyname("vm.swap_info_array", xswbuf, &bytes, NULL, 0) < 0) {
375 free(xswbuf);
376 err(1, "sysctlbyname()");
377 }
378 if (bytes == 0) {
379 free(xswbuf);
380 err(1, "sysctlbyname()");
381 }
382
383 /*
384 * Calculate size of xsw entry returned by kernel (it can be larger
385 * than the one we have if there is a version mismatch).
386 */
387 ksize = ((struct xswdev *)xswbuf)->xsw_size;
388 n = (int)(bytes / ksize);
389
390 if (lflag) {
391 printf("%-13s %*s %*s\n",
392 "Device:",
393 hlen, buf,
394 hlen, "Used:");
395 }
396
397 total = used = tmp_total = tmp_used = 0;
398 for (i = 0; i < n; ++i) {
399 xsw = (void *)((char *)xswbuf + i * ksize);
400
401 if (xsw->xsw_nblks == 0)
402 continue;
403
ebd20800
SW
404 tmp_total = (long long)xsw->xsw_nblks * pagesize;
405 tmp_used = (long long)xsw->xsw_used * pagesize;
406 total += tmp_total;
407 used += tmp_used;
9f3543c6
MD
408 if (lflag) {
409 sizetobuf(buf, sizeof(buf), hflag, tmp_total, hlen,
410 blocksize);
411 if (xsw->xsw_dev == NODEV) {
412 printf("%-13s %s ", "[NFS swap]", buf);
413 } else {
414 printf("/dev/%-8s %s ",
415 devname(xsw->xsw_dev, S_IFCHR), buf);
416 }
417
418 sizetobuf(buf, sizeof(buf), hflag, tmp_used, hlen,
419 blocksize);
420 printf("%s\n", buf);
421 }
422 }
423
424 if (sflag) {
425 sizetobuf(buf, sizeof(buf), hflag, total, hlen, blocksize);
426 printf("Total: %s ", buf);
427 sizetobuf(buf, sizeof(buf), hflag, used, hlen, blocksize);
428 printf("%s\n", buf);
429 }
430}