提交 a5efb319 编写于 作者: D Daniel P. Berrange

Add support for hotplug/unplug of host storage devices in LXC

Wire up the attach/detach device drivers in LXC to support the
hotplug/unplug of host storage devices.
Signed-off-by: NDaniel P. Berrange <berrange@redhat.com>
上级 ed77abc5
...@@ -3478,6 +3478,119 @@ cleanup: ...@@ -3478,6 +3478,119 @@ cleanup:
} }
static int
lxcDomainAttachDeviceHostdevStorageLive(virLXCDriverPtr driver,
virDomainObjPtr vm,
virDomainDeviceDefPtr dev)
{
virLXCDomainObjPrivatePtr priv = vm->privateData;
virDomainHostdevDefPtr def = dev->data.hostdev;
virCgroupPtr group = NULL;
int ret = -1;
char *dst = NULL;
char *vroot = NULL;
struct stat sb;
bool created = false;
mode_t mode = 0;
if (!def->source.caps.u.storage.block) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Missing storage block path"));
goto cleanup;
}
if (virDomainHostdevFind(vm->def, def, NULL) >= 0) {
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
_("host device already exists"));
return -1;
}
if (stat(def->source.caps.u.storage.block, &sb) < 0) {
virReportSystemError(errno,
_("Unable to access %s"),
def->source.caps.u.storage.block);
goto cleanup;
}
if (!S_ISBLK(sb.st_mode)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Hostdev source %s must be a block device"),
def->source.caps.u.storage.block);
goto cleanup;
}
if (virAsprintf(&vroot, "/proc/%llu/root",
(unsigned long long)priv->initpid) < 0) {
virReportOOMError();
goto cleanup;
}
if (virAsprintf(&dst, "%s/%s",
vroot,
def->source.caps.u.storage.block) < 0) {
virReportOOMError();
goto cleanup;
}
if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs+1) < 0) {
virReportOOMError();
goto cleanup;
}
mode = 0700 | S_IFBLK;
VIR_DEBUG("Creating dev %s (%d,%d)",
def->source.caps.u.storage.block,
major(sb.st_rdev), minor(sb.st_rdev));
if (mknod(dst, mode, sb.st_rdev) < 0) {
virReportSystemError(errno,
_("Unable to create device %s"),
dst);
goto cleanup;
}
created = true;
if (virSecurityManagerSetHostdevLabel(driver->securityManager,
vm->def, def, vroot) < 0)
goto cleanup;
if (!lxcCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
_("devices cgroup isn't mounted"));
goto cleanup;
}
if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot find cgroup for domain %s"), vm->def->name);
goto cleanup;
}
if (virCgroupAllowDevicePath(group, def->source.caps.u.storage.block,
VIR_CGROUP_DEVICE_RW |
VIR_CGROUP_DEVICE_MKNOD) != 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot allow device %s for domain %s"),
def->source.caps.u.storage.block, vm->def->name);
goto cleanup;
}
vm->def->hostdevs[vm->def->nhostdevs++] = def;
ret = 0;
cleanup:
virDomainAuditHostdev(vm, def, "attach", ret == 0);
if (group)
virCgroupFree(&group);
if (dst && created && ret < 0)
unlink(dst);
VIR_FREE(dst);
VIR_FREE(vroot);
return ret;
}
static int static int
lxcDomainAttachDeviceHostdevSubsysLive(virLXCDriverPtr driver, lxcDomainAttachDeviceHostdevSubsysLive(virLXCDriverPtr driver,
virDomainObjPtr vm, virDomainObjPtr vm,
...@@ -3496,6 +3609,24 @@ lxcDomainAttachDeviceHostdevSubsysLive(virLXCDriverPtr driver, ...@@ -3496,6 +3609,24 @@ lxcDomainAttachDeviceHostdevSubsysLive(virLXCDriverPtr driver,
} }
static int
lxcDomainAttachDeviceHostdevCapsLive(virLXCDriverPtr driver,
virDomainObjPtr vm,
virDomainDeviceDefPtr dev)
{
switch (dev->data.hostdev->source.caps.type) {
case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE:
return lxcDomainAttachDeviceHostdevStorageLive(driver, vm, dev);
default:
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Unsupported host device type %s"),
virDomainHostdevCapsTypeToString(dev->data.hostdev->source.caps.type));
return -1;
}
}
static int static int
lxcDomainAttachDeviceHostdevLive(virLXCDriverPtr driver, lxcDomainAttachDeviceHostdevLive(virLXCDriverPtr driver,
virDomainObjPtr vm, virDomainObjPtr vm,
...@@ -3513,6 +3644,9 @@ lxcDomainAttachDeviceHostdevLive(virLXCDriverPtr driver, ...@@ -3513,6 +3644,9 @@ lxcDomainAttachDeviceHostdevLive(virLXCDriverPtr driver,
case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS: case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS:
return lxcDomainAttachDeviceHostdevSubsysLive(driver, vm, dev); return lxcDomainAttachDeviceHostdevSubsysLive(driver, vm, dev);
case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
return lxcDomainAttachDeviceHostdevCapsLive(driver, vm, dev);
default: default:
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Unsupported host device mode %s"), _("Unsupported host device mode %s"),
...@@ -3778,6 +3912,78 @@ cleanup: ...@@ -3778,6 +3912,78 @@ cleanup:
return ret; return ret;
} }
static int
lxcDomainDetachDeviceHostdevStorageLive(virLXCDriverPtr driver,
virDomainObjPtr vm,
virDomainDeviceDefPtr dev)
{
virLXCDomainObjPrivatePtr priv = vm->privateData;
virDomainHostdevDefPtr def = NULL;
virCgroupPtr group = NULL;
int i, ret = -1;
char *dst = NULL;
if (!priv->initpid) {
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
_("Cannot attach disk until init PID is known"));
goto cleanup;
}
if ((i = virDomainHostdevFind(vm->def,
dev->data.hostdev,
&def)) < 0) {
virReportError(VIR_ERR_OPERATION_FAILED,
_("hostdev %s not found"),
dev->data.hostdev->source.caps.u.storage.block);
goto cleanup;
}
if (virAsprintf(&dst, "/proc/%llu/root/%s",
(unsigned long long)priv->initpid,
def->source.caps.u.storage.block) < 0) {
virReportOOMError();
goto cleanup;
}
if (!lxcCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
_("devices cgroup isn't mounted"));
goto cleanup;
}
if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot find cgroup for domain %s"), vm->def->name);
goto cleanup;
}
VIR_DEBUG("Unlinking %s", dst);
if (unlink(dst) < 0 && errno != ENOENT) {
virDomainAuditHostdev(vm, def, "detach", false);
virReportSystemError(errno,
_("Unable to remove device %s"), dst);
goto cleanup;
}
virDomainAuditHostdev(vm, def, "detach", true);
if (virCgroupDenyDevicePath(group, def->source.caps.u.storage.block, VIR_CGROUP_DEVICE_RWM) != 0)
VIR_WARN("cannot deny device %s for domain %s",
def->source.caps.u.storage.block, vm->def->name);
virDomainHostdevRemove(vm->def, i);
virDomainHostdevDefFree(def);
ret = 0;
cleanup:
VIR_FREE(dst);
if (group)
virCgroupFree(&group);
return ret;
}
static int static int
lxcDomainDetachDeviceHostdevSubsysLive(virLXCDriverPtr driver, lxcDomainDetachDeviceHostdevSubsysLive(virLXCDriverPtr driver,
virDomainObjPtr vm, virDomainObjPtr vm,
...@@ -3796,6 +4002,24 @@ lxcDomainDetachDeviceHostdevSubsysLive(virLXCDriverPtr driver, ...@@ -3796,6 +4002,24 @@ lxcDomainDetachDeviceHostdevSubsysLive(virLXCDriverPtr driver,
} }
static int
lxcDomainDetachDeviceHostdevCapsLive(virLXCDriverPtr driver,
virDomainObjPtr vm,
virDomainDeviceDefPtr dev)
{
switch (dev->data.hostdev->source.caps.type) {
case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE:
return lxcDomainDetachDeviceHostdevStorageLive(driver, vm, dev);
default:
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Unsupported host device type %s"),
virDomainHostdevCapsTypeToString(dev->data.hostdev->source.caps.type));
return -1;
}
}
static int static int
lxcDomainDetachDeviceHostdevLive(virLXCDriverPtr driver, lxcDomainDetachDeviceHostdevLive(virLXCDriverPtr driver,
virDomainObjPtr vm, virDomainObjPtr vm,
...@@ -3813,6 +4037,9 @@ lxcDomainDetachDeviceHostdevLive(virLXCDriverPtr driver, ...@@ -3813,6 +4037,9 @@ lxcDomainDetachDeviceHostdevLive(virLXCDriverPtr driver,
case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS: case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS:
return lxcDomainDetachDeviceHostdevSubsysLive(driver, vm, dev); return lxcDomainDetachDeviceHostdevSubsysLive(driver, vm, dev);
case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
return lxcDomainDetachDeviceHostdevCapsLive(driver, vm, dev);
default: default:
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Unsupported host device mode %s"), _("Unsupported host device mode %s"),
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册