Subject: Additional swap/dump magic
To: None <tech-userlevel@NetBSD.org>
From: Martin Husemann <martin@duskware.de>
List: tech-userlevel
Date: 08/24/2006 00:10:08
--bg08WKrSYDhXBjb5
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Folks,

I would like your input on the attached changes. This is not fixing something
we did miss for years, but I think the addition of this "magic" is very
convenient for the user (albeit mostly invisible) and on the other hand
pretty cheap.

What I did is:

 o A few swapctl(8) enhancements
   - add an option (-q for query) to check if any swap or dump specs
     are used in /etc/fstab
   - add a new "auto" type to the -t argument that makes -A or -U not
     parse /etc/fstab for explicitly configured swap/dump block
     devices, but autodected all available (loacl) swap partitions

 o A simple change to /etc/rc.d/swap1 using above enhancements so that
   - if any explicit swap or dump is configured in /etc/fstab everything
     behaves exactly as it does now (i.e. keep status quo)
   - if no swap or dump is configured in /etc/fstab, use the new autodetect
     magic to activate all swap partitions and set a dump device

If this change goes into tree, I'll change sysinst to not explicitly configure
a swap partition next (together with wedges support for archs that are there
already).

What do you think?

Martin

--bg08WKrSYDhXBjb5
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=patch

Index: etc/rc.d/swap1
===================================================================
RCS file: /cvsroot/src/etc/rc.d/swap1,v
retrieving revision 1.9
diff -u -r1.9 swap1
--- etc/rc.d/swap1	13 Aug 2004 18:08:03 -0000	1.9
+++ etc/rc.d/swap1	23 Aug 2006 16:28:17 -0000
@@ -19,7 +19,7 @@
 swap1_start()
 {
 	if ! checkyesno no_swap; then
-		swapctl -A -t blk
+		swapctl -A -t $t_arg
 	fi
 }
 
@@ -29,9 +29,13 @@
 {
 	if checkyesno swapoff || [ -n "$rc_force" ]; then
 		echo "Removing block-type swap devices"
-		swapctl -U -t blk
+		swapctl -U -t $t_arg
 	fi
 }
 
+# if any swap or dump configuration is found in /etc/fstab, just
+# use "blk" here - otherwise do full magic "auto"
+if swapctl -q >/dev/null; then t_arg="blk"; else t_arg="auto"; fi
+
 load_rc_config swap
 run_rc_command "$1"
Index: sbin/swapctl/Makefile
===================================================================
RCS file: /cvsroot/src/sbin/swapctl/Makefile,v
retrieving revision 1.4
diff -u -r1.4 Makefile
--- sbin/swapctl/Makefile	27 Jun 2005 01:00:07 -0000	1.4
+++ sbin/swapctl/Makefile	23 Aug 2006 16:28:17 -0000
@@ -3,6 +3,8 @@
 PROG=	swapctl
 SRCS=	swapctl.c swaplist.c
 MAN=	swapctl.8
+LDADD+=	-lutil
+DPADD+=	${LIBUTIL}
 
 LINKS=	${BINDIR}/swapctl ${BINDIR}/swapon
 MLINKS=	swapctl.8 swapon.8
Index: sbin/swapctl/swapctl.8
===================================================================
RCS file: /cvsroot/src/sbin/swapctl/swapctl.8,v
retrieving revision 1.33
diff -u -r1.33 swapctl.8
--- sbin/swapctl/swapctl.8	22 Aug 2006 21:38:39 -0000	1.33
+++ sbin/swapctl/swapctl.8	23 Aug 2006 16:28:17 -0000
@@ -26,7 +26,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd August 22, 2006
+.Dd August 23, 2006
 .Dt SWAPCTL 8
 .Os
 .Sh NAME
@@ -37,12 +37,12 @@
 .Nm
 .Fl A
 .Op Fl p Ar priority
-.Op Fl t Ar blk|noblk
+.Op Fl t Ar blk|noblk|auto
 .Nm
 .Fl D Ar dumpdev|none
 .Nm
 .Fl U
-.Op Fl t Ar blk|noblk
+.Op Fl t Ar blk|noblk|auto
 .Nm
 .Fl a
 .Op Fl p Ar priority
@@ -59,10 +59,12 @@
 .Op Fl k | Fl m | Fl g
 .Op Fl h
 .Nm
