X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/blobdiff_plain/41e5d54678673b39f2d6ae43a291fb79c5c3f45b..e0fb398bfbef1fb6d12dfb8308cdc83ce663cbc2:/sbin/swapon/swapon.c diff --git a/sbin/swapon/swapon.c b/sbin/swapon/swapon.c index ff807ec622..3a119e0e50 100644 --- a/sbin/swapon/swapon.c +++ b/sbin/swapon/swapon.c @@ -33,9 +33,15 @@ * @(#) Copyright (c) 1980, 1993 The Regents of the University of California. All rights reserved. * @(#)swapon.c 8.1 (Berkeley) 6/5/93 * $FreeBSD: src/sbin/swapon/swapon.c,v 1.8.2.2 2001/07/30 10:30:11 dd Exp $ - * $DragonFly: src/sbin/swapon/swapon.c,v 1.5 2005/11/06 12:50:21 swildner Exp $ */ +#include +#include +#include +#include +#include +#include + #include #include #include @@ -43,58 +49,242 @@ #include #include #include +#include +#include static void usage(void); -int add(char *name, int ignoreebusy); +static int swap_on_off(char *name, int doingall, int trim); +static void swaplist(int lflag, int sflag, int hflag); + +enum { SWAPON, SWAPOFF, SWAPCTL } orig_prog, which_prog = SWAPCTL; int main(int argc, char **argv) { struct fstab *fsp; - int stat; - int ch, doall; + char *ptr; + int ret; + int ch; + int doall, sflag, lflag, hflag, qflag, eflag; + + if ((ptr = strrchr(argv[0], '/')) == NULL) + ptr = argv[0]; + if (strstr(ptr, "swapon")) + which_prog = SWAPON; + else if (strstr(ptr, "swapoff")) + which_prog = SWAPOFF; + orig_prog = which_prog; - doall = 0; - while ((ch = getopt(argc, argv, "a")) != -1) + sflag = lflag = hflag = qflag = doall = eflag = 0; + while ((ch = getopt(argc, argv, "AadeghklmqsU")) != -1) { switch((char)ch) { + case 'A': + if (which_prog == SWAPCTL) { + doall = 1; + which_prog = SWAPON; + } else { + usage(); + } + break; case 'a': - doall = 1; + if (which_prog == SWAPON || which_prog == SWAPOFF) + doall = 1; + else + which_prog = SWAPON; + break; + case 'd': + if (which_prog == SWAPCTL) + which_prog = SWAPOFF; + else + usage(); + break; + case 'e': + eflag = 1; + break; + case 'g': + hflag = 'G'; + break; + case 'h': + hflag = 'H'; + break; + case 'k': + hflag = 'K'; + break; + case 'l': + lflag = 1; + break; + case 'm': + hflag = 'M'; + break; + case 'q': + if (which_prog == SWAPON || which_prog == SWAPOFF) + qflag = 1; + break; + case 's': + sflag = 1; + break; + case 'U': + if (which_prog == SWAPCTL) { + doall = 1; + which_prog = SWAPOFF; + } else { + usage(); + } break; case '?': default: usage(); } + } argv += optind; - stat = 0; - if (doall) - while ((fsp = getfsent()) != NULL) { - if (strcmp(fsp->fs_type, FSTAB_SW)) - continue; - if (strstr(fsp->fs_mntops, "noauto")) - continue; - if (add(fsp->fs_spec, 1)) - stat = 1; - else - printf("swapon: adding %s as swap device\n", - fsp->fs_spec); + ret = 0; + if (which_prog == SWAPON || which_prog == SWAPOFF) { + if (doall) { + while ((fsp = getfsent()) != NULL) { + if (strcmp(fsp->fs_type, FSTAB_SW)) + continue; + if (strstr(fsp->fs_mntops, "noauto")) + continue; + if (swap_on_off(fsp->fs_spec, 1, eflag)) { + ret = 1; + } else { + if (!qflag) { + printf("%s: %sing %s as swap device\n", + getprogname(), + which_prog == SWAPOFF ? "remov" : "add", + fsp->fs_spec); + } + } + } + } else if (*argv == NULL) { + usage(); } - else if (!*argv) - usage(); - for (; *argv; ++argv) - stat |= add(*argv, 0); - exit(stat); + for (; *argv; ++argv) { + if (swap_on_off(getdevpath(*argv, 0), 0, eflag)) { + ret = 1; + } else if (orig_prog == SWAPCTL) { + printf("%s: %sing %s as swap device\n", + getprogname(), + which_prog == SWAPOFF ? "remov" : "add", + *argv); + } + } + } else { + if (lflag || sflag) + swaplist(lflag, sflag, hflag); + else + usage(); + } + exit(ret); } -int -add(char *name, int ignoreebusy) +/* + * TRIM the device + */ +static +void +trim_volume(char * name) +{ + struct partinfo pinfo; + int fd,i,n; + size_t bytes = 0,ksize; + char *xswbuf; + struct xswdev *xsw; + + + /* + * Determine if this device is already being used by swap without + * calling swapon(). + */ + if ((sysctlbyname("vm.swap_info_array", NULL, &bytes, NULL, 0) < 0) || + bytes == 0) { + err(1, "sysctlbyname()"); + } + + xswbuf = malloc(bytes); + if ((sysctlbyname("vm.swap_info_array", xswbuf, &bytes, NULL, 0) < 0) || + bytes == 0) { + free(xswbuf); + err(1, "sysctlbyname()"); + } + + ksize = ((struct xswdev *)xswbuf)->xsw_size; + n = (int)(bytes / ksize); + for (i = 0; i < n; ++i) { + xsw = (void *)((char *)xswbuf + i * ksize); + + if (xsw->xsw_dev == NODEV ) + continue; + if(!strcmp(devname(xsw->xsw_dev, S_IFCHR), + name + strlen("/dev/"))) { + warnx("%s: device already a swap device", name); + exit(1); + } + } + + /* + * Get the size and offset of this parititon/device + */ + fd = open(name, O_RDWR); + if (fd < 0) + err(1, "Unable to open %s R+W", name); + if (ioctl(fd, DIOCGPART, &pinfo) < 0) { + printf("Cannot trim regular file\n"); + usage (); + } + off_t ioarg[2]; + + /*Trim the Device*/ + ioarg[0] = pinfo.media_offset; + ioarg[1] = pinfo.media_size; + printf("Trimming Device:%s, sectors (%llu -%llu)\n",name, + (unsigned long long)ioarg[0]/512, + (unsigned long long)ioarg[1]/512); + if (ioctl(fd, IOCTLTRIM, ioarg) < 0) { + printf("Device trim failed\n"); + usage (); + } + close(fd); +} + +static int +swap_on_off(char *name, int doingall, int trim) { - if (swapon(name) == -1) { - switch (errno) { + if (which_prog == SWAPON && trim){ + char sysctl_name[64]; + int trim_enabled = 0; + size_t olen = sizeof(trim_enabled); + char *dev_name = strdup(name); + dev_name = strtok(dev_name + strlen("/dev/da"),"s"); + sprintf(sysctl_name, "kern.cam.da.%s.trim_enabled", dev_name); + sysctlbyname(sysctl_name, &trim_enabled, &olen, NULL, 0); + if(errno == ENOENT) { + printf("Device:%s does not support the TRIM command\n", + name); + usage(); + } + if(!trim_enabled) { + printf("Erase device option selected, but sysctl (%s) " + "is not enabled\n",sysctl_name); + usage(); + } + + trim_volume(name); + + } + if ((which_prog == SWAPOFF ? swapoff(name) : swapon(name)) == -1) { + switch(errno) { case EBUSY: - if (!ignoreebusy) + if (!doingall) warnx("%s: device already in use", name); break; + case EINVAL: + if (which_prog == SWAPON) + warnx("%s: NSWAPDEV limit reached", name); + else if (!doingall) + warn("%s", name); + break; default: warn("%s", name); break; @@ -107,6 +297,134 @@ add(char *name, int ignoreebusy) static void usage(void) { - fprintf(stderr, "usage: swapon [-a] [special_file ...]\n"); + fprintf(stderr, "usage: %s ", getprogname()); + switch (orig_prog) { + case SWAPON: + case SWAPOFF: + fprintf(stderr, "-aeq | file ...\n"); + break; + case SWAPCTL: + fprintf(stderr, "[-AeghklmsU] [-a file ... | -d file ...]\n"); + break; + } exit(1); } + +static void +sizetobuf(char *buf, size_t bufsize, int hflag, long long val, int hlen, + long blocksize) +{ + if (hflag == 'H') { + char tmp[16]; + + humanize_number(tmp, 5, (int64_t)val, "", HN_AUTOSCALE, + HN_B | HN_NOSPACE | HN_DECIMAL); + snprintf(buf, bufsize, "%*s", hlen, tmp); + } else { + snprintf(buf, bufsize, "%*lld", hlen, val / blocksize); + } +} + +static void +swaplist(int lflag, int sflag, int hflag) +{ + size_t ksize, bytes = 0; + char *xswbuf; + struct xswdev *xsw; + int hlen, pagesize; + int i, n; + long blocksize; + long long total, used, tmp_total, tmp_used; + char buf[32]; + + pagesize = getpagesize(); + switch(hflag) { + case 'G': + blocksize = 1024 * 1024 * 1024; + strlcpy(buf, "1GB-blocks", sizeof(buf)); + hlen = 10; + break; + case 'H': + blocksize = -1; + strlcpy(buf, "Bytes", sizeof(buf)); + hlen = 10; + break; + case 'K': + blocksize = 1024; + strlcpy(buf, "1kB-blocks", sizeof(buf)); + hlen = 10; + break; + case 'M': + blocksize = 1024 * 1024; + strlcpy(buf, "1MB-blocks", sizeof(buf)); + hlen = 10; + break; + default: + getbsize(&hlen, &blocksize); + snprintf(buf, sizeof(buf), "%ld-blocks", blocksize); + break; + } + + if (sysctlbyname("vm.swap_info_array", NULL, &bytes, NULL, 0) < 0) + err(1, "sysctlbyname()"); + if (bytes == 0) + err(1, "sysctlbyname()"); + + xswbuf = malloc(bytes); + if (sysctlbyname("vm.swap_info_array", xswbuf, &bytes, NULL, 0) < 0) { + free(xswbuf); + err(1, "sysctlbyname()"); + } + if (bytes == 0) { + free(xswbuf); + err(1, "sysctlbyname()"); + } + + /* + * Calculate size of xsw entry returned by kernel (it can be larger + * than the one we have if there is a version mismatch). + */ + ksize = ((struct xswdev *)xswbuf)->xsw_size; + n = (int)(bytes / ksize); + + if (lflag) { + printf("%-13s %*s %*s\n", + "Device:", + hlen, buf, + hlen, "Used:"); + } + + total = used = tmp_total = tmp_used = 0; + for (i = 0; i < n; ++i) { + xsw = (void *)((char *)xswbuf + i * ksize); + + if (xsw->xsw_nblks == 0) + continue; + + tmp_total = (long long)xsw->xsw_nblks * pagesize; + tmp_used = (long long)xsw->xsw_used * pagesize; + total += tmp_total; + used += tmp_used; + if (lflag) { + sizetobuf(buf, sizeof(buf), hflag, tmp_total, hlen, + blocksize); + if (xsw->xsw_dev == NODEV) { + printf("%-13s %s ", "[NFS swap]", buf); + } else { + printf("/dev/%-8s %s ", + devname(xsw->xsw_dev, S_IFCHR), buf); + } + + sizetobuf(buf, sizeof(buf), hflag, tmp_used, hlen, + blocksize); + printf("%s\n", buf); + } + } + + if (sflag) { + sizetobuf(buf, sizeof(buf), hflag, total, hlen, blocksize); + printf("Total: %s ", buf); + sizetobuf(buf, sizeof(buf), hflag, used, hlen, blocksize); + printf("%s\n", buf); + } +}