static int virStorageBackendZFSDeleteVol(virConnectPtr conn ATTRIBUTE_UNUSED, virStoragePoolObjPtr pool, virStorageVolDefPtr vol, unsigned int flags) { int ret = -1; virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool); virCommandPtr destroy_cmd = NULL; virCheckFlags(0, -1); destroy_cmd = virCommandNewArgList(ZFS, "destroy", NULL); virCommandAddArgFormat(destroy_cmd, "%s/%s", def->source.name, vol->name); if (virCommandRun(destroy_cmd, NULL) < 0) goto cleanup; ret = 0; cleanup: virCommandFree(destroy_cmd); return ret; }
static int virStorageBackendZFSBuildPool(virConnectPtr conn ATTRIBUTE_UNUSED, virStoragePoolObjPtr pool, unsigned int flags) { virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool); virCommandPtr cmd = NULL; size_t i; int ret = -1; virCheckFlags(0, -1); if (def->source.ndevice == 0) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("missing source devices")); return -1; } cmd = virCommandNewArgList(ZPOOL, "create", def->source.name, NULL); for (i = 0; i < def->source.ndevice; i++) virCommandAddArg(cmd, def->source.devices[i].path); if (virCommandRun(cmd, NULL) < 0) goto cleanup; ret = 0; cleanup: virCommandFree(cmd); return ret; }
static int virStorageBackendVzIsMounted(virStoragePoolObjPtr pool) { int ret = -1; virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool); FILE *mtab; struct mntent ent; char buf[1024]; VIR_AUTOFREE(char *) cluster = NULL; if (virAsprintf(&cluster, "vstorage://%s", def->source.name) < 0) return -1; if ((mtab = fopen(_PATH_MOUNTED, "r")) == NULL) { virReportSystemError(errno, _("cannot read mount list '%s'"), _PATH_MOUNTED); goto cleanup; } while ((getmntent_r(mtab, &ent, buf, sizeof(buf))) != NULL) { if (STREQ(ent.mnt_dir, def->target.path) && STREQ(ent.mnt_fsname, cluster)) { ret = 1; goto cleanup; } } ret = 0; cleanup: VIR_FORCE_FCLOSE(mtab); return ret; }
static int virStorageBackendZFSFindVols(virStoragePoolObjPtr pool, virStorageVolDefPtr vol) { virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool); virCommandPtr cmd = NULL; char *volumes_list = NULL; char **lines = NULL; size_t i; /** * $ zfs list -Hp -t volume -o name,volsize -r test * test/vol1 5368709120 * test/vol3 1073741824 * test/vol4 1572864000 * $ * * Arguments description: * -t volume -- we want to see only volumes * -o name,volsize -- limit output to name and volume size * -r -- we want to see all the childer of our pool */ cmd = virCommandNewArgList(ZFS, "list", "-Hp", "-t", "volume", "-r", "-o", "name,volsize,refreservation", def->source.name, NULL); virCommandSetOutputBuffer(cmd, &volumes_list); if (virCommandRun(cmd, NULL) < 0) goto cleanup; if (!(lines = virStringSplit(volumes_list, "\n", 0))) goto cleanup; for (i = 0; lines[i]; i++) { if (STREQ(lines[i], "")) continue; if (virStorageBackendZFSParseVol(pool, vol, lines[i]) < 0) continue; } cleanup: virCommandFree(cmd); virStringListFree(lines); VIR_FREE(volumes_list); return 0; }
static int virStorageBackendVzPoolStop(virStoragePoolObjPtr pool) { virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool); int rc; VIR_AUTOPTR(virCommand) cmd = NULL; /* Short-circuit if already unmounted */ if ((rc = virStorageBackendVzIsMounted(pool)) != 1) return rc; cmd = virCommandNewArgList(UMOUNT, def->target.path, NULL); return virCommandRun(cmd, NULL); }
static int virStorageBackendZFSCheckPool(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, bool *isActive) { virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool); char *devpath; if (virAsprintf(&devpath, "/dev/zvol/%s", def->source.name) < 0) return -1; *isActive = virFileIsDir(devpath); VIR_FREE(devpath); return 0; }
static int virStorageBackendZFSDeletePool(virConnectPtr conn ATTRIBUTE_UNUSED, virStoragePoolObjPtr pool, unsigned int flags) { virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool); virCommandPtr cmd = NULL; int ret = -1; virCheckFlags(0, -1); cmd = virCommandNewArgList(ZPOOL, "destroy", def->source.name, NULL); if (virCommandRun(cmd, NULL) < 0) goto cleanup; ret = 0; cleanup: virCommandFree(cmd); return ret; }
static int virStorageBackendVzPoolStart(virStoragePoolObjPtr pool) { virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool); VIR_AUTOFREE(char *) grp_name = NULL; VIR_AUTOFREE(char *) usr_name = NULL; VIR_AUTOFREE(char *) mode = NULL; VIR_AUTOPTR(virCommand) cmd = NULL; /* Check the permissions */ if (def->target.perms.mode == (mode_t)-1) def->target.perms.mode = VIR_STORAGE_DEFAULT_POOL_PERM_MODE; if (def->target.perms.uid == (uid_t)-1) def->target.perms.uid = geteuid(); if (def->target.perms.gid == (gid_t)-1) def->target.perms.gid = getegid(); /* Convert ids to names because vstorage uses names */ if (!(grp_name = virGetGroupName(def->target.perms.gid))) return -1; if (!(usr_name = virGetUserName(def->target.perms.uid))) return -1; if (virAsprintf(&mode, "%o", def->target.perms.mode) < 0) return -1; cmd = virCommandNewArgList(VSTORAGE_MOUNT, "-c", def->source.name, def->target.path, "-m", mode, "-g", grp_name, "-u", usr_name, NULL); return virCommandRun(cmd, NULL); }
static int virStorageBackendZFSCreateVol(virConnectPtr conn ATTRIBUTE_UNUSED, virStoragePoolObjPtr pool, virStorageVolDefPtr vol) { virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool); virCommandPtr cmd = NULL; int ret = -1; int volmode_needed = -1; if (vol->target.encryption != NULL) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("storage pool does not support encrypted " "volumes")); return -1; } vol->type = VIR_STORAGE_VOL_BLOCK; VIR_FREE(vol->target.path); if (virAsprintf(&vol->target.path, "%s/%s", def->target.path, vol->name) < 0) return -1; if (VIR_STRDUP(vol->key, vol->target.path) < 0) goto cleanup; volmode_needed = virStorageBackendZFSVolModeNeeded(); if (volmode_needed < 0) goto cleanup; /** * $ zfs create -o volmode=dev -V 10240K test/volname * $ zfs create -o volmode=dev -s -V 10240K test/volname * $ zfs create -o volmode=dev -s -o refreservation=1024K -V 10240K test/volname * * -o volmode=dev -- we want to get volumes exposed as cdev * devices. If we don't specify that zfs * will lookup vfs.zfs.vol.mode sysctl value * -s -- create a sparse volume * -o refreservation -- reserve the specified amount of space * -V -- tells to create a volume with the specified size */ cmd = virCommandNewArgList(ZFS, "create", NULL); if (volmode_needed) virCommandAddArgList(cmd, "-o", "volmode=dev", NULL); if (vol->target.capacity != vol->target.allocation) { virCommandAddArg(cmd, "-s"); if (vol->target.allocation > 0) { virCommandAddArg(cmd, "-o"); virCommandAddArgFormat(cmd, "refreservation=%lluK", VIR_DIV_UP(vol->target.allocation, 1024)); } vol->target.sparse = true; } virCommandAddArg(cmd, "-V"); virCommandAddArgFormat(cmd, "%lluK", VIR_DIV_UP(vol->target.capacity, 1024)); virCommandAddArgFormat(cmd, "%s/%s", def->source.name, vol->name); if (virCommandRun(cmd, NULL) < 0) goto cleanup; if (virStorageBackendZFSFindVols(pool, vol) < 0) goto cleanup; ret = 0; cleanup: virCommandFree(cmd); return ret; }
static int virStorageBackendZFSRefreshPool(virConnectPtr conn ATTRIBUTE_UNUSED, virStoragePoolObjPtr pool ATTRIBUTE_UNUSED) { virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool); virCommandPtr cmd = NULL; char *zpool_props = NULL; char **lines = NULL; char **tokens = NULL; size_t i; /** * $ zpool get -Hp health,size,free,allocated test * test health ONLINE - * test size 199715979264 - * test free 198899976704 - * test allocated 816002560 - * $ * * Here we just provide a list of properties we want to see */ cmd = virCommandNewArgList(ZPOOL, "get", "-Hp", "health,size,free,allocated", def->source.name, NULL); virCommandSetOutputBuffer(cmd, &zpool_props); if (virCommandRun(cmd, NULL) < 0) goto cleanup; if (!(lines = virStringSplit(zpool_props, "\n", 0))) goto cleanup; for (i = 0; lines[i]; i++) { size_t count; char *prop_name; if (STREQ(lines[i], "")) continue; virStringListFree(tokens); if (!(tokens = virStringSplitCount(lines[i], "\t", 0, &count))) goto cleanup; if (count != 4) continue; prop_name = tokens[1]; if (STREQ(prop_name, "free") || STREQ(prop_name, "size") || STREQ(prop_name, "allocated")) { unsigned long long value; if (virStrToLong_ull(tokens[2], NULL, 10, &value) < 0) goto cleanup; if (STREQ(prop_name, "free")) def->available = value; else if (STREQ(prop_name, "size")) def->capacity = value; else if (STREQ(prop_name, "allocated")) def->allocation = value; } } /* Obtain a list of volumes */ if (virStorageBackendZFSFindVols(pool, NULL) < 0) goto cleanup; cleanup: virCommandFree(cmd); virStringListFree(lines); virStringListFree(tokens); VIR_FREE(zpool_props); return 0; }
static int virStorageBackendZFSParseVol(virStoragePoolObjPtr pool, virStorageVolDefPtr vol, const char *volume_string) { int ret = -1; char **tokens; size_t count; char **name_tokens = NULL; char *vol_name; bool is_new_vol = false; virStorageVolDefPtr volume = NULL; virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool); if (!(tokens = virStringSplitCount(volume_string, "\t", 0, &count))) return -1; if (count != 3) goto cleanup; if (!(name_tokens = virStringSplit(tokens[0], "/", 2))) goto cleanup; vol_name = name_tokens[1]; if (vol == NULL) volume = virStorageVolDefFindByName(pool, vol_name); else volume = vol; if (volume == NULL) { if (VIR_ALLOC(volume) < 0) goto cleanup; is_new_vol = true; volume->type = VIR_STORAGE_VOL_BLOCK; if (VIR_STRDUP(volume->name, vol_name) < 0) goto cleanup; } if (!volume->key && VIR_STRDUP(volume->key, tokens[0]) < 0) goto cleanup; if (volume->target.path == NULL) { if (virAsprintf(&volume->target.path, "%s/%s", def->target.path, volume->name) < 0) goto cleanup; } if (virStrToLong_ull(tokens[1], NULL, 10, &volume->target.capacity) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("malformed volsize reported")); goto cleanup; } if (virStrToLong_ull(tokens[2], NULL, 10, &volume->target.allocation) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("malformed refreservation reported")); goto cleanup; } if (volume->target.allocation < volume->target.capacity) volume->target.sparse = true; if (is_new_vol && virStoragePoolObjAddVol(pool, volume) < 0) goto cleanup; volume = NULL; ret = 0; cleanup: virStringListFree(tokens); virStringListFree(name_tokens); if (is_new_vol) virStorageVolDefFree(volume); return ret; }