Hi Adrian,

if you have a swap partition that's been used for swsuspend and you boot
into a different kernel, we should have the swapon re-initialize the
swap to avoid later resuming and causing data corruption. (quote from RH
bugzilla)


Note: there will be support for swsuspend swap detection in the next
release of libblkid (from Theo's e2fsprogs).


        Karel



Signed-off-by: Karel Zak <[EMAIL PROTECTED]>
----

--- util-linux-2.13-pre2/mount/swapon.c.swsuspend       2005-08-14 
17:17:49.000000000 +0200
+++ util-linux-2.13-pre2/mount/swapon.c 2005-09-08 14:34:51.000000000 +0200
@@ -11,6 +11,9 @@
 #include <mntent.h>
 #include <errno.h>
 #include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <fcntl.h>
 #include "xmalloc.h"
 #include "swap_constants.h"
 #include "swapargs.h"
@@ -22,6 +25,7 @@
 
 #define        _PATH_FSTAB     "/etc/fstab"
 #define PROC_SWAPS      "/proc/swaps"
+#define PATH_MKSWAP    "/sbin/mkswap"
 
 #define SWAPON_NEEDS_TWO_ARGS
 
@@ -163,6 +167,84 @@
        return 0 ;
 }
 
+/*
+ * It's better do swsuspend detection by follow routine than
+ * include huge mount_guess_fstype.o to swapon. We need only
+ * swsuspend and no the others filesystems.
+ */
+#ifdef HAVE_LIBBLKID
+static int
+swap_is_swsuspend(const char *device) {
+       const char *type = blkid_get_tag_value(blkid, "TYPE", device);
+       
+       if (type && strcmp(type, "swsuspend")==0)
+               return 0;
+       return 1;
+}
+#else
+static int
+swap_is_swsuspend(const char *device) {
+       int fd, re = 1, n = getpagesize() - 10;
+       char buf[10];
+       
+       fd = open(device, O_RDONLY);
+       if (fd < 0)
+               return -1;
+
+       if (lseek(fd, n, SEEK_SET) >= 0 &&
+           read(fd, buf, sizeof buf) == sizeof buf &&
+           (memcmp("S1SUSPEND", buf, 9)==0 ||
+                       memcmp("S2SUSPEND", buf, 9)==0))
+               re = 0;
+
+       close(fd);
+       return re;
+}
+#endif
+
+/* calls mkswap */
+static int
+swap_reinitialize(const char *device) {
+       const char *label = mount_get_volume_label_by_spec(device);
+       pid_t pid;
+       
+       switch((pid=fork())) {
+               case -1: /* fork error */
+                       fprintf(stderr, _("%s: cannot fork: %s\n"),
+                               progname, strerror(errno));
+                       return -1;
+                       
+               case 0: /* child */
+                       if (label && *label)
+                               execl(PATH_MKSWAP, PATH_MKSWAP, "-L", label, 
device, NULL);
+                       else
+                               execl(PATH_MKSWAP, PATH_MKSWAP, device, NULL);
+                       exit(1); /* error  */
+                       
+               default: /* parent */
+               {
+                       int status;
+                       int ret;
+
+                       do {
+                               if ((ret = waitpid(pid, &status, 0)) < 0 
+                                               && errno == EINTR)
+                                       continue;
+                               else if (ret < 0) {
+                                       fprintf(stderr, _("%s: waitpid: %s\n"),
+                                               progname, strerror(errno));
+                                       return -1;
+                               }
+                       } while (0);
+
+                       /* mkswap returns: 0=suss, 1=error */
+                       if (WIFEXITED(status) && WEXITSTATUS(status)==0)
+                               return 0; /* ok */
+               }
+       }
+       return -1; /* error */
+}
+       
 static int
 do_swapon(const char *orig_special, int prio) {
        int status;
@@ -186,6 +268,18 @@
                return -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 with suspended on.
+        */
+       if (swap_is_swsuspend(special)==0) {
+               fprintf(stdout, _("%s: %s: software suspend data detected. "
+                                       "Reinitializing the swap.\n"), 
+                       progname, special);
+               if (swap_reinitialize(special) < 0)
+                       return -1;
+       }
+       
        /* people generally dislike this warning - now it is printed
           only when `verbose' is set */
        if (verbose) {
--- util-linux-2.13-pre2/mount/get_label_uuid.c.swsuspend       2005-07-31 
23:58:38.000000000 +0200
+++ util-linux-2.13-pre2/mount/get_label_uuid.c 2005-09-08 14:34:51.000000000 
+0200
@@ -93,7 +93,24 @@
        }
        return 0;
 }
-           
+
+static int
+is_swsuspend_partition(int fd, char **label, char *uuid) {
+       int n = getpagesize();
+       char *buf = xmalloc(n);
+       struct swap_header_v1_2 *p = (struct swap_header_v1_2 *) buf;
+
+       if (lseek(fd, 0, SEEK_SET) == 0
+           && read(fd, buf, n) == n
+           && (strncmp(buf+n-10, "S1SUSPEND", 9)==0 || 
+                   strncmp(buf+n-10, "S2SUSPEND", 9)==0)
+           && p->version == 1) {
+               store_uuid(uuid, p->uuid);
+               store_label(label, p->volume_name, 16);
+               return 1;
+       }
+       return 0;
+}
 
 /*
  * Get both label and uuid.
@@ -126,6 +143,8 @@
 
        if (is_v1_swap_partition(fd, label, uuid))
                goto done;
+       if (is_swsuspend_partition(fd, label, uuid))
+               goto done;
 
        if (lseek(fd, 1024, SEEK_SET) == 1024
            && read(fd, (char *) &e2sb, sizeof(e2sb)) == sizeof(e2sb)




-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to