From a420c8119a98f5bf58f9fb965bf6b9b1d5efc81b Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Sat, 28 Dec 2002 23:39:47 +0000 Subject: [PATCH] Add 'swapctl' - as a hardlink to swapon/swapoff, and augment swapon with swapctl functionality. The idea is to create a swapctl command that is fairly close to the OpenBSD and NetBSD version. FreeBSD does not implement swap priority (and it would be a mistake if we did) so we didn't bother with that part of it. Submitted by: Eirik Nygaard Augmented by: dillon (extensively) Reviewed by: David Schultz --- sbin/swapon/Makefile | 2 + sbin/swapon/swapon.8 | 105 +++++++++++++++----- sbin/swapon/swapon.c | 223 ++++++++++++++++++++++++++++++++++--------- 3 files changed, 261 insertions(+), 69 deletions(-) diff --git a/sbin/swapon/Makefile b/sbin/swapon/Makefile index f052567e76cc..85b0f0ab60bb 100644 --- a/sbin/swapon/Makefile +++ b/sbin/swapon/Makefile @@ -4,6 +4,8 @@ PROG= swapon MAN= swapon.8 LINKS= ${BINDIR}/swapon ${BINDIR}/swapoff +LINKS+= ${BINDIR}/swapon ${BINDIR}/swapctl MLINKS= swapon.8 swapoff.8 +MLINKS+=swapon.8 swapctl.8 .include diff --git a/sbin/swapon/swapon.8 b/sbin/swapon/swapon.8 index edda998a38cc..cb6cd0098989 100644 --- a/sbin/swapon/swapon.8 +++ b/sbin/swapon/swapon.8 @@ -43,39 +43,94 @@ .Fl a .Nm swap[on|off] .Ar special_file ... +.Nm swapctl +.Fl lshk +.Nm swapctl +.Fl AU +.Nm swapctl +.Fl a +.Ar special_file ... +.Nm swapctl +.Fl d +.Ar special_file ... .Sh DESCRIPTION The +.Nm swap[on,off,ctl] +utilties are used to control swap devices in the system. At boot time all +swap entries in +.Pa /etc/fstab +are added automatically when the system goes multi-user. +Swap devices are interleaved and kernels are typically configured +to handle a maximum of 4 swap devices. There is no priority mechanism. +.Pp +The .Nm swapon -utility is used to specify additional devices on which paging and swapping -are to take place. -The system begins by swapping and paging on only a single device -so that only one disk is required at bootstrap time. -Calls to -.Nm swapon -normally occur in the system multi-user initialization file -.Pa /etc/rc -making all swap devices available, so that the paging and swapping -activity is interleaved across several devices. +utility adds the specified swap devices to the system. If the +.Fl a +option is used, all swap devices in +.Pa /etc/fstab +will be added, unless their ``noauto'' option is also set. .Pp The .Nm swapoff -utility disables paging and swapping on a device. -Calls to -.Nm swapoff -succeed only if disabling the device would leave enough -remaining virtual memory to accomodate all running programs. -.Pp -Normally, the first form is used: -.Bl -tag -width indent -.It Fl a -All devices marked as ``sw'' -swap devices in +utility removes the specified swap devices from the system. If the +.Fl a +option is used, all swap devices in .Pa /etc/fstab -are added to or removed from the pool of available swap -unless their ``noauto'' option is also set. -.El +will be removed, unless their ``noauto'' option is also set. +Note that +.Nm swapoff +will fail and refuse to remove a swap device if there is insufficient +VM (memory + remaining swap devices) to run the system. +.Nm Swapoff +must move swapped pages out of the device being removed which could +lead to high system loads for a period of time, depending on how +much data has been swapped out to that device. .Pp -The second form is used to configure or disable individual devices. +The +.Nm swapctl +utility exists primarily for those familiar with other BSDs and may be +used to add, remove, or list swap. Note that the +.Fl a +option is used diferently in +.Nm swapctl +and indicates that a specific list of devices should be added. +The +.Fl d +option indicates that a specific list should be removed. The +.Fl A +and +.Fl D +options to +.Nm swapctl +operate on all swap entries in +.Pa /etc/fstab +which do not have their ``noauto'' option set. +.Pp +Swap information can be generated using the +.Nm swapinfo +program, +.Nm pstat +.Fl s , +or +.Nm swapctl +.Fl lshk . +The +.Nm swapctl +utility has the following options for listing swap: +.Bl -tag -width indent +.It Fl l +List the devices making up system swap. +.It Fl s +Print a summary line for system swap. +.It Fl h +Output values in megabytes. +.It Fl k +Output values in kilobytes. +.Pp +The BLOCKSIZE environment variable is used if not specifically +overridden. 512 byte blocks are used by default. +.El .Sh SEE ALSO .Xr swapon 2 , .Xr fstab 5 , diff --git a/sbin/swapon/swapon.c b/sbin/swapon/swapon.c index 51042bc5bec7..d908b4afd091 100644 --- a/sbin/swapon/swapon.c +++ b/sbin/swapon/swapon.c @@ -45,6 +45,11 @@ static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ +#include +#include +#include +#include + #include #include #include @@ -52,59 +57,122 @@ static const char rcsid[] = #include #include #include +#include -static void usage(const char *); -static int is_swapoff(const char *); -int swap_on_off(char *name, int ignoreebusy, int do_swapoff); +static void usage(void); +static int swap_on_off(char *name, int ignoreebusy); +static void swaplist(int, int, int); + +enum { SWAPON, SWAPOFF, SWAPCTL } orig_prog, which_prog = SWAPCTL; int main(int argc, char **argv) { struct fstab *fsp; + char *ptr; int stat; int ch, doall; - int do_swapoff; - char *pname = argv[0]; - - do_swapoff = is_swapoff(pname); + int sflag = 0, lflag = 0, hflag = 0; + 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) - switch((char)ch) { + while ((ch = getopt(argc, argv, "AadlhksU")) != -1) { + switch(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 's': + sflag = 1; + break; + case 'l': + lflag = 1; + break; + case 'h': + hflag = 'M'; + break; + case 'k': + hflag = 'K'; + break; + case 'U': + if (which_prog == SWAPCTL) { + doall = 1; + which_prog = SWAPOFF; + } else { + usage(); + } break; case '?': default: - usage(pname); + 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 (swap_on_off(fsp->fs_spec, 1, do_swapoff)) - stat = 1; - else - printf("%s: %sing %s as swap device\n", - pname, do_swapoff ? "remov" : "add", - fsp->fs_spec); + 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, 0)) { + stat = 1; + } else { + printf("%s: %sing %s as swap device\n", + getprogname(), which_prog == SWAPOFF ? "remov" : "add", + fsp->fs_spec); + } + } } - else if (!*argv) - usage(pname); - for (; *argv; ++argv) - stat |= swap_on_off(*argv, 0, do_swapoff); + else if (!*argv) + usage(); + for (; *argv; ++argv) { + if (swap_on_off(*argv, 0)) { + stat = 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(stat); } -int -swap_on_off(char *name, int ignoreebusy, int do_swapoff) +static int +swap_on_off(char *name, int ignoreebusy) { - if ((do_swapoff ? swapoff(name) : swapon(name)) == -1) { + if ((which_prog == SWAPOFF ? swapoff(name) : swapon(name)) == -1) { switch (errno) { case EBUSY: if (!ignoreebusy) @@ -120,23 +188,90 @@ swap_on_off(char *name, int ignoreebusy, int do_swapoff) } static void -usage(const char *pname) +usage(void) { - fprintf(stderr, "usage: %s [-a] [special_file ...]\n", pname); + fprintf(stderr, "usage: %s ", getprogname()); + switch(orig_prog) { + case SWAPOFF: + fprintf(stderr, "[-a] [special_file ...]\n"); + break; + case SWAPON: + fprintf(stderr, "[-a] [special_file ...]\n"); + break; + case SWAPCTL: + fprintf(stderr, "[-lshAU] [-a/-d special_file ...]\n"); + break; + } exit(1); } -static int -is_swapoff(const char *s) +static void +swaplist(int lflag, int sflag, int hflag) { - const char *u; - - if ((u = strrchr(s, '/')) != NULL) - ++u; - else - u = s; - if (strcmp(u, "swapoff") == 0) - return 1; - else - return 0; + size_t mibsize, size; + struct xswdev xsw; + int mib[16], n, pagesize; + size_t hlen; + long blocksize; + long long total = 0; + long long used = 0; + long long tmp_total; + long long tmp_used; + + pagesize = getpagesize(); + switch(hflag) { + case 'K': + blocksize = 1024; + hlen = 10; + break; + case 'M': + blocksize = 1024 * 1024; + hlen = 10; + break; + default: + getbsize(&hlen, &blocksize); + break; + } + + mibsize = sizeof mib / sizeof mib[0]; + if (sysctlnametomib("vm.swap_info", mib, &mibsize) == -1) + err(1, "sysctlnametomib()"); + + if (lflag) { + char buf[32]; + snprintf(buf, sizeof(buf), "%ld-blocks", blocksize); + printf("%-13s %*s %*s\n", + "Device:", + hlen, buf, + hlen, "Used:"); + } + + for (n = 0; ; ++n) { + mib[mibsize] = n; + size = sizeof xsw; + if (sysctl(mib, mibsize + 1, &xsw, &size, NULL, NULL) == -1) + break; + if (xsw.xsw_version != XSWDEV_VERSION) + errx(1, "xswdev version mismatch"); + + tmp_total = (long long)xsw.xsw_nblks * pagesize / blocksize; + tmp_used = (long long)xsw.xsw_used * pagesize / blocksize; + total += tmp_total; + used += tmp_used; + if (lflag) { + printf("/dev/%-8s %*lld %*lld\n", + devname(xsw.xsw_dev, S_IFCHR), + hlen, tmp_total, + hlen, tmp_used); + } + } + if (errno != ENOENT) + err(1, "sysctl()"); + + if (sflag) { + printf("Total: %*lld %*lld\n", + hlen, total, + hlen, used); + } } +