File util-linux-2.14.1-mount_swap_pagesize.patch of Package util-linux

Index: util-linux-ng-2.14.1/mount/swapon.c
===================================================================
--- util-linux-ng-2.14.1.orig/mount/swapon.c	2008-09-10 11:02:43.000000000 +0200
+++ util-linux-ng-2.14.1/mount/swapon.c	2008-11-07 14:34:30.000000000 +0100
@@ -13,6 +13,8 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <fcntl.h>
+#include <stdint.h>
+#include <byteswap.h>
 #include "xmalloc.h"
 #include "swap_constants.h"
 #include "nls.h"
@@ -39,6 +41,33 @@
 #define QUIET	1
 #define CANONIC	1
 
+#define MAX_PAGESIZE	(64 * 1024)
+static unsigned int page_size[] = {  4 * 1024,
+				     8 * 1024,
+				    16 * 1024,
+				    64 * 1024,
+				    0 };
+
+
+struct swap_info {
+	char		bootbits[1024];	/* Space for disklabel etc. */
+	uint32_t	version;
+	uint32_t	last_page;
+	uint32_t	nr_badpages;
+	unsigned char	sws_uuid[16];
+	unsigned char	sws_volume[16];
+	uint32_t	padding[117];
+	uint32_t	badpages[1];
+};
+
+enum {
+	SWAP_V0 = 1,
+	SWAP_V1,
+	SWAP_SUSPEND,
+	SWAP_ULSUSPEND,
+	SWAP_OOTSUSPEND
+};
+
 int all = 0;
 int priority = -1;	/* non-prioritized swap by default */
 
@@ -238,11 +267,116 @@ swap_reinitialize(const char *device) {
 	return -1; /* error */
 }
 
+int
+swap_detect_signature(const char *buf)
+{
+	if (memcmp(buf, "SWAP-SPACE", 10) == 0)
+		return SWAP_V0;
+	else if (memcmp(buf, "SWAPSPACE2", 10) == 0)
+		return SWAP_V1;
+	else if	(memcmp(buf, "S1SUSPEND", 9) == 0)
+		return SWAP_SUSPEND;
+	else if	(memcmp(buf, "ULSUSPEND", 9) == 0)
+		return SWAP_ULSUSPEND;
+	else if (memcmp(buf, "\xed\xc3\x02\xe9\x98\x56\xe5\x0c", 8) == 0)
+		return SWAP_OOTSUSPEND;
+
+	return 0;
+}
+
+/* return the pagesize the swap format has been built with
+ * as swap metadata depends on the pagesize, we have to
+ * reinitialize if it does not match with the current pagesize
+ * returns 0 if not a valid swap format
+ */
+unsigned int
+swap_get_pagesize(const char *dev)
+{
+	int fd;
+	char *buf;
+	unsigned int *page, last_page = 0;
+	unsigned int pagesize = 0;
+	off_t size, swap_size;
+	int swap_version = 0;
+	int flip = 0;
+	struct swap_info *s;
+
+	fd = open(dev, O_RDONLY);
+	if (fd == -1) {
+		perror("open");
+		return 0;
+	}
+
+	/* get size */
+	size = lseek(fd, 0, SEEK_END);
+	if (size == (off_t)-1) {
+		perror("lseek");
+		goto err;
+	}
+	/* rewind */
+	if (lseek(fd, 0, SEEK_SET)) {
+		perror("lseek");
+		goto err;
+	}
+
+	buf = malloc(MAX_PAGESIZE);
+	if (!buf) {
+		perror("malloc");
+		goto err;
+	}
+
+	if (read(fd, buf, MAX_PAGESIZE) == (ssize_t)-1) {
+		perror("read");
+		goto err1;
+	}
+
+	for (page = page_size; *page; ++page) {
+		char *off = buf + *page - 10;
+		if (swap_detect_signature(off)) {
+			pagesize = *page;
+			break;
+		}
+	}
+	if (pagesize) {
+		s = (struct swap_info *)buf;
+		if (s->version == 1) {
+			swap_version = 1;
+			last_page = s->last_page;
+		} else if (bswap_32(s->version) == 1) {
+			flip = 1;
+			swap_version = 1;
+			last_page = bswap_32(s->last_page);
+		}
+		if (verbose)
+			fprintf(stderr, _("found %sswap v%d signature string"
+					" for %d KiB PAGE_SIZE\n"),
+				flip ? "other-endian " : "", swap_version,
+				pagesize / 1024);
+		swap_size = (last_page + 1) * pagesize;
+		if (swap_size > size) {
+			if (verbose)
+				fprintf(stderr, _("last_page 0x%08llx is larger"
+					" than actual size of swapspace\n"),
+					(unsigned long long)swap_size);
+			pagesize = 0;
+		}
+	}
+
+err1:
+	free(buf);
+err:
+	close(fd);
+	return pagesize;
+}
+
 static int
 do_swapon(const char *orig_special, int prio, int canonic) {
 	int status;
+	int reinitialize = 0;
 	struct stat st;
 	const char *special = orig_special;
+	unsigned int pagesize = sysconf(_SC_PAGESIZE);
+	unsigned int swap_pagesize = 0;
 
 	if (verbose)
 		printf(_("%s on %s\n"), progname, orig_special);
@@ -260,6 +394,15 @@ do_swapon(const char *orig_special, int
 		return -1;
 	}
 
+	swap_pagesize = swap_get_pagesize(special);
+	if (swap_pagesize && (pagesize != swap_pagesize)) {
+		if (verbose)
+			fprintf(stderr, _("swap format pagesize does not match."
+				" Reinitializing the swap.\n"),
+				progname, special);
+		reinitialize = 1;
+	}
+
 	/* We have to reinitialize swap with old (=useless) software suspend
 	 * data. The problem is that if we don't do it, then we get data
 	 * corruption the next time an attempt at unsuspending is made.
@@ -268,6 +411,10 @@ do_swapon(const char *orig_special, int
 		fprintf(stdout, _("%s: %s: software suspend data detected. "
 					"Reinitializing the swap.\n"),
 			progname, special);
+		reinitialize = 1;
+	}
+
+	if (reinitialize) {
 		if (swap_reinitialize(special) < 0)
 			return -1;
 	}
openSUSE Build Service is sponsored by