+.Fl q
+.Nm
 .Fl z
 .Nm swapon
 .Fl a
-.Op Fl t Ar blk|noblk
+.Op Fl t Ar blk|noblk|auto
 .Nm swapon
 .Ar path
 .Sh DESCRIPTION
@@ -106,6 +108,11 @@
 If no swap devices are configured,
 .Nm
 will exit with an error code.
+If usesd together with
+.Fl t Ar auto
+this option will not read
+.Pa /etc/fstab
+but query the kernel for all swap partitions on local hard disks.
 .It Fl D
 The
 .Fl D
@@ -137,6 +144,11 @@
 If no swap devices are unconfigured,
 .Nm
 will exit with an error code.
+If used together with
+.Fl t Ar auto
+this option will not read
+.Pa /etc/fstab
+but unconfigure all swap partitions.
 .It Fl a
 The
 .Fl a
@@ -186,6 +198,14 @@
 and
 .Fl l
 options.
+.It Fl q
+query
+.Pa /etc/fstab ,
+checking for any defined swap or dump devices.
+If any are found,
+.Nm
+returns with an exit status of 0, if none are found the exit status will
+be 1.
 .It Fl k
 The
 .Fl k
@@ -223,6 +243,9 @@
 causes all non-block devices in
 .Pa /etc/fstab
 to be added.
+An argument of
+.Ar auto
+causes all swap partitions on local hard disks to be used.
 This option is useful in early system startup, where swapping
 may be needed before all file systems are available, such as during
 disk checks of large file systems.
