xref: /freebsd-src/sys/geom/label/g_label_swaplinux.c (revision 78444b5ade65568d817ecc3cfa5d66e05edf2b14)
1*78444b5aSRicardo Branco /*-
2*78444b5aSRicardo Branco  * SPDX-License-Identifier: BSD-2-Clause
3*78444b5aSRicardo Branco  */
4*78444b5aSRicardo Branco 
5*78444b5aSRicardo Branco #include <sys/param.h>
6*78444b5aSRicardo Branco #include <sys/systm.h>
7*78444b5aSRicardo Branco #include <sys/kernel.h>
8*78444b5aSRicardo Branco #include <sys/malloc.h>
9*78444b5aSRicardo Branco 
10*78444b5aSRicardo Branco #include <geom/geom.h>
11*78444b5aSRicardo Branco #include <geom/geom_dbg.h>
12*78444b5aSRicardo Branco #include <geom/label/g_label.h>
13*78444b5aSRicardo Branco 
14*78444b5aSRicardo Branco /*
15*78444b5aSRicardo Branco  * Taken from
16*78444b5aSRicardo Branco  * https://github.com/util-linux/util-linux/blob/master/include/swapheader.h
17*78444b5aSRicardo Branco  */
18*78444b5aSRicardo Branco 
19*78444b5aSRicardo Branco #define SWAP_VERSION 1
20*78444b5aSRicardo Branco #define SWAP_UUID_LENGTH 16
21*78444b5aSRicardo Branco #define SWAP_LABEL_LENGTH 16
22*78444b5aSRicardo Branco #define SWAP_SIGNATURE "SWAPSPACE2"
23*78444b5aSRicardo Branco #define SWAP_SIGNATURE_SZ (sizeof(SWAP_SIGNATURE) - 1)
24*78444b5aSRicardo Branco 
25*78444b5aSRicardo Branco struct swap_header_v1_2 {
26*78444b5aSRicardo Branco 	char	      bootbits[1024];    /* Space for disklabel etc. */
27*78444b5aSRicardo Branco 	uint32_t      version;
28*78444b5aSRicardo Branco 	uint32_t      last_page;
29*78444b5aSRicardo Branco 	uint32_t      nr_badpages;
30*78444b5aSRicardo Branco 	unsigned char uuid[SWAP_UUID_LENGTH];
31*78444b5aSRicardo Branco 	char	      volume_name[SWAP_LABEL_LENGTH];
32*78444b5aSRicardo Branco 	uint32_t      padding[117];
33*78444b5aSRicardo Branco 	uint32_t      badpages[1];
34*78444b5aSRicardo Branco };
35*78444b5aSRicardo Branco 
36*78444b5aSRicardo Branco typedef union {
37*78444b5aSRicardo Branco 	struct swap_header_v1_2	header;
38*78444b5aSRicardo Branco 	struct {
39*78444b5aSRicardo Branco 		uint8_t reserved[PAGE_SIZE - SWAP_SIGNATURE_SZ];
40*78444b5aSRicardo Branco 		char	signature[SWAP_SIGNATURE_SZ];
41*78444b5aSRicardo Branco 	} tail;
42*78444b5aSRicardo Branco } swhdr_t;
43*78444b5aSRicardo Branco 
44*78444b5aSRicardo Branco #define sw_version	header.version
45*78444b5aSRicardo Branco #define sw_volume_name	header.volume_name
46*78444b5aSRicardo Branco #define sw_signature	tail.signature
47*78444b5aSRicardo Branco 
48*78444b5aSRicardo Branco static void
g_label_swaplinux_taste(struct g_consumer * cp,char * label,size_t size)49*78444b5aSRicardo Branco g_label_swaplinux_taste(struct g_consumer *cp, char *label, size_t size)
50*78444b5aSRicardo Branco {
51*78444b5aSRicardo Branco 	struct g_provider *pp;
52*78444b5aSRicardo Branco 	swhdr_t *hdr;
53*78444b5aSRicardo Branco 
54*78444b5aSRicardo Branco 	g_topology_assert_not();
55*78444b5aSRicardo Branco 	pp = cp->provider;
56*78444b5aSRicardo Branco 	label[0] = '\0';
57*78444b5aSRicardo Branco 
58*78444b5aSRicardo Branco 	KASSERT(pp->sectorsize != 0, ("Tasting a disk with 0 sectorsize"));
59*78444b5aSRicardo Branco 	if ((PAGE_SIZE % pp->sectorsize) != 0)
60*78444b5aSRicardo Branco 		return;
61*78444b5aSRicardo Branco 
62*78444b5aSRicardo Branco 	hdr = (swhdr_t *)g_read_data(cp, 0, PAGE_SIZE, NULL);
63*78444b5aSRicardo Branco 	if (hdr == NULL)
64*78444b5aSRicardo Branco 		return;
65*78444b5aSRicardo Branco 
66*78444b5aSRicardo Branco 	/* Check version and magic string */
67*78444b5aSRicardo Branco 	if (hdr->sw_version == SWAP_VERSION &&
68*78444b5aSRicardo Branco 	    !memcmp(hdr->sw_signature, SWAP_SIGNATURE, SWAP_SIGNATURE_SZ))
69*78444b5aSRicardo Branco 		G_LABEL_DEBUG(1, "linux swap detected on %s.", pp->name);
70*78444b5aSRicardo Branco 	else
71*78444b5aSRicardo Branco 		goto exit_free;
72*78444b5aSRicardo Branco 
73*78444b5aSRicardo Branco 	/* Check for volume label */
74*78444b5aSRicardo Branco 	if (hdr->sw_volume_name[0] == '\0')
75*78444b5aSRicardo Branco 		goto exit_free;
76*78444b5aSRicardo Branco 
77*78444b5aSRicardo Branco 	/* Terminate label */
78*78444b5aSRicardo Branco 	hdr->sw_volume_name[sizeof(hdr->sw_volume_name) - 1] = '\0';
79*78444b5aSRicardo Branco 	strlcpy(label, hdr->sw_volume_name, size);
80*78444b5aSRicardo Branco 
81*78444b5aSRicardo Branco exit_free:
82*78444b5aSRicardo Branco 	g_free(hdr);
83*78444b5aSRicardo Branco }
84*78444b5aSRicardo Branco 
85*78444b5aSRicardo Branco struct g_label_desc g_label_swaplinux = {
86*78444b5aSRicardo Branco 	.ld_taste = g_label_swaplinux_taste,
87*78444b5aSRicardo Branco 	.ld_dirprefix = "swaplinux/",
88*78444b5aSRicardo Branco 	.ld_enabled = 1
89*78444b5aSRicardo Branco };
90*78444b5aSRicardo Branco 
91*78444b5aSRicardo Branco G_LABEL_INIT(swaplinux, g_label_swaplinux, "Create device nodes for Linux swap");
92