On Tue, Apr 03, 2018 at 11:03:25 +0200, Michal Privoznik wrote: > This helper fetches dependencies for given device mapper target. > > At the same time, we need to provide a dummy log function because > by default libdevmapper prints out error messages to stderr which > we need to suppress. > > Signed-off-by: Michal Privoznik <mprivozn@xxxxxxxxxx> > --- > src/libvirt_private.syms | 4 + > src/util/Makefile.inc.am | 2 + > src/util/virdevmapper.c | 200 +++++++++++++++++++++++++++++++++++++++++++++++ > src/util/virdevmapper.h | 31 ++++++++ > 4 files changed, 237 insertions(+) > create mode 100644 src/util/virdevmapper.c > create mode 100644 src/util/virdevmapper.h [...] > diff --git a/src/util/virdevmapper.c b/src/util/virdevmapper.c > new file mode 100644 > index 0000000000..9491848f48 > --- /dev/null > +++ b/src/util/virdevmapper.c > @@ -0,0 +1,200 @@ > +/* > + * virdevmapper.c: Functions for handling devmapper device mapper > + * > + * Copyright (C) 2018 Red Hat, Inc. > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2.1 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library. If not, see > + * <http://www.gnu.org/licenses/>. > + * > + * Authors: > + * Michal Privoznik <mprivozn@xxxxxxxxxx> > + */ > + > +#include <config.h> [...] > +static int > +virDevMapperGetTargetsImpl(const char *path, > + char ***devPaths_ret, > + unsigned int ttl) > +{ > + struct dm_task *dmt = NULL; > + struct dm_deps *deps; > + struct dm_info info; > + char **devPaths = NULL; > + char **recursiveDevPaths = NULL; > + size_t i; > + int ret = -1; > + > + *devPaths_ret = NULL; > + > + if (virDevMapperInitialize() < 0) > + return ret; > + > + if (!ttl) { if (ttl == 0) > + errno = ELOOP; > + return ret; > + } > + > + if (!(dmt = dm_task_create(DM_DEVICE_DEPS))) > + return ret; > + > + if (!dm_task_set_name(dmt, path)) { > + if (errno == ENOENT) { > + /* It's okay, @path is not managed by devmapper => > + * not a devmapper device. */ > + ret = 0; > + } > + goto cleanup; > + } > + > + dm_task_no_open_count(dmt); > + > + if (!dm_task_run(dmt)) > + goto cleanup; > + > + if (!dm_task_get_info(dmt, &info)) > + goto cleanup; > + > + if (!info.exists) { > + ret = 0; > + goto cleanup; > + } > + > + if (!(deps = dm_task_get_deps(dmt))) > + goto cleanup; > + > + if (VIR_ALLOC_N_QUIET(devPaths, deps->count + 1) < 0) > + goto cleanup; > + > + for (i = 0; i < deps->count; i++) { > + if (virAsprintfQuiet(&devPaths[i], "/dev/block/%u:%u", > + major(deps->device[i]), > + minor(deps->device[i])) < 0) > + goto cleanup; > + } > + > + recursiveDevPaths = NULL; > + for (i = 0; i < deps->count; i++) { > + char **tmpPaths; > + > + if (virDevMapperGetTargetsImpl(devPaths[i], &tmpPaths, ttl - 1) < 0) > + goto cleanup; > + > + if (tmpPaths && > + virStringListMerge(&recursiveDevPaths, &tmpPaths) < 0) { So these report libvirt errors, but don't mess them up. And only in case of OOM, so this is fine. > + virStringListFree(tmpPaths); > + goto cleanup; > + } > + } > + > + if (virStringListMerge(&devPaths, &recursiveDevPaths) < 0) > + goto cleanup; > + > + VIR_STEAL_PTR(*devPaths_ret, devPaths); > + ret = 0; > + cleanup: > + virStringListFree(recursiveDevPaths); > + virStringListFree(devPaths); > + dm_task_destroy(dmt); > + return ret; > +} > + > + > +/** > + * virDevMapperGetTargets: > + * @path: devmapper target > + * @devPaths: returned string list of devices > + * > + * For given @path figure out its targets, and store them in > + * @devPaths array. Note, @devPaths is a string list so it's NULL > + * terminated. > + * > + * If @path is not a devmapper device, @devPaths is set to NULL and > + * success is returned. > + * > + * If @path consists of yet another devmapper targets these are > + * consulted recursively. > + * > + * If we don't have permissions to talk to kernel, -1 is returned > + * and errno is set to EBADF. > + * > + * Returns 0 on success, > + * -1 otherwise (with errno set, no libvirt error is > + * reported) > + */ > +int > +virDevMapperGetTargets(const char *path, > + char ***devPaths) > +{ > + const unsigned int ttl = 4; So even trivial setups (dmcrypt + LVM) would exhaust half of your limit for the device mapper block devices, and would still recurse one more level to check the backing block device. I think we need some more headroom here. I'd go with 16 or 32. > + > + /* Arbitrary limit on recursion level. A devmapper target can > + * consist of devices or yet another targets. If that's the > + * case, we have to stop recursion somewhere. My dice chose > + * four. */ Drop the last sentence of this comment. > + > + return virDevMapperGetTargetsImpl(path, devPaths, ttl); > +} > + ACK if you fix the condition syntax, raise the recursion level significantly, and tweak the comment.
Attachment:
signature.asc
Description: PGP signature
-- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list