[libvirt] [RFC PATCH] Prevent defining a domain has disk used by other domain

$subject + "If the disk is shared and readonly." If the disk is not shared or readonly, the later started domain will relabel the disk, thus the first domain will lose the permission to write to the disk and be corrupt. -- I'm not sure if it's the design to allow multiple domains use same disk not shared and readonly. So this patch just gives a demo of the implementation (it skips the checking of nbd disk, and only changes qemu driver), to see whether if the pricinple is right or not. --- src/conf/domain_conf.c | 34 ++++++++++++++++++++++++++++++++++ src/conf/domain_conf.h | 2 ++ src/libvirt_private.syms | 1 + src/qemu/qemu_driver.c | 24 ++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 0 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 7463d7c..b64450b 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -655,6 +655,40 @@ virDomainObjPtr virDomainFindByName(const virDomainObjListPtr doms, return obj; } +static int +virDomainObjListSearchDiskPath(const void *payload, + const void *name ATTRIBUTE_UNUSED, + const void *data) +{ + virDomainObjPtr obj = (virDomainObjPtr)payload; + int i; + int want = 0; + const char *path = NULL; + + path = (const char *)data; + + virDomainObjLock(obj); + for (i = 0; obj->def->ndisks; i++) { + if (STREQ(obj->def->disks[i]->src, path)) { + want = 1; + break; + } + } + virDomainObjUnlock(obj); + + return want; +} + +virDomainObjPtr +virDomainFindByDiskPath(const virDomainObjListPtr doms, + const char *path) +{ + virDomainObjPtr obj = NULL; + obj = virHashSearch(doms->objs, virDomainObjListSearchDiskPath, path); + if (obj) + virDomainObjLock(obj); + return obj; +} bool virDomainObjTaint(virDomainObjPtr obj, enum virDomainTaintFlags taint) diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 371f270..d7d42dd 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1549,6 +1549,8 @@ virDomainObjPtr virDomainFindByUUID(const virDomainObjListPtr doms, const unsigned char *uuid); virDomainObjPtr virDomainFindByName(const virDomainObjListPtr doms, const char *name); +virDomainObjPtr virDomainFindByDiskPath(const virDomainObjListPtr doms, + const char *path); bool virDomainObjTaint(virDomainObjPtr obj, enum virDomainTaintFlags taint); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 8235ea1..c33cb2d 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -302,6 +302,7 @@ virDomainFSTypeToString; virDomainFindByID; virDomainFindByName; virDomainFindByUUID; +virDomainFindByDiskPath; virDomainGetRootFilesystem; virDomainGraphicsAuthConnectedTypeFromString; virDomainGraphicsAuthConnectedTypeToString; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 0d0bea2..a448a0b 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -4796,6 +4796,7 @@ static virDomainPtr qemudDomainDefine(virConnectPtr conn, const char *xml) { virDomainPtr dom = NULL; virDomainEventPtr event = NULL; int dupVM; + int i; qemuDriverLock(driver); if (!(def = virDomainDefParseString(driver->caps, xml, @@ -4809,6 +4810,29 @@ static virDomainPtr qemudDomainDefine(virConnectPtr conn, const char *xml) { if ((dupVM = virDomainObjIsDuplicate(&driver->domains, def, 0)) < 0) goto cleanup; + /* Make sure no disk is used by other domain, if it's not + * either shareable or readonly. + */ + for (i = 0; i < def->ndisks; i++) { + /* XXX: Do we also need to check if same host&port is used by + * other domain for disk of nbd type? + */ + if (def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_NETWORK && + def->disks[i]->protocol == VIR_DOMAIN_DISK_PROTOCOL_NBD) + continue; + + if (!def->disks[i]->shared && + !def->disks[i]->readonly && + (vm = virDomainFindByDiskPath(&driver->domains, + def->disks[i]->src))) { + qemuReportError(VIR_ERR_INVALID_ARG, + _("disk '%s' already used by domain '%s'"), + def->disks[i]->src, + vm->def->name); + goto cleanup; + } + } + if (qemudCanonicalizeMachine(driver, def) < 0) goto cleanup; -- 1.7.6

On Fri, Sep 23, 2011 at 03:59:04PM +0800, Osier Yang wrote:
$subject + "If the disk is shared and readonly."
If the disk is not shared or readonly, the later started domain will relabel the disk, thus the first domain will lose the permission to write to the disk and be corrupt.
-- I'm not sure if it's the design to allow multiple domains use same disk not shared and readonly. So this patch just gives a demo of the implementation (it skips the checking of nbd disk, and only changes qemu driver), to see whether if the pricinple is right or not. --- src/conf/domain_conf.c | 34 ++++++++++++++++++++++++++++++++++ src/conf/domain_conf.h | 2 ++ src/libvirt_private.syms | 1 + src/qemu/qemu_driver.c | 24 ++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 0 deletions(-)
NACK, defining two guests with the same disk is not a bug. Only *starting* two guests with the same disk is a problem, and that is what the lock manager code is protecting against. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

于 2011年09月23日 15:59, Osier Yang 写道:
$subject + "If the disk is shared and readonly."
s/disk is/disk is not/
If the disk is not shared or readonly, the later started domain will relabel the disk, thus the first domain will lose the permission to write to the disk and be corrupt.
-- I'm not sure if it's the design to allow multiple domains use same disk not shared and readonly. So this patch just gives a demo of the implementation (it skips the checking of nbd disk, and only changes qemu driver),
Hmm, preventing the relabeling in security driver instead might be the more proper way? (If the disk source is used by other *running* domain, then quit relabeling and exit with error). However, this won't prevent one using same disk source for multiple domains if security_driver is disabled. And if security_driver is disabled, there will be no permission problem, all the domains can write to the same disk source, thus it might cause inconsistency between the domains or corrupt.
to see whether if the pricinple is right or not. --- src/conf/domain_conf.c | 34 ++++++++++++++++++++++++++++++++++ src/conf/domain_conf.h | 2 ++ src/libvirt_private.syms | 1 + src/qemu/qemu_driver.c | 24 ++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 0 deletions(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 7463d7c..b64450b 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -655,6 +655,40 @@ virDomainObjPtr virDomainFindByName(const virDomainObjListPtr doms, return obj; }
+static int +virDomainObjListSearchDiskPath(const void *payload, + const void *name ATTRIBUTE_UNUSED, + const void *data) +{ + virDomainObjPtr obj = (virDomainObjPtr)payload; + int i; + int want = 0; + const char *path = NULL; + + path = (const char *)data; + + virDomainObjLock(obj); + for (i = 0; obj->def->ndisks; i++) { + if (STREQ(obj->def->disks[i]->src, path)) { + want = 1; + break; + } + } + virDomainObjUnlock(obj); + + return want; +} + +virDomainObjPtr +virDomainFindByDiskPath(const virDomainObjListPtr doms, + const char *path) +{ + virDomainObjPtr obj = NULL; + obj = virHashSearch(doms->objs, virDomainObjListSearchDiskPath, path); + if (obj) + virDomainObjLock(obj); + return obj; +}
bool virDomainObjTaint(virDomainObjPtr obj, enum virDomainTaintFlags taint) diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 371f270..d7d42dd 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1549,6 +1549,8 @@ virDomainObjPtr virDomainFindByUUID(const virDomainObjListPtr doms, const unsigned char *uuid); virDomainObjPtr virDomainFindByName(const virDomainObjListPtr doms, const char *name); +virDomainObjPtr virDomainFindByDiskPath(const virDomainObjListPtr doms, + const char *path);
bool virDomainObjTaint(virDomainObjPtr obj, enum virDomainTaintFlags taint); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 8235ea1..c33cb2d 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -302,6 +302,7 @@ virDomainFSTypeToString; virDomainFindByID; virDomainFindByName; virDomainFindByUUID; +virDomainFindByDiskPath; virDomainGetRootFilesystem; virDomainGraphicsAuthConnectedTypeFromString; virDomainGraphicsAuthConnectedTypeToString; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 0d0bea2..a448a0b 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -4796,6 +4796,7 @@ static virDomainPtr qemudDomainDefine(virConnectPtr conn, const char *xml) { virDomainPtr dom = NULL; virDomainEventPtr event = NULL; int dupVM; + int i;
qemuDriverLock(driver); if (!(def = virDomainDefParseString(driver->caps, xml, @@ -4809,6 +4810,29 @@ static virDomainPtr qemudDomainDefine(virConnectPtr conn, const char *xml) { if ((dupVM = virDomainObjIsDuplicate(&driver->domains, def, 0)) < 0) goto cleanup;
+ /* Make sure no disk is used by other domain, if it's not + * either shareable or readonly. + */ + for (i = 0; i < def->ndisks; i++) { + /* XXX: Do we also need to check if same host&port is used by + * other domain for disk of nbd type? + */ + if (def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_NETWORK && + def->disks[i]->protocol == VIR_DOMAIN_DISK_PROTOCOL_NBD) + continue; + + if (!def->disks[i]->shared && + !def->disks[i]->readonly && + (vm = virDomainFindByDiskPath(&driver->domains, + def->disks[i]->src)) ) { + qemuReportError(VIR_ERR_INVALID_ARG, + _("disk '%s' already used by domain '%s'"), + def->disks[i]->src, + vm->def->name); + goto cleanup; + } + } + if (qemudCanonicalizeMachine(driver, def) < 0) goto cleanup;

On 09/23/2011 02:17 AM, Osier Yang wrote:
Hmm, preventing the relabeling in security driver instead might be the more proper way? (If the disk source is used by other *running* domain, then quit relabeling and exit with error).
No, prevent the relabeling in the lock manager. If one domain is running and the lock manager is running, that should be sufficient to prevent any other domain from starting with the same disk, even before we get to the labeling point.
However, this won't prevent one using same disk source for multiple domains if security_driver is disabled.
And if security_driver is disabled, there will be no permission problem, all the domains can write to the same disk source, thus it might cause inconsistency between the domains or corrupt.
to see whether if the pricinple is right or not.
The principle here is whether the lock manager is running. Only if you can still reproduce the problem with a lock manager (whether sanlock or fcntl) do we have a bug to fix. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org
participants (3)
-
Daniel P. Berrange
-
Eric Blake
-
Osier Yang