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 <eirikn@bluezone.no>
Augmented by:	dillon (extensively)
Reviewed by:	David Schultz <dschultz@uclink.Berkeley.EDU>
This commit is contained in:
Matthew Dillon 2002-12-28 23:39:47 +00:00
parent 63100290f3
commit a420c8119a
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=108375
3 changed files with 261 additions and 69 deletions

View File

@ -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 <bsd.prog.mk>

View File

@ -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 ,

View File

@ -45,6 +45,11 @@ static const char rcsid[] =
"$FreeBSD$";
#endif /* not lint */
#include <sys/stat.h>
#include <sys/param.h>
#include <sys/user.h>
#include <sys/sysctl.h>
#include <err.h>
#include <errno.h>
#include <fstab.h>
@ -52,59 +57,122 @@ static const char rcsid[] =
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
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);
}
}