Index: sbin/swapon/swapon.8 =================================================================== --- sbin/swapon/swapon.8 +++ sbin/swapon/swapon.8 @@ -28,7 +28,7 @@ .\" @(#)swapon.8 8.1 (Berkeley) 6/5/93 .\" $FreeBSD$ .\" -.Dd October 21, 2016 +.Dd June 21, 2019 .Dt SWAPON 8 .Os .Sh NAME @@ -38,7 +38,7 @@ .Nm swapon .Oo Fl F Ar fstab .Oc -.Fl aLq | Ar +.Fl aLq | E Ar .Nm swapoff .Oo Fl F Ar fstab .Oc @@ -86,6 +86,11 @@ option is used, informational messages will not be 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 The .Nm swapoff Index: sbin/swapon/swapon.c =================================================================== --- sbin/swapon/swapon.c +++ sbin/swapon/swapon.c @@ -43,6 +43,7 @@ #include __FBSDID("$FreeBSD$"); +#include #include #include #include @@ -77,7 +78,7 @@ static enum { SWAPON, SWAPOFF, SWAPCTL } orig_prog, which_prog = SWAPCTL; -static int qflag; +static int Eflag, qflag; int main(int argc, char **argv) @@ -100,7 +101,7 @@ doall = 0; etc_fstab = NULL; - while ((ch = getopt(argc, argv, "AadghklLmqsUF:")) != -1) { + while ((ch = getopt(argc, argv, "AadEghklLmqsUF:")) != -1) { switch(ch) { case 'A': if (which_prog == SWAPCTL) { @@ -121,6 +122,12 @@ else usage(); break; + case 'E': + if (which_prog == SWAPON) + Eflag = 2; + else + usage(); + break; case 'g': hflag = 'G'; break; @@ -182,8 +189,10 @@ strstr(fsp->fs_mntops, "late") == NULL && late != 0) continue; + Eflag |= (strstr(fsp->fs_mntops, "trimonce") != NULL); swfile = swap_on_off(fsp->fs_spec, 1, fsp->fs_mntops); + Eflag &= ~1; if (swfile == NULL) { ret = 1; continue; @@ -378,12 +387,22 @@ return (NULL); } } else if (strcmp(token, "notrim") == 0) { + if (Eflag) { + warn("Options \"notrim\" and " + "\"trimonce\" conflict"); + free(ops); + return (NULL); + } Tflag = " -T "; } else if (strcmp(token, "late") == 0) { /* ignore known option */ } else if (strcmp(token, "noauto") == 0) { /* 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); free(ops); return (NULL); @@ -721,14 +740,42 @@ 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 * swap_on_off_sfile(const char *name, int doingall) { int error; - if (which_prog == SWAPON) + if (which_prog == SWAPON) { + if (Eflag) + swap_trim(name); error = swapon(name); - else /* SWAPOFF */ + } else /* SWAPOFF */ error = swapoff(name); if (error == -1) { @@ -759,6 +806,8 @@ fprintf(stderr, "usage: %s ", getprogname()); switch(orig_prog) { case SWAPON: + fprintf(stderr, "[-F fstab] -aLq | [-E] file ...\n"); + break; case SWAPOFF: fprintf(stderr, "[-F fstab] -aLq | file ...\n"); break; Index: share/man/man5/fstab.5 =================================================================== --- share/man/man5/fstab.5 +++ share/man/man5/fstab.5 @@ -216,6 +216,12 @@ space by the .Xr swapon 8 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, .Dq file is supported in the