qemuDomainGetPreservedMounts: Fetch list of /dev/* mounts dynamically

With my namespace patches, we are spawning qemu in its own
namespace so that we can manage /dev entries ourselves. However,
some filesystems mounted under /dev needs to be preserved in
order to be shared with the parent namespace (e.g. /dev/pts).
Currently, the list of mount points to preserve is hardcoded
which ain't right - on some systems there might be less or more
items under real /dev that on our list. The solution is to parse
/proc/mounts and fetch the list from there.

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
This commit is contained in:
Michal Privoznik 2017-01-05 14:19:04 +01:00
parent 486fd7f700
commit e08ee7cd34

View File

@ -99,14 +99,8 @@ VIR_ENUM_IMPL(qemuDomainNamespace, QEMU_DOMAIN_NS_LAST,
); );
static struct { #define PROC_MOUNTS "/proc/mounts"
const char *path; #define DEVPREFIX "/dev/"
const char *suffix;
} devPreserveMounts[] = {
{"/dev/pts", "devpts"},
{"/dev/shm", "devshm"},
{"/dev/mqueue", "mqueue"},
};
struct _qemuDomainLogContext { struct _qemuDomainLogContext {
@ -200,33 +194,73 @@ qemuDomainEnableNamespace(virDomainObjPtr vm,
} }
/**
* qemuDomainGetPreservedMounts:
*
* Process list of mounted filesystems and:
* a) save all FSs mounted under /dev to @devPath
* b) generate backup path for all the entries in a)
*
* Any of the return pointers can be NULL.
*
* Returns 0 on success, -1 otherwise (with error reported)
*/
static int static int
qemuDomainGetPreservedMounts(virQEMUDriverPtr driver, qemuDomainGetPreservedMounts(virQEMUDriverPtr driver,
virDomainObjPtr vm, virDomainObjPtr vm,
char ***devMountsPath, char ***devPath,
size_t *ndevMountsPath) char ***devSavePath,
size_t *ndevPath)
{ {
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
char **paths; char **paths = NULL, **mounts = NULL;
size_t i; size_t i, nmounts;
if (VIR_ALLOC_N(paths, ARRAY_CARDINALITY(devPreserveMounts)) < 0) if (virFileGetMountSubtree(PROC_MOUNTS, "/dev",
&mounts, &nmounts) < 0)
goto error; goto error;
for (i = 0; i < ARRAY_CARDINALITY(devPreserveMounts); i++) { if (!nmounts) {
if (ndevPath)
*ndevPath = 0;
return 0;
}
/* Okay, this is crazy. But virFileGetMountSubtree() fetched us all the
* mount points under /dev including /dev itself. Fortunately, the paths
* are sorted based on their length so we skip the first one (/dev) as it
* is handled differently anyway. */
VIR_DELETE_ELEMENT(mounts, 0, nmounts);
if (VIR_ALLOC_N(paths, nmounts) < 0)
goto error;
for (i = 0; i < nmounts; i++) {
if (virAsprintf(&paths[i], "%s/%s.%s", if (virAsprintf(&paths[i], "%s/%s.%s",
cfg->stateDir, vm->def->name, cfg->stateDir, vm->def->name,
devPreserveMounts[i].suffix) < 0) mounts[i] + strlen(DEVPREFIX)) < 0)
goto error; goto error;
} }
*devMountsPath = paths; if (devPath)
*ndevMountsPath = ARRAY_CARDINALITY(devPreserveMounts); *devPath = mounts;
else
virStringListFreeCount(mounts, nmounts);
if (devSavePath)
*devSavePath = paths;
else
virStringListFreeCount(paths, nmounts);
if (ndevPath)
*ndevPath = nmounts;
virObjectUnref(cfg); virObjectUnref(cfg);
return 0; return 0;
error: error:
virStringListFreeCount(paths, ARRAY_CARDINALITY(devPreserveMounts)); virStringListFreeCount(mounts, nmounts);
virStringListFreeCount(paths, nmounts);
virObjectUnref(cfg); virObjectUnref(cfg);
return -1; return -1;
} }
@ -6917,8 +6951,6 @@ qemuDomainGetHostdevPath(virDomainHostdevDefPtr dev,
} }
#define DEVPREFIX "/dev/"
#if defined(__linux__) #if defined(__linux__)
static int static int
qemuDomainCreateDevice(const char *device, qemuDomainCreateDevice(const char *device,
@ -7304,7 +7336,7 @@ qemuDomainBuildNamespace(virQEMUDriverPtr driver,
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
const unsigned long mount_flags = MS_MOVE; const unsigned long mount_flags = MS_MOVE;
char *devPath = NULL; char *devPath = NULL;
char **devMountsPath = NULL; char **devMountsPath = NULL, **devMountsSavePath = NULL;
size_t ndevMountsPath = 0, i; size_t ndevMountsPath = 0, i;
int ret = -1; int ret = -1;
@ -7318,7 +7350,8 @@ qemuDomainBuildNamespace(virQEMUDriverPtr driver,
goto cleanup; goto cleanup;
if (qemuDomainGetPreservedMounts(driver, vm, if (qemuDomainGetPreservedMounts(driver, vm,
&devMountsPath, &ndevMountsPath) < 0) &devMountsPath, &devMountsSavePath,
&ndevMountsPath) < 0)
goto cleanup; goto cleanup;
if (qemuDomainSetupDev(driver, vm, devPath) < 0) if (qemuDomainSetupDev(driver, vm, devPath) < 0)
@ -7326,11 +7359,11 @@ qemuDomainBuildNamespace(virQEMUDriverPtr driver,
/* Save some mount points because we want to share them with the host */ /* Save some mount points because we want to share them with the host */
for (i = 0; i < ndevMountsPath; i++) { for (i = 0; i < ndevMountsPath; i++) {
if (mount(devPreserveMounts[i].path, devMountsPath[i], if (mount(devMountsPath[i], devMountsSavePath[i],
NULL, mount_flags, NULL) < 0) { NULL, mount_flags, NULL) < 0) {
virReportSystemError(errno, virReportSystemError(errno,
_("Unable to move %s mount"), _("Unable to move %s mount"),
devPreserveMounts[i].path); devMountsPath[i]);
goto cleanup; goto cleanup;
} }
} }
@ -7361,18 +7394,18 @@ qemuDomainBuildNamespace(virQEMUDriverPtr driver,
} }
for (i = 0; i < ndevMountsPath; i++) { for (i = 0; i < ndevMountsPath; i++) {
if (virFileMakePath(devPreserveMounts[i].path) < 0) { if (virFileMakePath(devMountsPath[i]) < 0) {
virReportSystemError(errno, _("Cannot create %s"), virReportSystemError(errno, _("Cannot create %s"),
devPreserveMounts[i].path); devMountsPath[i]);
goto cleanup; goto cleanup;
} }
if (mount(devMountsPath[i], devPreserveMounts[i].path, if (mount(devMountsSavePath[i], devMountsPath[i],
NULL, mount_flags, NULL) < 0) { NULL, mount_flags, NULL) < 0) {
virReportSystemError(errno, virReportSystemError(errno,
_("Failed to mount %s on %s"), _("Failed to mount %s on %s"),
devMountsPath[i], devMountsSavePath[i],
devPreserveMounts[i].path); devMountsPath[i]);
goto cleanup; goto cleanup;
} }
} }
@ -7382,6 +7415,7 @@ qemuDomainBuildNamespace(virQEMUDriverPtr driver,
virObjectUnref(cfg); virObjectUnref(cfg);
VIR_FREE(devPath); VIR_FREE(devPath);
virStringListFreeCount(devMountsPath, ndevMountsPath); virStringListFreeCount(devMountsPath, ndevMountsPath);
virStringListFreeCount(devMountsSavePath, ndevMountsPath);
return ret; return ret;
} }
@ -7393,8 +7427,8 @@ qemuDomainCreateNamespace(virQEMUDriverPtr driver,
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
int ret = -1; int ret = -1;
char *devPath = NULL; char *devPath = NULL;
char **devMountsPath = NULL; char **devMountsSavePath = NULL;
size_t ndevMountsPath = 0, i; size_t ndevMountsSavePath = 0, i;
if (!virBitmapIsBitSet(cfg->namespaces, QEMU_DOMAIN_NS_MOUNT) || if (!virBitmapIsBitSet(cfg->namespaces, QEMU_DOMAIN_NS_MOUNT) ||
!virQEMUDriverIsPrivileged(driver)) { !virQEMUDriverIsPrivileged(driver)) {
@ -7407,7 +7441,8 @@ qemuDomainCreateNamespace(virQEMUDriverPtr driver,
goto cleanup; goto cleanup;
if (qemuDomainGetPreservedMounts(driver, vm, if (qemuDomainGetPreservedMounts(driver, vm,
&devMountsPath, &ndevMountsPath) < 0) NULL, &devMountsSavePath,
&ndevMountsSavePath) < 0)
goto cleanup; goto cleanup;
if (virFileMakePath(devPath) < 0) { if (virFileMakePath(devPath) < 0) {
@ -7417,11 +7452,11 @@ qemuDomainCreateNamespace(virQEMUDriverPtr driver,
goto cleanup; goto cleanup;
} }
for (i = 0; i < ndevMountsPath; i++) { for (i = 0; i < ndevMountsSavePath; i++) {
if (virFileMakePath(devMountsPath[i]) < 0) { if (virFileMakePath(devMountsSavePath[i]) < 0) {
virReportSystemError(errno, virReportSystemError(errno,
_("Failed to create %s"), _("Failed to create %s"),
devMountsPath[i]); devMountsSavePath[i]);
goto cleanup; goto cleanup;
} }
} }
@ -7434,10 +7469,10 @@ qemuDomainCreateNamespace(virQEMUDriverPtr driver,
if (ret < 0) { if (ret < 0) {
if (devPath) if (devPath)
unlink(devPath); unlink(devPath);
for (i = 0; i < ndevMountsPath; i++) for (i = 0; i < ndevMountsSavePath; i++)
unlink(devMountsPath[i]); unlink(devMountsSavePath[i]);
} }
virStringListFreeCount(devMountsPath, ndevMountsPath); virStringListFreeCount(devMountsSavePath, ndevMountsSavePath);
VIR_FREE(devPath); VIR_FREE(devPath);
virObjectUnref(cfg); virObjectUnref(cfg);
return ret; return ret;
@ -7472,8 +7507,8 @@ qemuDomainDeleteNamespace(virQEMUDriverPtr driver,
{ {
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
char *devPath = NULL; char *devPath = NULL;
char **devMountsPath = NULL; char **devMountsSavePath = NULL;
size_t ndevMountsPath = 0, i; size_t ndevMountsSavePath = 0, i;
if (!qemuDomainNamespaceEnabled(vm, QEMU_DOMAIN_NS_MOUNT)) if (!qemuDomainNamespaceEnabled(vm, QEMU_DOMAIN_NS_MOUNT))
@ -7484,7 +7519,8 @@ qemuDomainDeleteNamespace(virQEMUDriverPtr driver,
goto cleanup; goto cleanup;
if (qemuDomainGetPreservedMounts(driver, vm, if (qemuDomainGetPreservedMounts(driver, vm,
&devMountsPath, &ndevMountsPath) < 0) NULL, &devMountsSavePath,
&ndevMountsSavePath) < 0)
goto cleanup; goto cleanup;
if (rmdir(devPath) < 0) { if (rmdir(devPath) < 0) {
@ -7494,17 +7530,17 @@ qemuDomainDeleteNamespace(virQEMUDriverPtr driver,
/* Bet effort. Fall through. */ /* Bet effort. Fall through. */
} }
for (i = 0; i < ndevMountsPath; i++) { for (i = 0; i < ndevMountsSavePath; i++) {
if (rmdir(devMountsPath[i]) < 0) { if (rmdir(devMountsSavePath[i]) < 0) {
virReportSystemError(errno, virReportSystemError(errno,
_("Unable to remove %s"), _("Unable to remove %s"),
devMountsPath[i]); devMountsSavePath[i]);
/* Bet effort. Fall through. */ /* Bet effort. Fall through. */
} }
} }
cleanup: cleanup:
virObjectUnref(cfg); virObjectUnref(cfg);
virStringListFreeCount(devMountsPath, ndevMountsPath); virStringListFreeCount(devMountsSavePath, ndevMountsSavePath);
VIR_FREE(devPath); VIR_FREE(devPath);
} }