aboutsummaryrefslogtreecommitdiff
path: root/sys/geom/label/g_label_swaplinux.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/geom/label/g_label_swaplinux.c')
-rw-r--r--sys/geom/label/g_label_swaplinux.c91
1 files changed, 91 insertions, 0 deletions
diff --git a/sys/geom/label/g_label_swaplinux.c b/sys/geom/label/g_label_swaplinux.c
new file mode 100644
index 000000000000..5994ad93fd6f
--- /dev/null
+++ b/sys/geom/label/g_label_swaplinux.c
@@ -0,0 +1,91 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+
+#include <geom/geom.h>
+#include <geom/geom_dbg.h>
+#include <geom/label/g_label.h>
+
+/*
+ * Taken from
+ * https://github.com/util-linux/util-linux/blob/master/include/swapheader.h
+ */
+
+#define SWAP_VERSION 1
+#define SWAP_UUID_LENGTH 16
+#define SWAP_LABEL_LENGTH 16
+#define SWAP_SIGNATURE "SWAPSPACE2"
+#define SWAP_SIGNATURE_SZ (sizeof(SWAP_SIGNATURE) - 1)
+
+struct swap_header_v1_2 {
+ char bootbits[1024]; /* Space for disklabel etc. */
+ uint32_t version;
+ uint32_t last_page;
+ uint32_t nr_badpages;
+ unsigned char uuid[SWAP_UUID_LENGTH];
+ char volume_name[SWAP_LABEL_LENGTH];
+ uint32_t padding[117];
+ uint32_t badpages[1];
+};
+
+typedef union {
+ struct swap_header_v1_2 header;
+ struct {
+ uint8_t reserved[PAGE_SIZE - SWAP_SIGNATURE_SZ];
+ char signature[SWAP_SIGNATURE_SZ];
+ } tail;
+} swhdr_t;
+
+#define sw_version header.version
+#define sw_volume_name header.volume_name
+#define sw_signature tail.signature
+
+static void
+g_label_swaplinux_taste(struct g_consumer *cp, char *label, size_t size)
+{
+ struct g_provider *pp;
+ swhdr_t *hdr;
+
+ g_topology_assert_not();
+ pp = cp->provider;
+ label[0] = '\0';
+
+ KASSERT(pp->sectorsize != 0, ("Tasting a disk with 0 sectorsize"));
+ if ((PAGE_SIZE % pp->sectorsize) != 0)
+ return;
+
+ hdr = (swhdr_t *)g_read_data(cp, 0, PAGE_SIZE, NULL);
+ if (hdr == NULL)
+ return;
+
+ /* Check version and magic string */
+ if (hdr->sw_version == SWAP_VERSION &&
+ !memcmp(hdr->sw_signature, SWAP_SIGNATURE, SWAP_SIGNATURE_SZ))
+ G_LABEL_DEBUG(1, "linux swap detected on %s.", pp->name);
+ else
+ goto exit_free;
+
+ /* Check for volume label */
+ if (hdr->sw_volume_name[0] == '\0')
+ goto exit_free;
+
+ /* Terminate label */
+ hdr->sw_volume_name[sizeof(hdr->sw_volume_name) - 1] = '\0';
+ strlcpy(label, hdr->sw_volume_name, size);
+
+exit_free:
+ g_free(hdr);
+}
+
+struct g_label_desc g_label_swaplinux = {
+ .ld_taste = g_label_swaplinux_taste,
+ .ld_dirprefix = "swaplinux/",
+ .ld_enabled = 1
+};
+
+G_LABEL_INIT(swaplinux, g_label_swaplinux, "Create device nodes for Linux swap");