Index: sbin/swapctl/swapctl.c
===================================================================
RCS file: /cvsroot/src/sbin/swapctl/swapctl.c,v
retrieving revision 1.30
diff -u -r1.30 swapctl.c
--- sbin/swapctl/swapctl.c	22 Aug 2006 14:08:36 -0000	1.30
+++ sbin/swapctl/swapctl.c	23 Aug 2006 16:28:17 -0000
@@ -35,8 +35,11 @@
  *	-D [<dev>|none]	set dumpdev to <dev> or disable dumps
  *	-z		show dumpdev
  *	-U		remove all devices listed as `sw' in /etc/fstab.
- *	-t [blk|noblk]	if -A or -U , add (remove) either all block device
- *			or all non-block devices
+ *	-t [blk|noblk|auto]
+ *			if -A or -U , add (remove) either all block device
+ *			or all non-block devices, or all swap partitions
+ *	-q		check if any swap or dump devices are defined in
+ *			/etc/fstab
  *	-a <dev>	add this device
  *	-d <dev>	remove this swap device
  *	-g		use gigabytes
@@ -65,6 +68,9 @@
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <sys/swap.h>
+#include <sys/sysctl.h>
+#include <sys/disk.h>
+#include <sys/disklabel.h>
 
 #include <unistd.h>
 #include <err.h>
@@ -73,6 +79,9 @@
 #include <stdlib.h>
 #include <string.h>
 #include <fstab.h>
+#include <fcntl.h>
+#include <util.h>
+#include <paths.h>
 
 #include "swapctl.h"
 
@@ -90,6 +99,7 @@
 #define	CMD_l		0x40	/* list swap files/devices */
 #define	CMD_s		0x80	/* summary of swap files/devices */
 #define	CMD_z		0x100	/* show dump device */
+#define CMD_q		0x200	/* check for dump/swap in /etc/fstab */
 
 #define	SET_COMMAND(cmd) \
 do { \
@@ -103,7 +113,7 @@
  * line, and the ones which require that none exist.
  */
 #define	REQUIRE_PATH	(CMD_D | CMD_a | CMD_c | CMD_d)
-#define	REQUIRE_NOPATH	(CMD_A | CMD_U | CMD_l | CMD_s | CMD_z)
+#define	REQUIRE_NOPATH	(CMD_A | CMD_U | CMD_l | CMD_s | CMD_z | CMD_q)
 
 /*
  * Option flags, and the commands with which they are valid.
@@ -119,7 +129,9 @@
 int	pflag;		/* priority was specified */
 #define	PFLAG_CMDS	(CMD_A | CMD_a | CMD_c)
 
-char	*tflag;		/* swap device type (blk or noblk) */
+char	*tflag;		/* swap device type (blk, noblk, auto) */
+int	autoflag;	/* 1, if tflag is "auto" */
+int	auto_add_dump;	/* 1, if the next found swap will become dump */
 #define	TFLAG_CMDS	(CMD_A | CMD_U)
 
 int	pri;		/* uses 0 as default pri */
@@ -130,6 +142,11 @@
 static	void set_dumpdev(char *);
 static	int get_dumpdev(void);
 static	void do_fstab(int);
+static	int check_fstab(void);
+static	void do_localdevs(int);
+static	void do_localdisk(const char *, int);
+static	int do_wedgesofdisk(int fd, int);
+static	int do_partitionsofdisk(const char *, int fd, int);
 static	void usage(void);
 static	void swapon_command(int, char **);
 #if 0
@@ -153,7 +170,7 @@
 	}
 #endif
 
-	while ((c = getopt(argc, argv, "ADUacdghklmp:st:z")) != -1) {
+	while ((c = getopt(argc, argv, "ADUacdghklmp:qst:z")) != -1) {
 		switch (c) {
 		case 'A':
 			SET_COMMAND(CMD_A);
@@ -205,6 +222,10 @@
 			pri = atoi(optarg);
 			break;
 
+		case 'q':
+			SET_COMMAND(CMD_q);
+			break;
+
 		case 's':
 			SET_COMMAND(CMD_s);
 			break;
@@ -213,6 +234,8 @@
 			if (tflag != NULL)
 				usage();
 			tflag = optarg;
+			if (strcmp(tflag, "auto") == 0)
+				autoflag = 1;
 			break;
 
 		case 'z':
@@ -256,7 +279,8 @@
 		if (command != CMD_A && command != CMD_U)
 			usage();
 		if (strcmp(tflag, "blk") != 0 &&
-		    strcmp(tflag, "noblk") != 0)
+		    strcmp(tflag, "noblk") != 0 &&
+		    strcmp(tflag, "auto") != 0)
 			usage();
 	}
 
@@ -286,7 +310,10 @@
 		break;
 
 	case CMD_A:
-		do_fstab(1);
+		if (autoflag)
+			do_localdevs(1);
+		else
+			do_fstab(1);
 		break;
 
 	case CMD_D:
@@ -299,8 +326,21 @@
 		break;
 
 	case CMD_U:
-		do_fstab(0);
+		if (autoflag)
+			do_localdevs(0);
+		else
+			do_fstab(0);
 		break;
+	case CMD_q:
+		if (check_fstab()) {
+			printf("%s: there are swap or dump devices defined in "
+			    _PATH_FSTAB "\n", getprogname());
+			exit(0);
+		} else {
+			printf("%s: no swap or dump devices in "
+			    _PATH_FSTAB "\n", getprogname());
+			exit(1);
+		}
 	}
 
 	exit(0);
@@ -390,6 +430,9 @@
 	if (swapctl(SWAP_ON, path, priority) < 0) {
 oops:
 		err(1, "%s", path);
+	} else if (auto_add_dump) {
+		set_dumpdev(path);
+		auto_add_dump = 0;
 	}
 	return (1);
 }
@@ -446,6 +489,154 @@
 }
 
 static void
+do_localdevs(int add)
+{
+	size_t ressize;
+	char *disknames, *disk;
+	dev_t	dev;
+	static const char mibname[] = "hw.disknames";
+
+	/*
+	 * Check if we want to add a dump device too
+	 */
+	if (swapctl(SWAP_GETDUMPDEV, &dev, 0) == 0 && dev == NODEV)
+		auto_add_dump = 1;	/* no dump device available */
+
+	ressize = 0;
+	if (sysctlbyname(mibname, NULL, &ressize, NULL, 0))
+		return;
+	ressize += 200;	/* add some arbitrary slope */
+	disknames = malloc(ressize);
+	if (sysctlbyname(mibname, disknames, &ressize, NULL, 0) == 0) {
+		for (disk = strtok(disknames, " "); disk;
+		    disk = strtok(NULL, " "))
+			do_localdisk(disk, add);
+	}
+	free(disknames);
+}
+
+static void
+do_localdisk(const char *disk, int add)
+{
+	int fd;
+	char dvname[MAXPATHLEN];
+
+	if ((fd = opendisk(disk, O_RDONLY, dvname, sizeof(dvname), 0)) == -1)
+		return;
+
+	if (!do_wedgesofdisk(fd, add))
+		do_partitionsofdisk(disk, fd, add);
+
+	close(fd);
+}
+
+static int
+do_wedgesofdisk(int fd, int add)
+{
+	char devicename[MAXPATHLEN];
+	struct dkwedge_info *dkw;
+	struct dkwedge_list dkwl;
+	size_t bufsize;
+	u_int i;
+
+	dkw = NULL;
+	dkwl.dkwl_buf = dkw;
+	dkwl.dkwl_bufsize = 0;
+
+	for (;;) {
+		if (ioctl(fd, DIOCLWEDGES, &dkwl) == -1)
+			return 0;
+		if (dkwl.dkwl_nwedges == dkwl.dkwl_ncopied)
+			break;
+		bufsize = dkwl.dkwl_nwedges * sizeof(*dkw);
+		if (dkwl.dkwl_bufsize < bufsize) {
+			dkw = realloc(dkwl.dkwl_buf, bufsize);
+			if (dkw == NULL)
+				return 0;
+			dkwl.dkwl_buf = dkw;
+			dkwl.dkwl_bufsize = bufsize;
+		}
+	}
+
+	for (i = 0; i < dkwl.dkwl_ncopied; i++) {
+		if (strcmp(dkw[i].dkw_ptype, DKW_PTYPE_SWAP) != 0)
+			continue;
+		snprintf(devicename, sizeof(devicename), "%s%s", _PATH_DEV,
+		    dkw[i].dkw_devname);
+		devicename[sizeof(devicename)-1] = '\0';
+
+		if (add) {
+			if (add_swap(devicename, 0)) {
+				printf(
+			    	"%s: adding %s as swap device at priority 0\n",
+				    getprogname(), devicename);
+			}
+		} else {
+			if (delete_swap(devicename)) {
+				printf(
+				    "%s: removing %s as swap device\n",
+				    getprogname(), devicename);
+			}
+		}
+
+	}
+
+	free(dkw);
+	return dkwl.dkwl_nwedges != 0;
+}
+
+static int
+do_partitionsofdisk(const char *prefix, int fd, int add)
+{
+	char devicename[MAXPATHLEN];
+	struct disklabel lab;
+	uint i;
+
+	if (ioctl(fd, DIOCGDINFO, &lab) != 0)
+		return 0;
+
+	for (i = 0; i < lab.d_npartitions; i++) {
+		if (lab.d_partitions[i].p_fstype != FS_SWAP)
+			continue;
+		snprintf(devicename, sizeof(devicename), "%s%s%c", _PATH_DEV,
+		    prefix, 'a'+i);
+		devicename[sizeof(devicename)-1] = '\0';
+
+		if (add) {
+			if (add_swap(devicename, 0)) {
+				printf(
+			    	"%s: adding %s as swap device at priority 0\n",
+				    getprogname(), devicename);
+			}
+		} else {
+			if (delete_swap(devicename)) {
+				printf(
+				    "%s: removing %s as swap device\n",
+				    getprogname(), devicename);
+			}
+		}
+	}
+
+	return 1;
+}
+
+static int
+check_fstab(void)
+{
+	struct	fstab *fp;
+
+	while ((fp = getfsent()) != NULL) {
+		if (strcmp(fp->fs_type, "dp") == 0)
+			return 1;
+
+		if (strcmp(fp->fs_type, "sw") == 0)
+			return 1;
+	}
+
+	return 0;
+}
+
+static void
 do_fstab(int add)
 {
 	struct	fstab *fp;
@@ -585,11 +776,12 @@
 {
 	const char *progname = getprogname();
 
-	fprintf(stderr, "usage: %s -A [-p priority] [-t blk|noblk]\n",
+	fprintf(stderr, "usage: %s -A [-p priority] [-t blk|noblk|auto]\n",
 	    progname);
 	fprintf(stderr, "       %s -D dumppath\n", progname);
-	fprintf(stderr, "       %s -U [-t blk|noblk]\n", progname);
+	fprintf(stderr, "       %s -U [-t blk|noblk|auto]\n", progname);
 	fprintf(stderr, "       %s -a [-p priority] path\n", progname);
+	fprintf(stderr, "       %s -q\n", progname);
 	fprintf(stderr, "       %s -c -p priority path\n", progname);
 	fprintf(stderr, "       %s -d path\n", progname);
 	fprintf(stderr, "       %s -l | -s [-k|-m|-g|-h]\n", progname);

--bg08WKrSYDhXBjb5--