diff --git a/configure.ac b/configure.ac index 59f78ff7c3..884e0e453f 100644 --- a/configure.ac +++ b/configure.ac @@ -416,6 +416,8 @@ AC_PATH_PROG([UDEVSETTLE], [udevsettle], [], [/sbin:/usr/sbin:/usr/local/sbin:$PATH]) AC_PATH_PROG([MODPROBE], [modprobe], [modprobe], [/sbin:/usr/sbin:/usr/local/sbin:$PATH]) +AC_PATH_PROG([RMMOD], [rmmod], [rmmod], + [/sbin:/usr/sbin:/usr/local/sbin:$PATH]) AC_PATH_PROG([OVSVSCTL], [ovs-vsctl], [ovs-vsctl], [/sbin:/usr/sbin:/usr/local/sbin:$PATH]) AC_PATH_PROG([SCRUB], [scrub], [scrub], @@ -444,6 +446,10 @@ if test -n "$MODPROBE"; then AC_DEFINE_UNQUOTED([MODPROBE],["$MODPROBE"], [Location or name of the modprobe program]) fi +if test -n "$RMMOD"; then + AC_DEFINE_UNQUOTED([RMMOD],["$RMMOD"], + [Location or name of the rmmod program]) +fi AC_DEFINE_UNQUOTED([SCRUB],["$SCRUB"], [Location or name of the scrub program (for wiping algorithms)]) diff --git a/src/Makefile.am b/src/Makefile.am index ac2d1d9fe5..3f8d22f5e1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -125,6 +125,7 @@ UTIL_SOURCES = \ util/virnetdevvportprofile.h util/virnetdevvportprofile.c \ util/virnetlink.c util/virnetlink.h \ util/virnodesuspend.c util/virnodesuspend.h \ + util/virkmod.c util/virkmod.h \ util/virnuma.c util/virnuma.h \ util/virobject.c util/virobject.h \ util/virpci.c util/virpci.h \ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 1a8d08852f..c5a7637cf7 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1383,6 +1383,13 @@ virKeyFileLoadFile; virKeyFileNew; +# util/virkmod.h +virKModConfig; +virKModIsBlacklisted; +virKModLoad; +virKModUnload; + + # util/virlockspace.h virLockSpaceAcquireResource; virLockSpaceCreateResource; diff --git a/src/util/virkmod.c b/src/util/virkmod.c new file mode 100644 index 0000000000..73cb3c7686 --- /dev/null +++ b/src/util/virkmod.c @@ -0,0 +1,181 @@ +/* + * virkmod.c: helper APIs for managing kernel modules + * + * Copyright (C) 2014 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 + * . + * + */ + +#include +#include "viralloc.h" +#include "virkmod.h" +#include "vircommand.h" +#include "virstring.h" + +static int +doModprobe(const char *opts, const char *module, char **outbuf, char **errbuf) +{ + int ret = -1; + virCommandPtr cmd = NULL; + + cmd = virCommandNew(MODPROBE); + if (opts) + virCommandAddArg(cmd, opts); + if (module) + virCommandAddArg(cmd, module); + if (outbuf) + virCommandSetOutputBuffer(cmd, outbuf); + if (errbuf) + virCommandSetErrorBuffer(cmd, errbuf); + + if (virCommandRun(cmd, NULL) < 0) + goto cleanup; + + ret = 0; + +cleanup: + virCommandFree(cmd); + return ret; +} + +static int +doRmmod(const char *module, char **errbuf) +{ + int ret = -1; + virCommandPtr cmd = NULL; + + cmd = virCommandNewArgList(RMMOD, module, NULL); + virCommandSetErrorBuffer(cmd, errbuf); + + if (virCommandRun(cmd, NULL) < 0) + goto cleanup; + + ret = 0; + +cleanup: + virCommandFree(cmd); + return ret; +} + +/** + * virKModConfig: + * + * Get the current kernel module configuration + * + * Returns NULL on failure or a pointer to the output which + * must be VIR_FREE()'d by the caller + */ +char * +virKModConfig(void) +{ + char *outbuf = NULL; + + if (doModprobe("-c", NULL, &outbuf, NULL) < 0) + return NULL; + + return outbuf; +} + + +/** + * virKModLoad: + * @module: Name of the module to load + * @useBlacklist: True if honoring blacklist + * + * Attempts to load a kernel module + * + * returns NULL in case of success and the error buffer output from the + * virCommandRun() on failure. The returned buffer must be VIR_FREE() + * by the caller + */ +char * +virKModLoad(const char *module, bool useBlacklist) +{ + char *errbuf = NULL; + + if (doModprobe(useBlacklist ? "-b" : NULL, module, NULL, &errbuf) < 0) + return errbuf; + + VIR_FREE(errbuf); + return NULL; +} + + +/** + * virKModUnload: + * @module: Name of the module to unload + * + * Remove or unload a module. + * + * NB: Do not use 'modprobe -r' here as that code will recursively + * unload any modules that were dependancies of the one being removed + * even if things still require them. e.g. it'll see the 'bridge' + * module has refcount of 0 and remove it, even if there are bridges + * created on the host + * + * returns NULL in case of success and the error buffer output from the + * virCommandRun() on failure. The returned buffer must be VIR_FREE() + * by the caller + */ +char * +virKModUnload(const char *module) +{ + char *errbuf = NULL; + + if (doRmmod(module, &errbuf) < 0) + return errbuf; + + VIR_FREE(errbuf); + return NULL; +} + + +/** + * virKModIsBlacklisted: + * @module: Name of the module to check for on the blacklist + * + * Search the output of the configuration data for the module being + * blacklisted. + * + * returns true when found blacklisted, false otherwise. + */ +bool +virKModIsBlacklisted(const char *module) +{ + bool retval = false; + size_t i; + char *drvblklst = NULL; + char *outbuf = NULL; + + if (virAsprintfQuiet(&drvblklst, "blacklist %s\n", module) < 0) + goto cleanup; + + /* modprobe will convert all '-' into '_', so we need to as well */ + for (i = 0; i < drvblklst[i]; i++) + if (drvblklst[i] == '-') + drvblklst[i] = '_'; + + if (doModprobe("-c", NULL, &outbuf, NULL) < 0) + goto cleanup; + + if (strstr(outbuf, drvblklst)) + retval = true; + +cleanup: + VIR_FREE(drvblklst); + VIR_FREE(outbuf); + return retval; +} diff --git a/src/util/virkmod.h b/src/util/virkmod.h new file mode 100644 index 0000000000..608f1b884e --- /dev/null +++ b/src/util/virkmod.h @@ -0,0 +1,34 @@ +/* + * virkmod.h: helper APIs for managing kernel modprobe + * + * Copyright (C) 2014 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 + * . + * + */ + +#ifndef __VIR_KMOD_H__ +# define __VIR_KMOD_H__ + +# include "internal.h" + +char *virKModConfig(void); +char *virKModLoad(const char *, bool) + ATTRIBUTE_NONNULL(1); +char *virKModUnload(const char *) + ATTRIBUTE_NONNULL(1); +bool virKModIsBlacklisted(const char *) + ATTRIBUTE_NONNULL(1); +#endif /* __VIR_KMOD_H__ */