summaryrefslogtreecommitdiff
path: root/lib/device/dev-lvm1-pool.c
blob: b51aba5bf8f7358a41684abf78e9d9f079e745f4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/*
 * Copyright (C) 2018 Red Hat, Inc. All rights reserved.
 *
 * This file is part of LVM2.
 *
 * This copyrighted material is made available to anyone wishing to use,
 * modify, copy, or redistribute it subject to the terms and conditions
 * of the GNU Lesser General Public License v.2.1.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include "lib/misc/lib.h"
#include "lib/device/dev-type.h"
#include "lib/mm/xlate.h"

/*
 * These lvm1 structs just used NAME_LEN in the previous format1 lvm2 code, but
 * NAME_LEN was defined as 128 in generic lvm2 code that was not lvm1-specific
 * and not disk-format-specific.
 */

#define LVM1_NAME_LEN 128

struct data_area {
	uint32_t base;
	uint32_t size;
} __attribute__ ((packed));

struct pv_disk {
	int8_t id[2];
	uint16_t version;       /* lvm version */
	struct data_area pv_on_disk;
	struct data_area vg_on_disk;
	struct data_area pv_uuidlist_on_disk;
	struct data_area lv_on_disk;
	struct data_area pe_on_disk;
	int8_t pv_uuid[LVM1_NAME_LEN];
	int8_t vg_name[LVM1_NAME_LEN];
	int8_t system_id[LVM1_NAME_LEN];     /* for vgexport/vgimport */
	uint32_t pv_major;
	uint32_t pv_number;
	uint32_t pv_status;
	uint32_t pv_allocatable;
	uint32_t pv_size;
	uint32_t lv_cur;
	uint32_t pe_size;
	uint32_t pe_total;
	uint32_t pe_allocated;

	/* only present on version == 2 pv's */
	uint32_t pe_start;
} __attribute__ ((packed));


int dev_is_lvm1(struct device *dev, char *buf, int buflen)
{
	struct pv_disk *pvd = (struct pv_disk *) buf;
	uint32_t version;
	int ret;

	version = xlate16(pvd->version);

	if (pvd->id[0] == 'H' && pvd->id[1] == 'M' &&
	    (version == 1 || version == 2))
		ret = 1;
	else
		ret = 0;

	return ret;
}


#define POOL_MAGIC 0x011670
#define POOL_NAME_SIZE 256

#define NSPMajorVersion        4
#define NSPMinorVersion        1
#define NSPUpdateLevel 3

/* When checking for version matching, the first two numbers **
** are important for metadata formats, a.k.a pool labels.   **
** All the numbers are important when checking if the user  **
** space tools match up with the kernel module............. */

#define POOL_VERSION           (NSPMajorVersion << 16 | \
				NSPMinorVersion <<  8 | \
				NSPUpdateLevel)

struct pool_disk {
	uint64_t pl_magic;      /* Pool magic number */
	uint64_t pl_pool_id;    /* Unique pool identifier */
	char pl_pool_name[POOL_NAME_SIZE];      /* Name of pool */
	uint32_t pl_version;    /* Pool version */
	uint32_t pl_subpools;   /* Number of subpools in this pool */
	uint32_t pl_sp_id;      /* Subpool number within pool */
	uint32_t pl_sp_devs;    /* Number of data partitions in this subpool */
	uint32_t pl_sp_devid;   /* Partition number within subpool */
	uint32_t pl_sp_type;    /* Partition type */
	uint64_t pl_blocks;     /* Number of blocks in this partition */
	uint32_t pl_striping;   /* Striping size within subpool */
	/*
	 * If the number of DMEP devices is zero, then the next field **
	 * ** (pl_sp_dmepid) becomes the subpool ID for redirection.  In **
	 * ** other words, if this subpool does not have the capability  **
	 * ** to do DMEP, then it must specify which subpool will do it  **
	 * ** in it's place
	 */

	/*
	 * While the next 3 field are no longer used, they must stay to keep **
	 * ** backward compatibility...........................................
	 */
	uint32_t pl_sp_dmepdevs;/* Number of dmep devices in this subpool */
	uint32_t pl_sp_dmepid;  /* Dmep device number within subpool */
	uint32_t pl_sp_weight;  /* if dmep dev, pref to using it */

	uint32_t pl_minor;      /* the pool minor number */
	uint32_t pl_padding;    /* reminder - think about alignment */

	/*
	 * Even though we're zeroing out 8k at the front of the disk before
	 * writing the label, putting this in
	 */
	char pl_reserve[184];   /* bump the structure size out to 512 bytes */
};

#define CPIN_8(x, y, z) {memcpy((x), (y), (z));}
#define CPIN_16(x, y) {(x) = xlate16_be((y));}
#define CPIN_32(x, y) {(x) = xlate32_be((y));}
#define CPIN_64(x, y) {(x) = xlate64_be((y));}

static void pool_label_in(struct pool_disk *pl, void *buf)
{
	struct pool_disk *bufpl = (struct pool_disk *) buf;

	CPIN_64(pl->pl_magic, bufpl->pl_magic);
	CPIN_64(pl->pl_pool_id, bufpl->pl_pool_id);
	CPIN_8(pl->pl_pool_name, bufpl->pl_pool_name, POOL_NAME_SIZE);
	CPIN_32(pl->pl_version, bufpl->pl_version);
	CPIN_32(pl->pl_subpools, bufpl->pl_subpools);
	CPIN_32(pl->pl_sp_id, bufpl->pl_sp_id);
	CPIN_32(pl->pl_sp_devs, bufpl->pl_sp_devs);
	CPIN_32(pl->pl_sp_devid, bufpl->pl_sp_devid);
	CPIN_32(pl->pl_sp_type, bufpl->pl_sp_type);
	CPIN_64(pl->pl_blocks, bufpl->pl_blocks);
	CPIN_32(pl->pl_striping, bufpl->pl_striping);
	CPIN_32(pl->pl_sp_dmepdevs, bufpl->pl_sp_dmepdevs);
	CPIN_32(pl->pl_sp_dmepid, bufpl->pl_sp_dmepid);
	CPIN_32(pl->pl_sp_weight, bufpl->pl_sp_weight);
	CPIN_32(pl->pl_minor, bufpl->pl_minor);
	CPIN_32(pl->pl_padding, bufpl->pl_padding);
	CPIN_8(pl->pl_reserve, bufpl->pl_reserve, 184);
}

int dev_is_pool(struct device *dev, char *buf, int buflen)
{
	struct pool_disk pd;
	int ret;

	pool_label_in(&pd, buf);

	/* can ignore 8 rightmost bits for ondisk format check */
	if ((pd.pl_magic == POOL_MAGIC) &&
	    (pd.pl_version >> 8 == POOL_VERSION >> 8))
		ret = 1;
	else
		ret = 0;

	return ret;
}