Modify swapon(8) to invoke BIO_DELETE to trim swap devices, either if

'-E' appears on the swapon command line, or if "trimonce" appears as
an fstab option.

Discussed at: BSDCAN
Tested by: markj
Reviewed by: markj
Approved by: markj (mentor)
Differential Revision:https://reviews.freebsd.org/D20599
This commit is contained in:
dougm 2019-06-22 03:16:01 +00:00
parent e18b1f330a
commit e1145d7ea4
3 changed files with 67 additions and 7 deletions

View File

@ -28,7 +28,7 @@
.\" @(#)swapon.8 8.1 (Berkeley) 6/5/93 .\" @(#)swapon.8 8.1 (Berkeley) 6/5/93
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.Dd October 21, 2016 .Dd June 21, 2019
.Dt SWAPON 8 .Dt SWAPON 8
.Os .Os
.Sh NAME .Sh NAME
@ -38,7 +38,7 @@
.Nm swapon .Nm swapon
.Oo Fl F Ar fstab .Oo Fl F Ar fstab
.Oc .Oc
.Fl aLq | Ar .Fl aLq | E Ar
.Nm swapoff .Nm swapoff
.Oo Fl F Ar fstab .Oo Fl F Ar fstab
.Oc .Oc
@ -86,6 +86,11 @@ If the
option is used, option is used,
informational messages will not be informational messages will not be
written to standard output when a swap device is added. written to standard output when a swap device is added.
The
.Fl E
option causes each of following devices to receive a
.Dv BIO_DELETE
command to mark all blocks as unused.
.Pp .Pp
The The
.Nm swapoff .Nm swapoff

View File

@ -43,6 +43,7 @@ static char sccsid[] = "@(#)swapon.c 8.1 (Berkeley) 6/5/93";
#include <sys/cdefs.h> #include <sys/cdefs.h>
__FBSDID("$FreeBSD$"); __FBSDID("$FreeBSD$");
#include <sys/disk.h>
#include <sys/param.h> #include <sys/param.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/mdioctl.h> #include <sys/mdioctl.h>
@ -77,7 +78,7 @@ static int run_cmd(int *, const char *, ...) __printflike(2, 3);
static enum { SWAPON, SWAPOFF, SWAPCTL } orig_prog, which_prog = SWAPCTL; static enum { SWAPON, SWAPOFF, SWAPCTL } orig_prog, which_prog = SWAPCTL;
static int qflag; static int Eflag, qflag;
int int
main(int argc, char **argv) main(int argc, char **argv)
@ -100,7 +101,7 @@ main(int argc, char **argv)
doall = 0; doall = 0;
etc_fstab = NULL; etc_fstab = NULL;
while ((ch = getopt(argc, argv, "AadghklLmqsUF:")) != -1) { while ((ch = getopt(argc, argv, "AadEghklLmqsUF:")) != -1) {
switch(ch) { switch(ch) {
case 'A': case 'A':
if (which_prog == SWAPCTL) { if (which_prog == SWAPCTL) {
@ -121,6 +122,12 @@ main(int argc, char **argv)
else else
usage(); usage();
break; break;
case 'E':
if (which_prog == SWAPON)
Eflag = 2;
else
usage();
break;
case 'g': case 'g':
hflag = 'G'; hflag = 'G';
break; break;
@ -182,8 +189,10 @@ main(int argc, char **argv)
strstr(fsp->fs_mntops, "late") == NULL && strstr(fsp->fs_mntops, "late") == NULL &&
late != 0) late != 0)
continue; continue;
Eflag |= (strstr(fsp->fs_mntops, "trimonce") != NULL);
swfile = swap_on_off(fsp->fs_spec, 1, swfile = swap_on_off(fsp->fs_spec, 1,
fsp->fs_mntops); fsp->fs_mntops);
Eflag &= ~1;
if (swfile == NULL) { if (swfile == NULL) {
ret = 1; ret = 1;
continue; continue;
@ -378,12 +387,22 @@ swap_on_geli_args(const char *mntops)
return (NULL); return (NULL);
} }
} else if (strcmp(token, "notrim") == 0) { } else if (strcmp(token, "notrim") == 0) {
if (Eflag) {
warn("Options \"notrim\" and "
"\"trimonce\" conflict");
free(ops);
return (NULL);
}
Tflag = " -T "; Tflag = " -T ";
} else if (strcmp(token, "late") == 0) { } else if (strcmp(token, "late") == 0) {
/* ignore known option */ /* ignore known option */
} else if (strcmp(token, "noauto") == 0) { } else if (strcmp(token, "noauto") == 0) {
/* ignore known option */ /* ignore known option */
} else if (strcmp(token, "sw") != 0) { } else if (strcmp(token, "sw") == 0) {
/* ignore known option */
} else if (strcmp(token, "trimonce") == 0) {
/* ignore known option */
} else {
warnx("Invalid option: %s", token); warnx("Invalid option: %s", token);
free(ops); free(ops);
return (NULL); return (NULL);
@ -721,14 +740,42 @@ run_cmd(int *ofd, const char *cmdline, ...)
return (WEXITSTATUS(status)); return (WEXITSTATUS(status));
} }
static void
swap_trim(const char *name)
{
struct stat sb;
off_t ioarg[2], sz;
int fd;
fd = open(name, O_WRONLY);
if (fd < 0)
errx(1, "Cannot open %s", name);
if (fstat(fd, &sb) < 0)
errx(1, "Cannot stat %s", name);
if (S_ISREG(sb.st_mode))
sz = sb.st_size;
else if (S_ISCHR(sb.st_mode) || S_ISBLK(sb.st_mode)) {
if (ioctl(fd, DIOCGMEDIASIZE, &sz) != 0)
err(1, "ioctl(DIOCGMEDIASIZE)");
} else
errx(1, "%s has an invalid file type", name);
ioarg[0] = 0;
ioarg[1] = sz;
if (ioctl(fd, DIOCGDELETE, ioarg) != 0)
warn("ioctl(DIOCGDELETE)");
close(fd);
}
static const char * static const char *
swap_on_off_sfile(const char *name, int doingall) swap_on_off_sfile(const char *name, int doingall)
{ {
int error; int error;
if (which_prog == SWAPON) if (which_prog == SWAPON) {
if (Eflag)
swap_trim(name);
error = swapon(name); error = swapon(name);
else /* SWAPOFF */ } else /* SWAPOFF */
error = swapoff(name); error = swapoff(name);
if (error == -1) { if (error == -1) {
@ -759,6 +806,8 @@ usage(void)
fprintf(stderr, "usage: %s ", getprogname()); fprintf(stderr, "usage: %s ", getprogname());
switch(orig_prog) { switch(orig_prog) {
case SWAPON: case SWAPON:
fprintf(stderr, "[-F fstab] -aLq | [-E] file ...\n");
break;
case SWAPOFF: case SWAPOFF:
fprintf(stderr, "[-F fstab] -aLq | file ...\n"); fprintf(stderr, "[-F fstab] -aLq | file ...\n");
break; break;

View File

@ -216,6 +216,12 @@ then the special file is made available as a piece of swap
space by the space by the
.Xr swapon 8 .Xr swapon 8
command at the end of the system reboot procedure. command at the end of the system reboot procedure.
For swap devices, the keyword
.Dq trimonce
triggers the delivery of a
.Dv BIO_DELETE
command to the device to mark
all blocks as unused.
For vnode-backed swap spaces, For vnode-backed swap spaces,
.Dq file .Dq file
is supported in the is supported in the