王松波你好,
Thanks a lot for reporting a bug and providing a patch for it. However,
you will need to send the patch using git send-email to this mailing
list: it will ease the review and integration in master.
Thanks a lot for your help,
--
Cedric
On Tue, 2015-06-02 at 20:27 +0800, 王松波 wrote:
I report a bug [Bug 1227257] . In the environment
libvirt-1.2.16.tar.gz + qemu-img version 2.1.2 + ceph version 0.94.1.
libvirt pool will become inactive after one client does vol.delete and
the other does pool.refresh in the same pool simultaneously.
The reason is that rbd_list and rbd_open are not wrapped in an atomic
operation, but two seperate operations.
For example, two clients are operating in the same pool at the same
time. One client does rbd_list, and got 10 rbd images, meanwhile, the
other client deletes one of the rbd image. In this situation, when the
first client does next operation, such as rbd_open , the command may
fail, because the rbd image has been removed.
I write a testcase in python to reproduce this problem as follow(also
have put it in the attachment):
##################################
import libvirt
import sys
import time
import sys
#coding:utf-8
QEMU_URL = 'qemu:///system'
VOL_TEMPLATE='''
<volume>
<name>{vol}</name>
<key>{pool}/{vol}</key>
<source>
</source>
<capacity unit='MB'>{cap_size}</capacity>
<allocation unit='MB'>{alloc_size}</allocation>
<target>
<path>rbd:{pool}/{vol}</path>
<format type='unknown'/>
<permissions>
<mode>00</mode>
<owner>0</owner>
<group>0</group>
</permissions>
</target>
</volume>'''
def create_vol(pool_name, vol_name, cap_size, alloc_size):
conn = libvirt.open(QEMU_URL)
if conn == None:
print 'Failed to open connection to the hypervisor'
sys.exit(1)
try:
pool = conn.storagePoolLookupByName(pool_name)
pool.refresh()
template = VOL_TEMPLATE.format(pool=pool_name, vol=vol_name,
cap_size=cap_size, alloc_size=alloc_size)
pool.createXML(template, 0)
except:
print 'Failed to open pool'
sys.exit(1)
finally:
if conn is not None:
conn.close()
def destroy_vol(pool_name, vol_name):
conn = libvirt.open(QEMU_URL)
if conn == None:
sys.exit(1)
pool = conn.storagePoolLookupByName(pool_name)
pool.refresh(0)
vol = pool.storageVolLookupByName(vol_name)
if vol is not None:
vol.delete(0)
if conn is not None:
conn.close()
if sys.argv[2] == 'create':
for i in range(1, 20):
volname = 'pool-down-test-%s-%d' % (sys.argv[1], i)
print 'create %s' % volname
create_vol('capacity', volname, '500', '500')
elif sys.argv[2] == 'destroy':
for i in range(1, 20):
volname = 'pool-down-test-%s-%d' % (sys.argv[1], i)
print 'destroy %s' % volname
destroy_vol('capacity', volname)
else:
print 'Usage: python vol-test.py clientId OPER'
print ' '
print 'where clientId : a num/string used to distinguish
different client'
print ' OPER : create/destroy'
Patch for this is as fllow:
diff --git a/src/storage/storage_backend_rbd.c
b/src/storage/storage_backend_rbd.c
index ae4bcb3..24fbc84 100644
--- a/src/storage/storage_backend_rbd.c
+++ b/src/storage/storage_backend_rbd.c
@@ -266,6 +266,46 @@ static int
virStorageBackendRBDCloseRADOSConn(virStorageBackendRBDStatePtr ptr)
return ret;
}
+static int volStorageBackendRBDVolIsExist(char *volname,
virStorageBackendRBDStatePtr ptr)
+{
+ int ret = -1;
+ char *name, *names = NULL;
+ size_t max_size = 1024;
+ int len = -1;
+
+ while (true) {
+ if (VIR_ALLOC_N(names, max_size) < 0)
+ goto cleanup;
+
+ len = rbd_list(ptr->ioctx, names, &max_size);
+ if (len >= 0)
+ break;
+ if (len != -ERANGE) {
+ VIR_WARN("%s", _("A problem occurred while listing RBD
images"));
+ goto cleanup;
+ }
+ VIR_FREE(names);
+ }
+
+ for (name = names; name < names + max_size;) {
+
+ if (STREQ(name, ""))
+ break;
+
+ name += strlen(name) + 1;
+ if (STREQ(volname, name)) {
+ VIR_ERROR("RBD images '%s' is exist, but cannot open it",
volname);
+ ret = -2;
+ break;
+ }
+ }
+ ret = 0;
+
+cleanup:
+ VIR_FREE(names);
+ return ret;
+}
+
static int volStorageBackendRBDRefreshVolInfo(virStorageVolDefPtr
vol,
virStoragePoolObjPtr
pool,
virStorageBackendRBDStatePtr ptr)
@@ -276,8 +316,15 @@ static int
volStorageBackendRBDRefreshVolInfo(virStorageVolDefPtr vol,
r = rbd_open(ptr->ioctx, vol->name, &image, NULL);
if (r < 0) {
- virReportSystemError(-r, _("failed to open the RBD image '%
s'"),
- vol->name);
+ VIR_DEBUG("failed to open RBD image '%s', check if it was
still exist in its pool",\
+ vol->name);
+ if (volStorageBackendRBDVolIsExist(vol->name, ptr) == 0) {
+ VIR_DEBUG("vol '%s' may be removed by the other rbd
client", vol->name);
+ ret = 0;
+ } else {
+ virReportSystemError(-r, _("failed to open the RBD image
'%s'"),
+ vol->name);
+ }
return ret;
}
--
libvir-list mailing list
libvir-list(a)redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list