PageRenderTime 57ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/libvirt-0.9.11/src/storage/storage_backend_logical.c

#
C | 829 lines | 597 code | 134 blank | 98 comment | 103 complexity | 14bafc05a46408d922dca7b593cfd3ce MD5 | raw file
Possible License(s): LGPL-2.1
  1. /*
  2. * storage_backend_logical.c: storage backend for logical volume handling
  3. *
  4. * Copyright (C) 2007-2009, 2011 Red Hat, Inc.
  5. * Copyright (C) 2007-2008 Daniel P. Berrange
  6. *
  7. * This library is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * This library is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with this library; if not, write to the Free Software
  19. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  20. *
  21. * Author: Daniel P. Berrange <berrange@redhat.com>
  22. */
  23. #include <config.h>
  24. #include <sys/wait.h>
  25. #include <sys/stat.h>
  26. #include <stdio.h>
  27. #include <regex.h>
  28. #include <string.h>
  29. #include <unistd.h>
  30. #include <fcntl.h>
  31. #include "virterror_internal.h"
  32. #include "storage_backend_logical.h"
  33. #include "storage_conf.h"
  34. #include "command.h"
  35. #include "memory.h"
  36. #include "logging.h"
  37. #include "virfile.h"
  38. #define VIR_FROM_THIS VIR_FROM_STORAGE
  39. #define PV_BLANK_SECTOR_SIZE 512
  40. static int
  41. virStorageBackendLogicalSetActive(virStoragePoolObjPtr pool,
  42. int on)
  43. {
  44. const char *cmdargv[4];
  45. cmdargv[0] = VGCHANGE;
  46. cmdargv[1] = on ? "-aly" : "-aln";
  47. cmdargv[2] = pool->def->source.name;
  48. cmdargv[3] = NULL;
  49. if (virRun(cmdargv, NULL) < 0)
  50. return -1;
  51. return 0;
  52. }
  53. #define VIR_STORAGE_VOL_LOGICAL_SEGTYPE_STRIPED "striped"
  54. static int
  55. virStorageBackendLogicalMakeVol(virStoragePoolObjPtr pool,
  56. char **const groups,
  57. void *data)
  58. {
  59. virStorageVolDefPtr vol = NULL;
  60. bool is_new_vol = false;
  61. unsigned long long offset, size, length;
  62. const char *regex_unit = "(\\S+)\\((\\S+)\\)";
  63. char *regex = NULL;
  64. regex_t *reg = NULL;
  65. regmatch_t *vars = NULL;
  66. char *p = NULL;
  67. int i, err, nextents, nvars, ret = -1;
  68. /* See if we're only looking for a specific volume */
  69. if (data != NULL) {
  70. vol = data;
  71. if (STRNEQ(vol->name, groups[0]))
  72. return 0;
  73. }
  74. /* Or filling in more data on an existing volume */
  75. if (vol == NULL)
  76. vol = virStorageVolDefFindByName(pool, groups[0]);
  77. /* Or a completely new volume */
  78. if (vol == NULL) {
  79. if (VIR_ALLOC(vol) < 0) {
  80. virReportOOMError();
  81. return -1;
  82. }
  83. is_new_vol = true;
  84. vol->type = VIR_STORAGE_VOL_BLOCK;
  85. if ((vol->name = strdup(groups[0])) == NULL) {
  86. virReportOOMError();
  87. goto cleanup;
  88. }
  89. if (VIR_REALLOC_N(pool->volumes.objs,
  90. pool->volumes.count + 1)) {
  91. virReportOOMError();
  92. goto cleanup;
  93. }
  94. }
  95. if (vol->target.path == NULL) {
  96. if (virAsprintf(&vol->target.path, "%s/%s",
  97. pool->def->target.path, vol->name) < 0) {
  98. virReportOOMError();
  99. goto cleanup;
  100. }
  101. }
  102. /* Skips the backingStore of lv created with "--virtualsize",
  103. * its original device "/dev/$vgname/$lvname_vorigin" is
  104. * just for lvm internal use, one should never use it.
  105. *
  106. * (lvs outputs "[$lvname_vorigin] for field "origin" if the
  107. * lv is created with "--virtualsize").
  108. */
  109. if (groups[1] && !STREQ(groups[1], "") && (groups[1][0] != '[')) {
  110. if (virAsprintf(&vol->backingStore.path, "%s/%s",
  111. pool->def->target.path, groups[1]) < 0) {
  112. virReportOOMError();
  113. goto cleanup;
  114. }
  115. vol->backingStore.format = VIR_STORAGE_POOL_LOGICAL_LVM2;
  116. }
  117. if (vol->key == NULL &&
  118. (vol->key = strdup(groups[2])) == NULL) {
  119. virReportOOMError();
  120. goto cleanup;
  121. }
  122. if (virStorageBackendUpdateVolInfo(vol, 1) < 0)
  123. goto cleanup;
  124. nextents = 1;
  125. if (STREQ(groups[4], VIR_STORAGE_VOL_LOGICAL_SEGTYPE_STRIPED)) {
  126. if (virStrToLong_i(groups[5], NULL, 10, &nextents) < 0) {
  127. virStorageReportError(VIR_ERR_INTERNAL_ERROR, "%s",
  128. _("malformed volume extent stripes value"));
  129. goto cleanup;
  130. }
  131. }
  132. /* Finally fill in extents information */
  133. if (VIR_REALLOC_N(vol->source.extents,
  134. vol->source.nextent + nextents) < 0) {
  135. virReportOOMError();
  136. goto cleanup;
  137. }
  138. if (virStrToLong_ull(groups[6], NULL, 10, &length) < 0) {
  139. virStorageReportError(VIR_ERR_INTERNAL_ERROR,
  140. "%s", _("malformed volume extent length value"));
  141. goto cleanup;
  142. }
  143. if (virStrToLong_ull(groups[7], NULL, 10, &size) < 0) {
  144. virStorageReportError(VIR_ERR_INTERNAL_ERROR,
  145. "%s", _("malformed volume extent size value"));
  146. goto cleanup;
  147. }
  148. /* Now parse the "devices" field separately */
  149. regex = strdup(regex_unit);
  150. for (i = 1; i < nextents; i++) {
  151. if (VIR_REALLOC_N(regex, strlen(regex) + strlen(regex_unit) + 2) < 0) {
  152. virReportOOMError();
  153. goto cleanup;
  154. }
  155. /* "," is the separator of "devices" field */
  156. strcat(regex, ",");
  157. strncat(regex, regex_unit, strlen(regex_unit));
  158. }
  159. if (VIR_ALLOC(reg) < 0) {
  160. virReportOOMError();
  161. goto cleanup;
  162. }
  163. /* Each extent has a "path:offset" pair, and vars[0] will
  164. * be the whole matched string.
  165. */
  166. nvars = (nextents * 2) + 1;
  167. if (VIR_ALLOC_N(vars, nvars) < 0) {
  168. virReportOOMError();
  169. goto cleanup;
  170. }
  171. err = regcomp(reg, regex, REG_EXTENDED);
  172. if (err != 0) {
  173. char error[100];
  174. regerror(err, reg, error, sizeof(error));
  175. virStorageReportError(VIR_ERR_INTERNAL_ERROR,
  176. _("Failed to compile regex %s"),
  177. error);
  178. goto cleanup;
  179. }
  180. if (regexec(reg, groups[3], nvars, vars, 0) != 0) {
  181. virStorageReportError(VIR_ERR_INTERNAL_ERROR, "%s",
  182. _("malformed volume extent devices value"));
  183. goto cleanup;
  184. }
  185. p = groups[3];
  186. /* vars[0] is skipped */
  187. for (i = 0; i < nextents; i++) {
  188. int j, len;
  189. const char *offset_str = NULL;
  190. j = (i * 2) + 1;
  191. len = vars[j].rm_eo - vars[j].rm_so;
  192. p[vars[j].rm_eo] = '\0';
  193. if ((vol->source.extents[vol->source.nextent].path =
  194. strndup(p + vars[j].rm_so, len)) == NULL) {
  195. virReportOOMError();
  196. goto cleanup;
  197. }
  198. len = vars[j + 1].rm_eo - vars[j + 1].rm_so;
  199. if (!(offset_str = strndup(p + vars[j + 1].rm_so, len))) {
  200. virReportOOMError();
  201. goto cleanup;
  202. }
  203. if (virStrToLong_ull(offset_str, NULL, 10, &offset) < 0) {
  204. virStorageReportError(VIR_ERR_INTERNAL_ERROR, "%s",
  205. _("malformed volume extent offset value"));
  206. VIR_FREE(offset_str);
  207. goto cleanup;
  208. }
  209. VIR_FREE(offset_str);
  210. vol->source.extents[vol->source.nextent].start = offset * size;
  211. vol->source.extents[vol->source.nextent].end = (offset * size) + length;
  212. vol->source.nextent++;
  213. }
  214. if (is_new_vol)
  215. pool->volumes.objs[pool->volumes.count++] = vol;
  216. ret = 0;
  217. cleanup:
  218. VIR_FREE(regex);
  219. VIR_FREE(reg);
  220. VIR_FREE(vars);
  221. if (is_new_vol && (ret == -1))
  222. virStorageVolDefFree(vol);
  223. return ret;
  224. }
  225. static int
  226. virStorageBackendLogicalFindLVs(virStoragePoolObjPtr pool,
  227. virStorageVolDefPtr vol)
  228. {
  229. /*
  230. * # lvs --separator , --noheadings --units b --unbuffered --nosuffix --options "lv_name,origin,uuid,devices,seg_size,vg_extent_size" VGNAME
  231. * RootLV,,06UgP5-2rhb-w3Bo-3mdR-WeoL-pytO-SAa2ky,/dev/hda2(0),5234491392,33554432
  232. * SwapLV,,oHviCK-8Ik0-paqS-V20c-nkhY-Bm1e-zgzU0M,/dev/hda2(156),1040187392,33554432
  233. * Test2,,3pg3he-mQsA-5Sui-h0i6-HNmc-Cz7W-QSndcR,/dev/hda2(219),1073741824,33554432
  234. * Test3,,UB5hFw-kmlm-LSoX-EI1t-ioVd-h7GL-M0W8Ht,/dev/hda2(251),2181038080,33554432
  235. * Test3,Test2,UB5hFw-kmlm-LSoX-EI1t-ioVd-h7GL-M0W8Ht,/dev/hda2(187),1040187392,33554432
  236. *
  237. * Pull out name, origin, & uuid, device, device extent start #, segment size, extent size.
  238. *
  239. * NB can be multiple rows per volume if they have many extents
  240. *
  241. * NB lvs from some distros (e.g. SLES10 SP2) outputs trailing "," on each line
  242. *
  243. * NB Encrypted logical volumes can print ':' in their name, so it is
  244. * not a suitable separator (rhbz 470693).
  245. * NB "devices" field has multiple device paths and "," if the volume is
  246. * striped, so "," is not a suitable separator either (rhbz 727474).
  247. */
  248. const char *regexes[] = {
  249. "^\\s*(\\S+)#(\\S*)#(\\S+)#(\\S+)#(\\S+)#([0-9]+)#(\\S+)#([0-9]+)#?\\s*$"
  250. };
  251. int vars[] = {
  252. 8
  253. };
  254. const char *prog[] = {
  255. LVS, "--separator", "#", "--noheadings", "--units", "b",
  256. "--unbuffered", "--nosuffix", "--options",
  257. "lv_name,origin,uuid,devices,segtype,stripes,seg_size,vg_extent_size",
  258. pool->def->source.name, NULL
  259. };
  260. if (virStorageBackendRunProgRegex(pool,
  261. prog,
  262. 1,
  263. regexes,
  264. vars,
  265. virStorageBackendLogicalMakeVol,
  266. vol, "lvs") < 0) {
  267. return -1;
  268. }
  269. return 0;
  270. }
  271. static int
  272. virStorageBackendLogicalRefreshPoolFunc(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
  273. char **const groups,
  274. void *data ATTRIBUTE_UNUSED)
  275. {
  276. if (virStrToLong_ull(groups[0], NULL, 10, &pool->def->capacity) < 0)
  277. return -1;
  278. if (virStrToLong_ull(groups[1], NULL, 10, &pool->def->available) < 0)
  279. return -1;
  280. pool->def->allocation = pool->def->capacity - pool->def->available;
  281. return 0;
  282. }
  283. static int
  284. virStorageBackendLogicalFindPoolSourcesFunc(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
  285. char **const groups,
  286. void *data)
  287. {
  288. virStoragePoolSourceListPtr sourceList = data;
  289. char *pvname = NULL;
  290. char *vgname = NULL;
  291. int i;
  292. virStoragePoolSourceDevicePtr dev;
  293. virStoragePoolSource *thisSource;
  294. pvname = strdup(groups[0]);
  295. vgname = strdup(groups[1]);
  296. if (pvname == NULL || vgname == NULL) {
  297. virReportOOMError();
  298. goto err_no_memory;
  299. }
  300. thisSource = NULL;
  301. for (i = 0 ; i < sourceList->nsources; i++) {
  302. if (STREQ(sourceList->sources[i].name, vgname)) {
  303. thisSource = &sourceList->sources[i];
  304. break;
  305. }
  306. }
  307. if (thisSource == NULL) {
  308. if (!(thisSource = virStoragePoolSourceListNewSource(sourceList)))
  309. goto err_no_memory;
  310. thisSource->name = vgname;
  311. }
  312. else
  313. VIR_FREE(vgname);
  314. if (VIR_REALLOC_N(thisSource->devices, thisSource->ndevice + 1) != 0) {
  315. virReportOOMError();
  316. goto err_no_memory;
  317. }
  318. dev = &thisSource->devices[thisSource->ndevice];
  319. thisSource->ndevice++;
  320. thisSource->format = VIR_STORAGE_POOL_LOGICAL_LVM2;
  321. memset(dev, 0, sizeof(*dev));
  322. dev->path = pvname;
  323. return 0;
  324. err_no_memory:
  325. VIR_FREE(pvname);
  326. VIR_FREE(vgname);
  327. return -1;
  328. }
  329. static char *
  330. virStorageBackendLogicalFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSED,
  331. const char *srcSpec ATTRIBUTE_UNUSED,
  332. unsigned int flags)
  333. {
  334. /*
  335. * # pvs --noheadings -o pv_name,vg_name
  336. * /dev/sdb
  337. * /dev/sdc VolGroup00
  338. */
  339. const char *regexes[] = {
  340. "^\\s*(\\S+)\\s+(\\S+)\\s*$"
  341. };
  342. int vars[] = {
  343. 2
  344. };
  345. const char *const prog[] = { PVS, "--noheadings", "-o", "pv_name,vg_name", NULL };
  346. const char *const scanprog[] = { VGSCAN, NULL };
  347. char *retval = NULL;
  348. virStoragePoolSourceList sourceList;
  349. int i;
  350. virCheckFlags(0, NULL);
  351. /*
  352. * NOTE: ignoring errors here; this is just to "touch" any logical volumes
  353. * that might be hanging around, so if this fails for some reason, the
  354. * worst that happens is that scanning doesn't pick everything up
  355. */
  356. if (virRun(scanprog, NULL) < 0) {
  357. VIR_WARN("Failure when running vgscan to refresh physical volumes");
  358. }
  359. memset(&sourceList, 0, sizeof(sourceList));
  360. sourceList.type = VIR_STORAGE_POOL_LOGICAL;
  361. if (virStorageBackendRunProgRegex(NULL, prog, 1, regexes, vars,
  362. virStorageBackendLogicalFindPoolSourcesFunc,
  363. &sourceList, "pvs") < 0)
  364. return NULL;
  365. retval = virStoragePoolSourceListFormat(&sourceList);
  366. if (retval == NULL) {
  367. virStorageReportError(VIR_ERR_INTERNAL_ERROR, "%s",
  368. _("failed to get source from sourceList"));
  369. goto cleanup;
  370. }
  371. cleanup:
  372. for (i = 0; i < sourceList.nsources; i++)
  373. virStoragePoolSourceClear(&sourceList.sources[i]);
  374. VIR_FREE(sourceList.sources);
  375. return retval;
  376. }
  377. static int
  378. virStorageBackendLogicalCheckPool(virConnectPtr conn ATTRIBUTE_UNUSED,
  379. virStoragePoolObjPtr pool,
  380. bool *isActive)
  381. {
  382. char *path;
  383. *isActive = false;
  384. if (virAsprintf(&path, "/dev/%s", pool->def->source.name) < 0) {
  385. virReportOOMError();
  386. return -1;
  387. }
  388. if (access(path, F_OK) == 0)
  389. *isActive = true;
  390. VIR_FREE(path);
  391. return 0;
  392. }
  393. static int
  394. virStorageBackendLogicalStartPool(virConnectPtr conn ATTRIBUTE_UNUSED,
  395. virStoragePoolObjPtr pool)
  396. {
  397. if (virStorageBackendLogicalSetActive(pool, 1) < 0)
  398. return -1;
  399. return 0;
  400. }
  401. static int
  402. virStorageBackendLogicalBuildPool(virConnectPtr conn ATTRIBUTE_UNUSED,
  403. virStoragePoolObjPtr pool,
  404. unsigned int flags)
  405. {
  406. const char **vgargv;
  407. const char *pvargv[3];
  408. int n = 0, i, fd;
  409. char zeros[PV_BLANK_SECTOR_SIZE];
  410. virCheckFlags(0, -1);
  411. memset(zeros, 0, sizeof(zeros));
  412. if (VIR_ALLOC_N(vgargv, 3 + pool->def->source.ndevice) < 0) {
  413. virReportOOMError();
  414. return -1;
  415. }
  416. vgargv[n++] = VGCREATE;
  417. vgargv[n++] = pool->def->source.name;
  418. pvargv[0] = PVCREATE;
  419. pvargv[2] = NULL;
  420. for (i = 0 ; i < pool->def->source.ndevice ; i++) {
  421. /*
  422. * LVM requires that the first sector is blanked if using
  423. * a whole disk as a PV. So we just blank them out regardless
  424. * rather than trying to figure out if we're a disk or partition
  425. */
  426. if ((fd = open(pool->def->source.devices[i].path, O_WRONLY)) < 0) {
  427. virReportSystemError(errno,
  428. _("cannot open device '%s'"),
  429. pool->def->source.devices[i].path);
  430. goto cleanup;
  431. }
  432. if (safewrite(fd, zeros, sizeof(zeros)) < 0) {
  433. virReportSystemError(errno,
  434. _("cannot clear device header of '%s'"),
  435. pool->def->source.devices[i].path);
  436. VIR_FORCE_CLOSE(fd);
  437. goto cleanup;
  438. }
  439. if (fsync(fd) < 0) {
  440. virReportSystemError(errno,
  441. _("cannot flush header of device'%s'"),
  442. pool->def->source.devices[i].path);
  443. VIR_FORCE_CLOSE(fd);
  444. goto cleanup;
  445. }
  446. if (VIR_CLOSE(fd) < 0) {
  447. virReportSystemError(errno,
  448. _("cannot close device '%s'"),
  449. pool->def->source.devices[i].path);
  450. goto cleanup;
  451. }
  452. /*
  453. * Initialize the physical volume because vgcreate is not
  454. * clever enough todo this for us :-(
  455. */
  456. vgargv[n++] = pool->def->source.devices[i].path;
  457. pvargv[1] = pool->def->source.devices[i].path;
  458. if (virRun(pvargv, NULL) < 0)
  459. goto cleanup;
  460. }
  461. vgargv[n] = NULL;
  462. /* Now create the volume group itself */
  463. if (virRun(vgargv, NULL) < 0)
  464. goto cleanup;
  465. VIR_FREE(vgargv);
  466. return 0;
  467. cleanup:
  468. VIR_FREE(vgargv);
  469. return -1;
  470. }
  471. static int
  472. virStorageBackendLogicalRefreshPool(virConnectPtr conn ATTRIBUTE_UNUSED,
  473. virStoragePoolObjPtr pool)
  474. {
  475. /*
  476. * # vgs --separator : --noheadings --units b --unbuffered --nosuffix --options "vg_size,vg_free" VGNAME
  477. * 10603200512:4328521728
  478. *
  479. * Pull out size & free
  480. *
  481. * NB vgs from some distros (e.g. SLES10 SP2) outputs trailing ":" on each line
  482. */
  483. const char *regexes[] = {
  484. "^\\s*(\\S+):([0-9]+):?\\s*$"
  485. };
  486. int vars[] = {
  487. 2
  488. };
  489. const char *prog[] = {
  490. VGS, "--separator", ":", "--noheadings", "--units", "b", "--unbuffered",
  491. "--nosuffix", "--options", "vg_size,vg_free",
  492. pool->def->source.name, NULL
  493. };
  494. virFileWaitForDevices();
  495. /* Get list of all logical volumes */
  496. if (virStorageBackendLogicalFindLVs(pool, NULL) < 0) {
  497. virStoragePoolObjClearVols(pool);
  498. return -1;
  499. }
  500. /* Now get basic volgrp metadata */
  501. if (virStorageBackendRunProgRegex(pool,
  502. prog,
  503. 1,
  504. regexes,
  505. vars,
  506. virStorageBackendLogicalRefreshPoolFunc,
  507. NULL, "vgs") < 0) {
  508. virStoragePoolObjClearVols(pool);
  509. return -1;
  510. }
  511. return 0;
  512. }
  513. /*
  514. * This is actually relatively safe; if you happen to try to "stop" the
  515. * pool that your / is on, for instance, you will get failure like:
  516. * "Can't deactivate volume group "VolGroup00" with 3 open logical volume(s)"
  517. */
  518. static int
  519. virStorageBackendLogicalStopPool(virConnectPtr conn ATTRIBUTE_UNUSED,
  520. virStoragePoolObjPtr pool)
  521. {
  522. if (virStorageBackendLogicalSetActive(pool, 0) < 0)
  523. return -1;
  524. return 0;
  525. }
  526. static int
  527. virStorageBackendLogicalDeletePool(virConnectPtr conn ATTRIBUTE_UNUSED,
  528. virStoragePoolObjPtr pool,
  529. unsigned int flags)
  530. {
  531. const char *cmdargv[] = {
  532. VGREMOVE, "-f", pool->def->source.name, NULL
  533. };
  534. const char *pvargv[3];
  535. int i, error;
  536. virCheckFlags(0, -1);
  537. /* first remove the volume group */
  538. if (virRun(cmdargv, NULL) < 0)
  539. return -1;
  540. /* now remove the pv devices and clear them out */
  541. error = 0;
  542. pvargv[0] = PVREMOVE;
  543. pvargv[2] = NULL;
  544. for (i = 0 ; i < pool->def->source.ndevice ; i++) {
  545. pvargv[1] = pool->def->source.devices[i].path;
  546. if (virRun(pvargv, NULL) < 0) {
  547. error = -1;
  548. break;
  549. }
  550. }
  551. return error;
  552. }
  553. static int
  554. virStorageBackendLogicalDeleteVol(virConnectPtr conn,
  555. virStoragePoolObjPtr pool,
  556. virStorageVolDefPtr vol,
  557. unsigned int flags);
  558. static int
  559. virStorageBackendLogicalCreateVol(virConnectPtr conn,
  560. virStoragePoolObjPtr pool,
  561. virStorageVolDefPtr vol)
  562. {
  563. int fdret, fd = -1;
  564. char size[100];
  565. const char *cmdargvnew[] = {
  566. LVCREATE, "--name", vol->name, "-L", size,
  567. pool->def->target.path, NULL
  568. };
  569. const char *cmdargvsnap[] = {
  570. LVCREATE, "--name", vol->name, "-L", size,
  571. "-s", vol->backingStore.path, NULL
  572. };
  573. const char **cmdargv = cmdargvnew;
  574. if (vol->target.encryption != NULL) {
  575. virStorageReportError(VIR_ERR_CONFIG_UNSUPPORTED,
  576. "%s", _("storage pool does not support encrypted "
  577. "volumes"));
  578. return -1;
  579. }
  580. if (vol->backingStore.path) {
  581. cmdargv = cmdargvsnap;
  582. }
  583. snprintf(size, sizeof(size)-1, "%lluK", VIR_DIV_UP(vol->capacity, 1024));
  584. size[sizeof(size)-1] = '\0';
  585. vol->type = VIR_STORAGE_VOL_BLOCK;
  586. if (vol->target.path != NULL) {
  587. /* A target path passed to CreateVol has no meaning */
  588. VIR_FREE(vol->target.path);
  589. }
  590. if (virAsprintf(&vol->target.path, "%s/%s",
  591. pool->def->target.path,
  592. vol->name) == -1) {
  593. virReportOOMError();
  594. return -1;
  595. }
  596. if (virRun(cmdargv, NULL) < 0)
  597. return -1;
  598. if ((fdret = virStorageBackendVolOpen(vol->target.path)) < 0)
  599. goto cleanup;
  600. fd = fdret;
  601. /* We can only chown/grp if root */
  602. if (getuid() == 0) {
  603. if (fchown(fd, vol->target.perms.uid, vol->target.perms.gid) < 0) {
  604. virReportSystemError(errno,
  605. _("cannot set file owner '%s'"),
  606. vol->target.path);
  607. goto cleanup;
  608. }
  609. }
  610. if (fchmod(fd, vol->target.perms.mode) < 0) {
  611. virReportSystemError(errno,
  612. _("cannot set file mode '%s'"),
  613. vol->target.path);
  614. goto cleanup;
  615. }
  616. if (VIR_CLOSE(fd) < 0) {
  617. virReportSystemError(errno,
  618. _("cannot close file '%s'"),
  619. vol->target.path);
  620. goto cleanup;
  621. }
  622. fd = -1;
  623. /* Fill in data about this new vol */
  624. if (virStorageBackendLogicalFindLVs(pool, vol) < 0) {
  625. virReportSystemError(errno,
  626. _("cannot find newly created volume '%s'"),
  627. vol->target.path);
  628. goto cleanup;
  629. }
  630. return 0;
  631. cleanup:
  632. VIR_FORCE_CLOSE(fd);
  633. virStorageBackendLogicalDeleteVol(conn, pool, vol, 0);
  634. return -1;
  635. }
  636. static int
  637. virStorageBackendLogicalBuildVolFrom(virConnectPtr conn,
  638. virStoragePoolObjPtr pool,
  639. virStorageVolDefPtr vol,
  640. virStorageVolDefPtr inputvol,
  641. unsigned int flags)
  642. {
  643. virStorageBackendBuildVolFrom build_func;
  644. build_func = virStorageBackendGetBuildVolFromFunction(vol, inputvol);
  645. if (!build_func)
  646. return -1;
  647. return build_func(conn, pool, vol, inputvol, flags);
  648. }
  649. static int
  650. virStorageBackendLogicalDeleteVol(virConnectPtr conn ATTRIBUTE_UNUSED,
  651. virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
  652. virStorageVolDefPtr vol,
  653. unsigned int flags)
  654. {
  655. int ret = -1;
  656. virCommandPtr lvchange_cmd = NULL;
  657. virCommandPtr lvremove_cmd = NULL;
  658. virCheckFlags(0, -1);
  659. virFileWaitForDevices();
  660. lvchange_cmd = virCommandNewArgList(LVCHANGE,
  661. "-aln",
  662. vol->target.path,
  663. NULL);
  664. lvremove_cmd = virCommandNewArgList(LVREMOVE,
  665. "-f",
  666. vol->target.path,
  667. NULL);
  668. if (virCommandRun(lvremove_cmd, NULL) < 0) {
  669. if (virCommandRun(lvchange_cmd, NULL) < 0) {
  670. goto cleanup;
  671. } else {
  672. if (virCommandRun(lvremove_cmd, NULL) < 0)
  673. goto cleanup;
  674. }
  675. }
  676. ret = 0;
  677. cleanup:
  678. virCommandFree(lvchange_cmd);
  679. virCommandFree(lvremove_cmd);
  680. return ret;
  681. }
  682. virStorageBackend virStorageBackendLogical = {
  683. .type = VIR_STORAGE_POOL_LOGICAL,
  684. .findPoolSources = virStorageBackendLogicalFindPoolSources,
  685. .checkPool = virStorageBackendLogicalCheckPool,
  686. .startPool = virStorageBackendLogicalStartPool,
  687. .buildPool = virStorageBackendLogicalBuildPool,
  688. .refreshPool = virStorageBackendLogicalRefreshPool,
  689. .stopPool = virStorageBackendLogicalStopPool,
  690. .deletePool = virStorageBackendLogicalDeletePool,
  691. .buildVol = NULL,
  692. .buildVolFrom = virStorageBackendLogicalBuildVolFrom,
  693. .createVol = virStorageBackendLogicalCreateVol,
  694. .deleteVol = virStorageBackendLogicalDeleteVol,
  695. };