-
Notifications
You must be signed in to change notification settings - Fork 0
/
lmv-support-2.02.patch
306 lines (288 loc) · 10.1 KB
/
lmv-support-2.02.patch
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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
From: Alexander Rumyantsev <[email protected]>
Date: Mon Jul 13 14:34:12 UTC 2015
Subject: [PATCH] Install to LVM PVs
Original patch made by Gabriel de Perthuis <[email protected]>
http://lists.gnu.org/archive/html/grub-devel/2013-09/msg00113.html
This patch lets grub install to a reserved area in LVM physical volumes.
These bootloader areas can be created with LVM 2.02.99 and the --bootloaderareasize argument to pvcreate and vgconvert.
Tested it in QEMU and VMware, installing to and booting a disk that contains a PV and no partition table.
Adopted for CentOS 7.x by Alexander Rumyantsev <[email protected]>
Just add this file to patches list in RPM spec file and rebuild the package
diff -Naur grub-2.02~beta2/grub-core/disk/lvm.c grub-2.02~beta2-pve-boot/grub-core/disk/lvm.c
--- grub-2.02~beta2/grub-core/disk/lvm.c 2013-12-24 20:40:31.000000000 +0400
+++ grub-2.02~beta2-pve-boot/grub-core/disk/lvm.c 2015-07-09 11:39:27.662772922 +0300
@@ -95,6 +95,38 @@
}
}
+static struct grub_lvm_pv_header *
+grub_lvm_get_pvh(grub_disk_t disk, char buf[static GRUB_LVM_LABEL_SIZE])
+{
+ struct grub_lvm_label_header *lh = (struct grub_lvm_label_header *) buf;
+ unsigned int i;
+
+ /* Search for label. */
+ for (i = 0; i < GRUB_LVM_LABEL_SCAN_SECTORS; i++)
+ {
+ if (grub_disk_read (disk, i, 0, GRUB_LVM_LABEL_SIZE, buf))
+ return NULL;
+
+ if ((! grub_strncmp ((char *)lh->id, GRUB_LVM_LABEL_ID,
+ sizeof (lh->id)))
+ && (! grub_strncmp ((char *)lh->type, GRUB_LVM_LVM2_LABEL,
+ sizeof (lh->type))))
+ break;
+ }
+
+ /* Return if we didn't find a label. */
+ if (i == GRUB_LVM_LABEL_SCAN_SECTORS)
+ {
+#ifdef GRUB_UTIL
+ grub_util_info ("no LVM signature found");
+#endif
+ return NULL;
+ }
+
+ return (struct grub_lvm_pv_header *) (buf + grub_le_to_cpu32(lh->offset_xl));
+}
+
+
static struct grub_diskfilter_vg *
grub_lvm_detect (grub_disk_t disk,
struct grub_diskfilter_pv_id *id,
@@ -106,7 +138,6 @@
char vg_id[GRUB_LVM_ID_STRLEN+1];
char pv_id[GRUB_LVM_ID_STRLEN+1];
char *metadatabuf, *p, *q, *vgname;
- struct grub_lvm_label_header *lh = (struct grub_lvm_label_header *) buf;
struct grub_lvm_pv_header *pvh;
struct grub_lvm_disk_locn *dlocn;
struct grub_lvm_mda_header *mdah;
@@ -116,30 +147,9 @@
struct grub_diskfilter_vg *vg;
struct grub_diskfilter_pv *pv;
- /* Search for label. */
- for (i = 0; i < GRUB_LVM_LABEL_SCAN_SECTORS; i++)
- {
- err = grub_disk_read (disk, i, 0, sizeof(buf), buf);
- if (err)
- goto fail;
-
- if ((! grub_strncmp ((char *)lh->id, GRUB_LVM_LABEL_ID,
- sizeof (lh->id)))
- && (! grub_strncmp ((char *)lh->type, GRUB_LVM_LVM2_LABEL,
- sizeof (lh->type))))
- break;
- }
-
- /* Return if we didn't find a label. */
- if (i == GRUB_LVM_LABEL_SCAN_SECTORS)
- {
-#ifdef GRUB_UTIL
- grub_util_info ("no LVM signature found");
-#endif
- goto fail;
- }
-
- pvh = (struct grub_lvm_pv_header *) (buf + grub_le_to_cpu32(lh->offset_xl));
+ pvh = grub_lvm_get_pvh(disk, buf);
+ if (! pvh)
+ goto fail;
for (i = 0, j = 0; i < GRUB_LVM_ID_LEN; i++)
{
@@ -152,7 +162,7 @@
dlocn = pvh->disk_areas_xl;
dlocn++;
- /* Is it possible to have multiple data/metadata areas? I haven't
+ /* Is it possible to have multiple data areas? I haven't
seen devices that have it. */
if (dlocn->offset)
{
@@ -770,6 +780,89 @@
return NULL;
}
+#ifdef GRUB_UTIL
+int
+grub_util_is_lvm(grub_disk_t disk)
+{
+ struct grub_diskfilter_pv_id id;
+ struct grub_diskfilter_vg *vg;
+ grub_disk_addr_t start_sector;
+ vg = grub_lvm_detect(disk, &id, &start_sector);
+ if (! vg)
+ return 0;
+ /* don't free the vg, it's held by grub_diskfilter_vg_register */
+ grub_free(id.uuid);
+ return 1;
+}
+
+grub_err_t
+grub_util_lvm_embed (struct grub_disk *disk, unsigned int *nsectors,
+ unsigned int max_nsectors,
+ grub_embed_type_t embed_type,
+ grub_disk_addr_t **sectors)
+{
+ char buf[GRUB_LVM_LABEL_SIZE];
+ struct grub_lvm_pv_header *pvh;
+ struct grub_lvm_pv_header_ext *pvh_ext;
+ struct grub_diskfilter_pv *pv = NULL;
+ struct grub_diskfilter_vg *vg = NULL;
+ struct grub_lvm_disk_locn *dlocn;
+ grub_uint64_t ba_offset, ba_size, ba_start_sector;
+ unsigned int i;
+
+ if (embed_type != GRUB_EMBED_PCBIOS)
+ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "LVM curently supports only PC-BIOS embedding");
+ if (disk->partition)
+ return grub_error (GRUB_ERR_BUG, "disk isn't LVM");
+ pv = grub_diskfilter_get_pv_from_disk (disk, &vg);
+ if (! pv)
+ return grub_error (GRUB_ERR_BUG, "disk isn't LVM");
+
+ pvh = grub_lvm_get_pvh(disk, buf);
+ if (! pvh)
+ return grub_error (GRUB_ERR_BUG, "disk isn't LVM");
+
+ dlocn = pvh->disk_areas_xl;
+
+ /* skip past the data area list */
+ while (dlocn->offset)
+ dlocn++;
+ dlocn++;
+ /* and the metadata area list */
+ while (dlocn->offset)
+ dlocn++;
+ dlocn++;
+
+ pvh_ext = (struct grub_lvm_pv_header_ext*)dlocn;
+ if (! pvh_ext->version_xl)
+ return grub_error (GRUB_ERR_BUG, "LVM PV doesn't have a bootloader area");
+
+ dlocn = pvh_ext->disk_areas_xl;
+ ba_offset = grub_le_to_cpu64 (dlocn->offset);
+ ba_size = grub_le_to_cpu64 (dlocn->size);
+ if (! (ba_offset && ba_size))
+ return grub_error (GRUB_ERR_BUG, "LVM PV doesn't have a bootloader area");
+ /* could be worked around with extra arithmetic if this actually happens */
+ if (ba_offset % GRUB_DISK_SECTOR_SIZE)
+ return grub_error (
+ GRUB_ERR_BUG, "LVM bootloader area is improperly aligned");
+ ba_start_sector = ba_offset / GRUB_DISK_SECTOR_SIZE;
+
+ *nsectors = ba_size / GRUB_DISK_SECTOR_SIZE;
+ if (*nsectors > max_nsectors)
+ *nsectors = max_nsectors;
+
+ *sectors = grub_malloc (*nsectors * sizeof (**sectors));
+ if (!*sectors)
+ return grub_errno;
+ for (i = 0; i < *nsectors; i++)
+ (*sectors)[i] = ba_start_sector + i;
+
+ return GRUB_ERR_NONE;
+}
+#endif
+
static struct grub_diskfilter grub_lvm_dev = {
diff -Naur grub-2.02~beta2/include/grub/diskfilter.h grub-2.02~beta2-pve-boot/include/grub/diskfilter.h
--- grub-2.02~beta2/include/grub/diskfilter.h 2013-12-24 20:29:27.000000000 +0400
+++ grub-2.02~beta2-pve-boot/include/grub/diskfilter.h 2015-07-07 12:37:29.040865099 +0300
@@ -75,6 +75,9 @@
#ifdef GRUB_UTIL
char **partmaps;
#endif
+ /* Optional bootloader embedding area */
+ grub_uint64_t ba_offset;
+ grub_uint64_t ba_size;
};
struct grub_diskfilter_lv {
diff -Naur grub-2.02~beta2/include/grub/emu/hostdisk.h grub-2.02~beta2-pve-boot/include/grub/emu/hostdisk.h
--- grub-2.02~beta2/include/grub/emu/hostdisk.h 2013-12-24 20:40:31.000000000 +0400
+++ grub-2.02~beta2-pve-boot/include/grub/emu/hostdisk.h 2015-07-07 12:37:44.581864173 +0300
@@ -45,9 +45,16 @@
char *
grub_util_get_ldm (grub_disk_t disk, grub_disk_addr_t start);
int
+grub_util_is_lvm (grub_disk_t disk);
+int
grub_util_is_ldm (grub_disk_t disk);
#ifdef GRUB_UTIL
grub_err_t
+grub_util_lvm_embed (struct grub_disk *disk, unsigned int *nsectors,
+ unsigned int max_nsectors,
+ grub_embed_type_t embed_type,
+ grub_disk_addr_t **sectors);
+grub_err_t
grub_util_ldm_embed (struct grub_disk *disk, unsigned int *nsectors,
unsigned int max_nsectors,
grub_embed_type_t embed_type,
diff -Naur grub-2.02~beta2/include/grub/lvm.h grub-2.02~beta2-pve-boot/include/grub/lvm.h
--- grub-2.02~beta2/include/grub/lvm.h 2013-12-24 20:29:27.000000000 +0400
+++ grub-2.02~beta2-pve-boot/include/grub/lvm.h 2015-07-07 12:37:48.255863954 +0300
@@ -62,6 +62,13 @@
struct grub_lvm_disk_locn disk_areas_xl[0]; /* Two lists */
} GRUB_PACKED;
+struct grub_lvm_pv_header_ext {
+ grub_uint32_t version_xl;
+ grub_uint32_t flags_xl;
+ /* NULL-terminated list of bootloader embedding areas */
+ struct grub_lvm_disk_locn disk_areas_xl[0];
+} __attribute__ ((packed));
+
#define GRUB_LVM_FMTT_MAGIC "\040\114\126\115\062\040\170\133\065\101\045\162\060\116\052\076"
#define GRUB_LVM_FMTT_VERSION 1
#define GRUB_LVM_MDA_HEADER_SIZE 512
diff -Naur grub-2.02~beta2/util/setup.c grub-2.02~beta2-pve-boot/util/setup.c
--- grub-2.02~beta2/util/setup.c 2013-12-24 20:29:28.000000000 +0400
+++ grub-2.02~beta2-pve-boot/util/setup.c 2015-07-13 16:43:14.990087122 +0300
@@ -388,7 +388,7 @@
.container = dest_dev->disk->partition,
.multiple_partmaps = 0
};
- int is_ldm;
+ int is_ldm, is_lvm;
grub_err_t err;
grub_disk_addr_t *sectors;
int i;
@@ -421,8 +421,9 @@
grub_errno = GRUB_ERR_NONE;
is_ldm = grub_util_is_ldm (dest_dev->disk);
+ is_lvm = grub_util_is_lvm (dest_dev->disk);
- if (fs_probe)
+ if (!is_lvm && fs_probe)
{
if (!fs && !ctx.dest_partmap)
grub_util_error (_("unable to identify a filesystem in %s; safety check can't be performed"),
@@ -460,7 +461,7 @@
}
- if (! ctx.dest_partmap && ! fs && !is_ldm)
+ if (! ctx.dest_partmap && ! fs && !is_ldm && !is_lvm)
{
grub_util_warn ("%s", _("Attempting to install GRUB to a partitionless disk or to a partition. This is a BAD idea."));
goto unable_to_embed;
@@ -497,7 +498,25 @@
maxsec = ((0x78000 - GRUB_KERNEL_I386_PC_LINK_ADDR)
>> GRUB_DISK_SECTOR_BITS);
- if (is_ldm)
+ if (is_lvm) {
+ err = grub_util_lvm_embed (dest_dev->disk, &nsec, maxsec,
+ GRUB_EMBED_PCBIOS, §ors);
+
+ /* DIRTY HACK: Do not allow blkid to determine msdos partition type */
+
+ /* clear partition table */
+ memset (boot_img + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC,
+ 0, GRUB_BOOT_MACHINE_PART_END - GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC);
+
+ /* first partition boot flag: invalid partition */
+ ((struct grub_msdos_partition_entry *)
+ (boot_img + GRUB_BOOT_MACHINE_PART_START))->flag = 0x01;
+
+ /* first partition type: GPT */
+ ((struct grub_msdos_partition_entry *)
+ (boot_img + GRUB_BOOT_MACHINE_PART_START))->type = GRUB_PC_PARTITION_TYPE_GPT_DISK;
+ }
+ else if (is_ldm)
err = grub_util_ldm_embed (dest_dev->disk, &nsec, maxsec,
GRUB_EMBED_PCBIOS, §ors);
else if (ctx.dest_partmap)