lvm.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092
  1. /* lvm.c - module to read Logical Volumes. */
  2. /*
  3. * GRUB -- GRand Unified Bootloader
  4. * Copyright (C) 2006,2007,2008,2009,2011 Free Software Foundation, Inc.
  5. *
  6. * GRUB is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * GRUB is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <grub/dl.h>
  20. #include <grub/disk.h>
  21. #include <grub/mm.h>
  22. #include <grub/err.h>
  23. #include <grub/misc.h>
  24. #include <grub/lvm.h>
  25. #include <grub/partition.h>
  26. #include <grub/i18n.h>
  27. #include <grub/safemath.h>
  28. #ifdef GRUB_UTIL
  29. #include <grub/emu/misc.h>
  30. #include <grub/emu/hostdisk.h>
  31. #endif
  32. GRUB_MOD_LICENSE ("GPLv3+");
  33. struct cache_lv
  34. {
  35. struct grub_diskfilter_lv *lv;
  36. char *cache_pool;
  37. char *origin;
  38. struct cache_lv *next;
  39. };
  40. /* Go the string STR and return the number after STR. *P will point
  41. at the number. In case STR is not found, *P will be NULL and the
  42. return value will be 0. */
  43. static grub_uint64_t
  44. grub_lvm_getvalue (const char ** const p, const char *str)
  45. {
  46. *p = grub_strstr (*p, str);
  47. if (! *p)
  48. return 0;
  49. *p += grub_strlen (str);
  50. return grub_strtoull (*p, p, 10);
  51. }
  52. #if 0
  53. static int
  54. grub_lvm_checkvalue (char **p, char *str, char *tmpl)
  55. {
  56. int tmpllen = grub_strlen (tmpl);
  57. *p = grub_strstr (*p, str);
  58. if (! *p)
  59. return 0;
  60. *p += grub_strlen (str);
  61. if (**p != '"')
  62. return 0;
  63. return (grub_memcmp (*p + 1, tmpl, tmpllen) == 0 && (*p)[tmpllen + 1] == '"');
  64. }
  65. #endif
  66. static int
  67. grub_lvm_check_flag (const char *p, const char *str, const char *flag)
  68. {
  69. grub_size_t len_str = grub_strlen (str), len_flag = grub_strlen (flag);
  70. while (1)
  71. {
  72. const char *q;
  73. p = grub_strstr (p, str);
  74. if (! p)
  75. return 0;
  76. p += len_str;
  77. if (grub_memcmp (p, " = [", sizeof (" = [") - 1) != 0)
  78. continue;
  79. q = p + sizeof (" = [") - 1;
  80. while (1)
  81. {
  82. while (grub_isspace (*q))
  83. q++;
  84. if (*q != '"')
  85. return 0;
  86. q++;
  87. if (grub_memcmp (q, flag, len_flag) == 0 && q[len_flag] == '"')
  88. return 1;
  89. while (*q != '"')
  90. q++;
  91. q++;
  92. if (*q == ']')
  93. return 0;
  94. q++;
  95. }
  96. }
  97. }
  98. static void
  99. grub_lvm_free_cache_lvs (struct cache_lv *cache_lvs)
  100. {
  101. struct cache_lv *cache;
  102. while ((cache = cache_lvs))
  103. {
  104. cache_lvs = cache_lvs->next;
  105. if (cache->lv)
  106. {
  107. unsigned int i;
  108. for (i = 0; i < cache->lv->segment_count; ++i)
  109. if (cache->lv->segments)
  110. grub_free (cache->lv->segments[i].nodes);
  111. grub_free (cache->lv->segments);
  112. grub_free (cache->lv->fullname);
  113. grub_free (cache->lv->idname);
  114. grub_free (cache->lv->name);
  115. }
  116. grub_free (cache->lv);
  117. grub_free (cache->origin);
  118. grub_free (cache->cache_pool);
  119. grub_free (cache);
  120. }
  121. }
  122. static struct grub_diskfilter_vg *
  123. grub_lvm_detect (grub_disk_t disk,
  124. struct grub_diskfilter_pv_id *id,
  125. grub_disk_addr_t *start_sector)
  126. {
  127. grub_err_t err;
  128. grub_uint64_t mda_offset, mda_size;
  129. grub_size_t ptr;
  130. char buf[GRUB_LVM_LABEL_SIZE];
  131. char vg_id[GRUB_LVM_ID_STRLEN+1];
  132. char pv_id[GRUB_LVM_ID_STRLEN+1];
  133. char *metadatabuf, *mda_end, *vgname;
  134. const char *p, *q;
  135. struct grub_lvm_label_header *lh = (struct grub_lvm_label_header *) buf;
  136. struct grub_lvm_pv_header *pvh;
  137. struct grub_lvm_disk_locn *dlocn;
  138. struct grub_lvm_mda_header *mdah;
  139. struct grub_lvm_raw_locn *rlocn;
  140. unsigned int i, j;
  141. grub_size_t vgname_len;
  142. struct grub_diskfilter_vg *vg;
  143. struct grub_diskfilter_pv *pv;
  144. /* Search for label. */
  145. for (i = 0; i < GRUB_LVM_LABEL_SCAN_SECTORS; i++)
  146. {
  147. err = grub_disk_read (disk, i, 0, sizeof(buf), buf);
  148. if (err)
  149. goto fail;
  150. if ((! grub_strncmp ((char *)lh->id, GRUB_LVM_LABEL_ID,
  151. sizeof (lh->id)))
  152. && (! grub_strncmp ((char *)lh->type, GRUB_LVM_LVM2_LABEL,
  153. sizeof (lh->type))))
  154. break;
  155. }
  156. /* Return if we didn't find a label. */
  157. if (i == GRUB_LVM_LABEL_SCAN_SECTORS)
  158. {
  159. #ifdef GRUB_UTIL
  160. grub_util_info ("no LVM signature found");
  161. #endif
  162. goto fail;
  163. }
  164. /*
  165. * We read a grub_lvm_pv_header and then 2 grub_lvm_disk_locns that
  166. * immediately follow the PV header. Make sure we have space for both.
  167. */
  168. if (grub_le_to_cpu32 (lh->offset_xl) >=
  169. GRUB_LVM_LABEL_SIZE - sizeof (struct grub_lvm_pv_header) -
  170. 2 * sizeof (struct grub_lvm_disk_locn))
  171. {
  172. #ifdef GRUB_UTIL
  173. grub_util_info ("LVM PV header/disk locations are beyond the end of the block");
  174. #endif
  175. goto fail;
  176. }
  177. pvh = (struct grub_lvm_pv_header *) (buf + grub_le_to_cpu32(lh->offset_xl));
  178. for (i = 0, j = 0; i < GRUB_LVM_ID_LEN; i++)
  179. {
  180. pv_id[j++] = pvh->pv_uuid[i];
  181. if ((i != 1) && (i != 29) && (i % 4 == 1))
  182. pv_id[j++] = '-';
  183. }
  184. pv_id[j] = '\0';
  185. dlocn = pvh->disk_areas_xl;
  186. dlocn++;
  187. /* Is it possible to have multiple data/metadata areas? I haven't
  188. seen devices that have it. */
  189. if (dlocn->offset)
  190. {
  191. grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
  192. "we don't support multiple LVM data areas");
  193. #ifdef GRUB_UTIL
  194. grub_util_info ("we don't support multiple LVM data areas");
  195. #endif
  196. goto fail;
  197. }
  198. dlocn++;
  199. mda_offset = grub_le_to_cpu64 (dlocn->offset);
  200. mda_size = grub_le_to_cpu64 (dlocn->size);
  201. /* It's possible to have multiple copies of metadata areas, we just use the
  202. first one. */
  203. /* Allocate buffer space for the circular worst-case scenario. */
  204. metadatabuf = grub_calloc (2, mda_size);
  205. if (! metadatabuf)
  206. goto fail;
  207. err = grub_disk_read (disk, 0, mda_offset, mda_size, metadatabuf);
  208. if (err)
  209. goto fail2;
  210. mdah = (struct grub_lvm_mda_header *) metadatabuf;
  211. if ((grub_strncmp ((char *)mdah->magic, GRUB_LVM_FMTT_MAGIC,
  212. sizeof (mdah->magic)))
  213. || (grub_le_to_cpu32 (mdah->version) != GRUB_LVM_FMTT_VERSION))
  214. {
  215. grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
  216. "unknown LVM metadata header");
  217. #ifdef GRUB_UTIL
  218. grub_util_info ("unknown LVM metadata header");
  219. #endif
  220. goto fail2;
  221. }
  222. rlocn = mdah->raw_locns;
  223. if (grub_le_to_cpu64 (rlocn->offset) >= grub_le_to_cpu64 (mda_size))
  224. {
  225. #ifdef GRUB_UTIL
  226. grub_util_info ("metadata offset is beyond end of metadata area");
  227. #endif
  228. goto fail2;
  229. }
  230. if (grub_le_to_cpu64 (rlocn->offset) + grub_le_to_cpu64 (rlocn->size) >
  231. grub_le_to_cpu64 (mdah->size))
  232. {
  233. if (2 * mda_size < GRUB_LVM_MDA_HEADER_SIZE ||
  234. (grub_le_to_cpu64 (rlocn->offset) + grub_le_to_cpu64 (rlocn->size) -
  235. grub_le_to_cpu64 (mdah->size) > mda_size - GRUB_LVM_MDA_HEADER_SIZE))
  236. {
  237. #ifdef GRUB_UTIL
  238. grub_util_info ("cannot copy metadata wrap in circular buffer");
  239. #endif
  240. goto fail2;
  241. }
  242. /* Metadata is circular. Copy the wrap in place. */
  243. grub_memcpy (metadatabuf + mda_size,
  244. metadatabuf + GRUB_LVM_MDA_HEADER_SIZE,
  245. grub_le_to_cpu64 (rlocn->offset) +
  246. grub_le_to_cpu64 (rlocn->size) -
  247. grub_le_to_cpu64 (mdah->size));
  248. }
  249. if (grub_add ((grub_size_t)metadatabuf,
  250. (grub_size_t)grub_le_to_cpu64 (rlocn->offset),
  251. &ptr))
  252. {
  253. error_parsing_metadata:
  254. #ifdef GRUB_UTIL
  255. grub_util_info ("error parsing metadata");
  256. #endif
  257. goto fail2;
  258. }
  259. p = q = (char *)ptr;
  260. if (grub_add (ptr, (grub_size_t) grub_le_to_cpu64 (rlocn->size), &ptr))
  261. goto error_parsing_metadata;
  262. mda_end = (char *)ptr;
  263. while (*q != ' ' && q < mda_end)
  264. q++;
  265. if (q == mda_end)
  266. goto error_parsing_metadata;
  267. vgname_len = q - p;
  268. vgname = grub_malloc (vgname_len + 1);
  269. if (!vgname)
  270. goto fail2;
  271. grub_memcpy (vgname, p, vgname_len);
  272. vgname[vgname_len] = '\0';
  273. p = grub_strstr (q, "id = \"");
  274. if (p == NULL)
  275. {
  276. #ifdef GRUB_UTIL
  277. grub_util_info ("couldn't find ID");
  278. #endif
  279. goto fail3;
  280. }
  281. p += sizeof ("id = \"") - 1;
  282. grub_memcpy (vg_id, p, GRUB_LVM_ID_STRLEN);
  283. vg_id[GRUB_LVM_ID_STRLEN] = '\0';
  284. vg = grub_diskfilter_get_vg_by_uuid (GRUB_LVM_ID_STRLEN, vg_id);
  285. if (! vg)
  286. {
  287. struct cache_lv *cache_lvs = NULL;
  288. /* First time we see this volume group. We've to create the
  289. whole volume group structure. */
  290. vg = grub_malloc (sizeof (*vg));
  291. if (! vg)
  292. goto fail3;
  293. vg->name = vgname;
  294. vg->uuid = grub_malloc (GRUB_LVM_ID_STRLEN);
  295. if (! vg->uuid)
  296. goto fail3;
  297. grub_memcpy (vg->uuid, vg_id, GRUB_LVM_ID_STRLEN);
  298. vg->uuid_len = GRUB_LVM_ID_STRLEN;
  299. vg->extent_size = grub_lvm_getvalue (&p, "extent_size = ");
  300. if (p == NULL)
  301. {
  302. #ifdef GRUB_UTIL
  303. grub_util_info ("unknown extent size");
  304. #endif
  305. goto fail4;
  306. }
  307. vg->lvs = NULL;
  308. vg->pvs = NULL;
  309. p = grub_strstr (p, "physical_volumes {");
  310. if (p)
  311. {
  312. p += sizeof ("physical_volumes {") - 1;
  313. /* Add all the pvs to the volume group. */
  314. while (1)
  315. {
  316. grub_ssize_t s;
  317. while (grub_isspace (*p) && p < mda_end)
  318. p++;
  319. if (p == mda_end)
  320. goto fail4;
  321. if (*p == '}')
  322. break;
  323. pv = grub_zalloc (sizeof (*pv));
  324. q = p;
  325. while (*q != ' ' && q < mda_end)
  326. q++;
  327. if (q == mda_end)
  328. goto pvs_fail_noname;
  329. s = q - p;
  330. pv->name = grub_malloc (s + 1);
  331. grub_memcpy (pv->name, p, s);
  332. pv->name[s] = '\0';
  333. p = grub_strstr (p, "id = \"");
  334. if (p == NULL)
  335. goto pvs_fail;
  336. p += sizeof("id = \"") - 1;
  337. pv->id.uuid = grub_malloc (GRUB_LVM_ID_STRLEN);
  338. if (!pv->id.uuid)
  339. goto pvs_fail;
  340. grub_memcpy (pv->id.uuid, p, GRUB_LVM_ID_STRLEN);
  341. pv->id.uuidlen = GRUB_LVM_ID_STRLEN;
  342. pv->start_sector = grub_lvm_getvalue (&p, "pe_start = ");
  343. if (p == NULL)
  344. {
  345. #ifdef GRUB_UTIL
  346. grub_util_info ("unknown pe_start");
  347. #endif
  348. goto pvs_fail;
  349. }
  350. p = grub_strchr (p, '}');
  351. if (p == NULL)
  352. {
  353. #ifdef GRUB_UTIL
  354. grub_util_info ("error parsing pe_start");
  355. #endif
  356. goto pvs_fail;
  357. }
  358. p++;
  359. pv->disk = NULL;
  360. pv->next = vg->pvs;
  361. vg->pvs = pv;
  362. continue;
  363. pvs_fail:
  364. grub_free (pv->name);
  365. pvs_fail_noname:
  366. grub_free (pv);
  367. goto fail4;
  368. }
  369. }
  370. else
  371. goto fail4;
  372. p = grub_strstr (p, "logical_volumes {");
  373. if (p)
  374. {
  375. p += sizeof ("logical_volumes {") - 1;
  376. /* And add all the lvs to the volume group. */
  377. while (1)
  378. {
  379. grub_ssize_t s;
  380. int skip_lv = 0;
  381. struct grub_diskfilter_lv *lv;
  382. struct grub_diskfilter_segment *seg;
  383. int is_pvmove;
  384. while (grub_isspace (*p) && p < mda_end)
  385. p++;
  386. if (p == mda_end)
  387. goto fail4;
  388. if (*p == '}')
  389. break;
  390. lv = grub_zalloc (sizeof (*lv));
  391. q = p;
  392. while (*q != ' ' && q < mda_end)
  393. q++;
  394. if (q == mda_end)
  395. goto lvs_fail;
  396. s = q - p;
  397. lv->name = grub_strndup (p, s);
  398. if (!lv->name)
  399. goto lvs_fail;
  400. {
  401. const char *iptr;
  402. char *optr;
  403. /*
  404. * This is kind of hard to read with our safe (but rather
  405. * baroque) math primatives, but it boils down to:
  406. *
  407. * sz0 = vgname_len * 2 + 1 +
  408. * s * 2 + 1 +
  409. * sizeof ("lvm/") - 1;
  410. */
  411. grub_size_t sz0 = vgname_len, sz1 = s;
  412. if (grub_mul (sz0, 2, &sz0) ||
  413. grub_add (sz0, 1, &sz0) ||
  414. grub_mul (sz1, 2, &sz1) ||
  415. grub_add (sz1, 1, &sz1) ||
  416. grub_add (sz0, sz1, &sz0) ||
  417. grub_add (sz0, sizeof ("lvm/") - 1, &sz0))
  418. goto lvs_fail;
  419. lv->fullname = grub_malloc (sz0);
  420. if (!lv->fullname)
  421. goto lvs_fail;
  422. grub_memcpy (lv->fullname, "lvm/", sizeof ("lvm/") - 1);
  423. optr = lv->fullname + sizeof ("lvm/") - 1;
  424. for (iptr = vgname; iptr < vgname + vgname_len; iptr++)
  425. {
  426. *optr++ = *iptr;
  427. if (*iptr == '-')
  428. *optr++ = '-';
  429. }
  430. *optr++ = '-';
  431. for (iptr = p; iptr < p + s; iptr++)
  432. {
  433. *optr++ = *iptr;
  434. if (*iptr == '-')
  435. *optr++ = '-';
  436. }
  437. *optr++ = 0;
  438. lv->idname = grub_malloc (sizeof ("lvmid/")
  439. + 2 * GRUB_LVM_ID_STRLEN + 1);
  440. if (!lv->idname)
  441. goto lvs_fail;
  442. grub_memcpy (lv->idname, "lvmid/",
  443. sizeof ("lvmid/") - 1);
  444. grub_memcpy (lv->idname + sizeof ("lvmid/") - 1,
  445. vg_id, GRUB_LVM_ID_STRLEN);
  446. lv->idname[sizeof ("lvmid/") - 1 + GRUB_LVM_ID_STRLEN] = '/';
  447. p = grub_strstr (q, "id = \"");
  448. if (p == NULL)
  449. {
  450. #ifdef GRUB_UTIL
  451. grub_util_info ("couldn't find ID");
  452. #endif
  453. goto lvs_fail;
  454. }
  455. p += sizeof ("id = \"") - 1;
  456. grub_memcpy (lv->idname + sizeof ("lvmid/") - 1
  457. + GRUB_LVM_ID_STRLEN + 1,
  458. p, GRUB_LVM_ID_STRLEN);
  459. lv->idname[sizeof ("lvmid/") - 1 + 2 * GRUB_LVM_ID_STRLEN + 1] = '\0';
  460. }
  461. lv->size = 0;
  462. lv->visible = grub_lvm_check_flag (p, "status", "VISIBLE");
  463. is_pvmove = grub_lvm_check_flag (p, "status", "PVMOVE");
  464. lv->segment_count = grub_lvm_getvalue (&p, "segment_count = ");
  465. if (p == NULL)
  466. {
  467. #ifdef GRUB_UTIL
  468. grub_util_info ("unknown segment_count");
  469. #endif
  470. goto lvs_fail;
  471. }
  472. lv->segments = grub_calloc (lv->segment_count, sizeof (*seg));
  473. seg = lv->segments;
  474. for (i = 0; i < lv->segment_count; i++)
  475. {
  476. p = grub_strstr (p, "segment");
  477. if (p == NULL)
  478. {
  479. #ifdef GRUB_UTIL
  480. grub_util_info ("unknown segment");
  481. #endif
  482. goto lvs_segment_fail;
  483. }
  484. seg->start_extent = grub_lvm_getvalue (&p, "start_extent = ");
  485. if (p == NULL)
  486. {
  487. #ifdef GRUB_UTIL
  488. grub_util_info ("unknown start_extent");
  489. #endif
  490. goto lvs_segment_fail;
  491. }
  492. seg->extent_count = grub_lvm_getvalue (&p, "extent_count = ");
  493. if (p == NULL)
  494. {
  495. #ifdef GRUB_UTIL
  496. grub_util_info ("unknown extent_count");
  497. #endif
  498. goto lvs_segment_fail;
  499. }
  500. p = grub_strstr (p, "type = \"");
  501. if (p == NULL)
  502. goto lvs_segment_fail;
  503. p += sizeof("type = \"") - 1;
  504. lv->size += seg->extent_count * vg->extent_size;
  505. if (grub_memcmp (p, "striped\"",
  506. sizeof ("striped\"") - 1) == 0)
  507. {
  508. struct grub_diskfilter_node *stripe;
  509. seg->type = GRUB_DISKFILTER_STRIPED;
  510. seg->node_count = grub_lvm_getvalue (&p, "stripe_count = ");
  511. if (p == NULL)
  512. {
  513. #ifdef GRUB_UTIL
  514. grub_util_info ("unknown stripe_count");
  515. #endif
  516. goto lvs_segment_fail;
  517. }
  518. if (seg->node_count != 1)
  519. {
  520. seg->stripe_size = grub_lvm_getvalue (&p, "stripe_size = ");
  521. if (p == NULL)
  522. {
  523. #ifdef GRUB_UTIL
  524. grub_util_info ("unknown stripe_size");
  525. #endif
  526. goto lvs_segment_fail;
  527. }
  528. }
  529. seg->nodes = grub_calloc (seg->node_count,
  530. sizeof (*stripe));
  531. stripe = seg->nodes;
  532. p = grub_strstr (p, "stripes = [");
  533. if (p == NULL)
  534. {
  535. #ifdef GRUB_UTIL
  536. grub_util_info ("unknown stripes");
  537. #endif
  538. goto lvs_segment_fail2;
  539. }
  540. p += sizeof("stripes = [") - 1;
  541. for (j = 0; j < seg->node_count; j++)
  542. {
  543. p = grub_strchr (p, '"');
  544. if (p == NULL)
  545. goto lvs_segment_fail2;
  546. q = ++p;
  547. while (q < mda_end && *q != '"')
  548. q++;
  549. if (q == mda_end)
  550. goto lvs_segment_fail2;
  551. s = q - p;
  552. stripe->name = grub_malloc (s + 1);
  553. if (stripe->name == NULL)
  554. goto lvs_segment_fail2;
  555. grub_memcpy (stripe->name, p, s);
  556. stripe->name[s] = '\0';
  557. p = q + 1;
  558. stripe->start = grub_lvm_getvalue (&p, ",")
  559. * vg->extent_size;
  560. if (p == NULL)
  561. {
  562. grub_free (stripe->name);
  563. goto lvs_segment_fail2;
  564. }
  565. stripe++;
  566. }
  567. }
  568. else if (grub_memcmp (p, "mirror\"", sizeof ("mirror\"") - 1)
  569. == 0)
  570. {
  571. seg->type = GRUB_DISKFILTER_MIRROR;
  572. seg->node_count = grub_lvm_getvalue (&p, "mirror_count = ");
  573. if (p == NULL)
  574. {
  575. #ifdef GRUB_UTIL
  576. grub_util_info ("unknown mirror_count");
  577. #endif
  578. goto lvs_segment_fail;
  579. }
  580. seg->nodes = grub_zalloc (sizeof (seg->nodes[0])
  581. * seg->node_count);
  582. p = grub_strstr (p, "mirrors = [");
  583. if (p == NULL)
  584. {
  585. #ifdef GRUB_UTIL
  586. grub_util_info ("unknown mirrors");
  587. #endif
  588. goto lvs_segment_fail2;
  589. }
  590. p += sizeof("mirrors = [") - 1;
  591. for (j = 0; j < seg->node_count; j++)
  592. {
  593. char *lvname;
  594. p = grub_strchr (p, '"');
  595. if (p == NULL)
  596. goto lvs_segment_fail2;
  597. q = ++p;
  598. while (q < mda_end && *q != '"')
  599. q++;
  600. if (q == mda_end)
  601. goto lvs_segment_fail2;
  602. s = q - p;
  603. lvname = grub_malloc (s + 1);
  604. if (lvname == NULL)
  605. goto lvs_segment_fail2;
  606. grub_memcpy (lvname, p, s);
  607. lvname[s] = '\0';
  608. seg->nodes[j].name = lvname;
  609. p = q + 1;
  610. }
  611. /* Only first (original) is ok with in progress pvmove. */
  612. if (is_pvmove)
  613. seg->node_count = 1;
  614. }
  615. else if (grub_memcmp (p, "raid", sizeof ("raid") - 1) == 0
  616. && ((p[sizeof ("raid") - 1] >= '4'
  617. && p[sizeof ("raid") - 1] <= '6')
  618. || p[sizeof ("raid") - 1] == '1')
  619. && p[sizeof ("raidX") - 1] == '"')
  620. {
  621. switch (p[sizeof ("raid") - 1])
  622. {
  623. case '1':
  624. seg->type = GRUB_DISKFILTER_MIRROR;
  625. break;
  626. case '4':
  627. seg->type = GRUB_DISKFILTER_RAID4;
  628. seg->layout = GRUB_RAID_LAYOUT_LEFT_ASYMMETRIC;
  629. break;
  630. case '5':
  631. seg->type = GRUB_DISKFILTER_RAID5;
  632. seg->layout = GRUB_RAID_LAYOUT_LEFT_SYMMETRIC;
  633. break;
  634. case '6':
  635. seg->type = GRUB_DISKFILTER_RAID6;
  636. seg->layout = (GRUB_RAID_LAYOUT_RIGHT_ASYMMETRIC
  637. | GRUB_RAID_LAYOUT_MUL_FROM_POS);
  638. break;
  639. }
  640. seg->node_count = grub_lvm_getvalue (&p, "device_count = ");
  641. if (p == NULL)
  642. {
  643. #ifdef GRUB_UTIL
  644. grub_util_info ("unknown device_count");
  645. #endif
  646. goto lvs_segment_fail;
  647. }
  648. if (seg->type != GRUB_DISKFILTER_MIRROR)
  649. {
  650. seg->stripe_size = grub_lvm_getvalue (&p, "stripe_size = ");
  651. if (p == NULL)
  652. {
  653. #ifdef GRUB_UTIL
  654. grub_util_info ("unknown stripe_size");
  655. #endif
  656. goto lvs_segment_fail;
  657. }
  658. }
  659. seg->nodes = grub_zalloc (sizeof (seg->nodes[0])
  660. * seg->node_count);
  661. p = grub_strstr (p, "raids = [");
  662. if (p == NULL)
  663. {
  664. #ifdef GRUB_UTIL
  665. grub_util_info ("unknown raids");
  666. #endif
  667. goto lvs_segment_fail2;
  668. }
  669. p += sizeof("raids = [") - 1;
  670. for (j = 0; j < seg->node_count; j++)
  671. {
  672. char *lvname;
  673. p = grub_strchr (p, '"');
  674. p = p ? grub_strchr (p + 1, '"') : 0;
  675. p = p ? grub_strchr (p + 1, '"') : 0;
  676. if (p == NULL)
  677. goto lvs_segment_fail2;
  678. q = ++p;
  679. while (*q != '"')
  680. q++;
  681. s = q - p;
  682. lvname = grub_malloc (s + 1);
  683. if (lvname == NULL)
  684. goto lvs_segment_fail2;
  685. grub_memcpy (lvname, p, s);
  686. lvname[s] = '\0';
  687. seg->nodes[j].name = lvname;
  688. p = q + 1;
  689. }
  690. if (seg->type == GRUB_DISKFILTER_RAID4)
  691. {
  692. char *tmp;
  693. tmp = seg->nodes[0].name;
  694. grub_memmove (seg->nodes, seg->nodes + 1,
  695. sizeof (seg->nodes[0])
  696. * (seg->node_count - 1));
  697. seg->nodes[seg->node_count - 1].name = tmp;
  698. }
  699. }
  700. else if (grub_memcmp (p, "cache\"",
  701. sizeof ("cache\"") - 1) == 0)
  702. {
  703. struct cache_lv *cache = NULL;
  704. char *p2, *p3;
  705. grub_size_t sz;
  706. cache = grub_zalloc (sizeof (*cache));
  707. if (!cache)
  708. goto cache_lv_fail;
  709. cache->lv = grub_zalloc (sizeof (*cache->lv));
  710. if (!cache->lv)
  711. goto cache_lv_fail;
  712. grub_memcpy (cache->lv, lv, sizeof (*cache->lv));
  713. if (lv->fullname)
  714. {
  715. cache->lv->fullname = grub_strdup (lv->fullname);
  716. if (!cache->lv->fullname)
  717. goto cache_lv_fail;
  718. }
  719. if (lv->idname)
  720. {
  721. cache->lv->idname = grub_strdup (lv->idname);
  722. if (!cache->lv->idname)
  723. goto cache_lv_fail;
  724. }
  725. if (lv->name)
  726. {
  727. cache->lv->name = grub_strdup (lv->name);
  728. if (!cache->lv->name)
  729. goto cache_lv_fail;
  730. }
  731. skip_lv = 1;
  732. p2 = grub_strstr (p, "cache_pool = \"");
  733. if (!p2)
  734. goto cache_lv_fail;
  735. p2 = grub_strchr (p2, '"');
  736. if (!p2)
  737. goto cache_lv_fail;
  738. p3 = ++p2;
  739. if (p3 == mda_end)
  740. goto cache_lv_fail;
  741. p3 = grub_strchr (p3, '"');
  742. if (!p3)
  743. goto cache_lv_fail;
  744. sz = p3 - p2;
  745. cache->cache_pool = grub_malloc (sz + 1);
  746. if (!cache->cache_pool)
  747. goto cache_lv_fail;
  748. grub_memcpy (cache->cache_pool, p2, sz);
  749. cache->cache_pool[sz] = '\0';
  750. p2 = grub_strstr (p, "origin = \"");
  751. if (!p2)
  752. goto cache_lv_fail;
  753. p2 = grub_strchr (p2, '"');
  754. if (!p2)
  755. goto cache_lv_fail;
  756. p3 = ++p2;
  757. if (p3 == mda_end)
  758. goto cache_lv_fail;
  759. p3 = grub_strchr (p3, '"');
  760. if (!p3)
  761. goto cache_lv_fail;
  762. sz = p3 - p2;
  763. cache->origin = grub_malloc (sz + 1);
  764. if (!cache->origin)
  765. goto cache_lv_fail;
  766. grub_memcpy (cache->origin, p2, sz);
  767. cache->origin[sz] = '\0';
  768. cache->next = cache_lvs;
  769. cache_lvs = cache;
  770. break;
  771. cache_lv_fail:
  772. if (cache)
  773. {
  774. grub_free (cache->origin);
  775. grub_free (cache->cache_pool);
  776. if (cache->lv)
  777. {
  778. grub_free (cache->lv->fullname);
  779. grub_free (cache->lv->idname);
  780. grub_free (cache->lv->name);
  781. }
  782. grub_free (cache->lv);
  783. grub_free (cache);
  784. }
  785. grub_lvm_free_cache_lvs (cache_lvs);
  786. goto fail4;
  787. }
  788. else
  789. {
  790. #ifdef GRUB_UTIL
  791. char *p2;
  792. p2 = grub_strchr (p, '"');
  793. if (p2)
  794. *p2 = 0;
  795. grub_util_info ("unknown LVM type %s", p);
  796. if (p2)
  797. *p2 ='"';
  798. #endif
  799. /* Found a non-supported type, give up and move on. */
  800. skip_lv = 1;
  801. break;
  802. }
  803. seg++;
  804. continue;
  805. lvs_segment_fail2:
  806. grub_free (seg->nodes);
  807. lvs_segment_fail:
  808. goto fail4;
  809. }
  810. if (p != NULL)
  811. p = grub_strchr (p, '}');
  812. if (p == NULL)
  813. goto lvs_fail;
  814. p += 3;
  815. if (skip_lv)
  816. {
  817. grub_free (lv->name);
  818. grub_free (lv);
  819. continue;
  820. }
  821. lv->vg = vg;
  822. lv->next = vg->lvs;
  823. vg->lvs = lv;
  824. continue;
  825. lvs_fail:
  826. grub_free (lv->name);
  827. grub_free (lv);
  828. goto fail4;
  829. }
  830. }
  831. /* Match lvs. */
  832. {
  833. struct grub_diskfilter_lv *lv1;
  834. struct grub_diskfilter_lv *lv2;
  835. for (lv1 = vg->lvs; lv1; lv1 = lv1->next)
  836. for (i = 0; i < lv1->segment_count; i++)
  837. for (j = 0; j < lv1->segments[i].node_count; j++)
  838. {
  839. if (vg->pvs)
  840. for (pv = vg->pvs; pv; pv = pv->next)
  841. {
  842. if (! grub_strcmp (pv->name,
  843. lv1->segments[i].nodes[j].name))
  844. {
  845. lv1->segments[i].nodes[j].pv = pv;
  846. break;
  847. }
  848. }
  849. if (lv1->segments[i].nodes[j].pv == NULL)
  850. for (lv2 = vg->lvs; lv2; lv2 = lv2->next)
  851. {
  852. if (lv1 == lv2)
  853. continue;
  854. if (grub_strcmp (lv2->name,
  855. lv1->segments[i].nodes[j].name) == 0)
  856. lv1->segments[i].nodes[j].lv = lv2;
  857. }
  858. }
  859. }
  860. {
  861. struct cache_lv *cache;
  862. for (cache = cache_lvs; cache; cache = cache->next)
  863. {
  864. struct grub_diskfilter_lv *lv;
  865. for (lv = vg->lvs; lv; lv = lv->next)
  866. if (grub_strcmp (lv->name, cache->origin) == 0)
  867. break;
  868. if (lv)
  869. {
  870. cache->lv->segments = grub_calloc (lv->segment_count, sizeof (*lv->segments));
  871. if (!cache->lv->segments)
  872. {
  873. grub_lvm_free_cache_lvs (cache_lvs);
  874. goto fail4;
  875. }
  876. grub_memcpy (cache->lv->segments, lv->segments, lv->segment_count * sizeof (*lv->segments));
  877. for (i = 0; i < lv->segment_count; ++i)
  878. {
  879. struct grub_diskfilter_node *nodes = lv->segments[i].nodes;
  880. grub_size_t node_count = lv->segments[i].node_count;
  881. cache->lv->segments[i].nodes = grub_calloc (node_count, sizeof (*nodes));
  882. if (!cache->lv->segments[i].nodes)
  883. {
  884. for (j = 0; j < i; ++j)
  885. grub_free (cache->lv->segments[j].nodes);
  886. grub_free (cache->lv->segments);
  887. cache->lv->segments = NULL;
  888. grub_lvm_free_cache_lvs (cache_lvs);
  889. goto fail4;
  890. }
  891. grub_memcpy (cache->lv->segments[i].nodes, nodes, node_count * sizeof (*nodes));
  892. }
  893. if (cache->lv->segments)
  894. {
  895. cache->lv->segment_count = lv->segment_count;
  896. cache->lv->vg = vg;
  897. cache->lv->next = vg->lvs;
  898. vg->lvs = cache->lv;
  899. cache->lv = NULL;
  900. }
  901. }
  902. }
  903. }
  904. grub_lvm_free_cache_lvs (cache_lvs);
  905. if (grub_diskfilter_vg_register (vg))
  906. goto fail4;
  907. }
  908. else
  909. {
  910. grub_free (vgname);
  911. }
  912. id->uuid = grub_malloc (GRUB_LVM_ID_STRLEN);
  913. if (!id->uuid)
  914. goto fail4;
  915. grub_memcpy (id->uuid, pv_id, GRUB_LVM_ID_STRLEN);
  916. id->uuidlen = GRUB_LVM_ID_STRLEN;
  917. grub_free (metadatabuf);
  918. *start_sector = -1;
  919. return vg;
  920. /* Failure path. */
  921. fail4:
  922. grub_free (vg);
  923. fail3:
  924. grub_free (vgname);
  925. fail2:
  926. grub_free (metadatabuf);
  927. fail:
  928. return NULL;
  929. }
  930. static struct grub_diskfilter grub_lvm_dev = {
  931. .name = "lvm",
  932. .detect = grub_lvm_detect,
  933. .next = 0
  934. };
  935. GRUB_MOD_INIT (lvm)
  936. {
  937. grub_diskfilter_register_back (&grub_lvm_dev);
  938. }
  939. GRUB_MOD_FINI (lvm)
  940. {
  941. grub_diskfilter_unregister (&grub_lvm_dev);
  942. }