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:
parent
f0efa00b3b
commit
954749368b
@ -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>
|
||||
|
@ -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 ,
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user