forked from pool/util-linux
190 lines
4.5 KiB
Diff
190 lines
4.5 KiB
Diff
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-10-24 14:19:06.000000000 +0200
|
|
@@ -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,114 @@ 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;
|
|
+ unsigned int pagesize = 0;
|
|
+ off_t size, swap_size;
|
|
+ int swap_version;
|
|
+ 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)
|
|
+ last_page = s->last_page;
|
|
+ else if (bswap_32(s->version) == 1) {
|
|
+ flip = 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 - 1,
|
|
+ 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 +392,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 +409,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;
|
|
}
|