rbd: Use librbd to create RBD images

This way the images are in format 2 since libvirt doesn't support this yet
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java
index 29c52ea..dae25ae 100644
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java
@@ -74,6 +74,8 @@
     private String _manageSnapshotPath;
 
     private String rbdTemplateSnapName = "cloudstack-base-snap";
+    private int rbdFeatures = (1<<0); /* Feature 1<<0 means layering in RBD format 2 */
+    private int rbdOrder = 0; /* Order 0 means 4MB blocks (the default) */
 
     public LibvirtStorageAdaptor(StorageLayer storage) {
         _storageLayer = storage;
@@ -616,34 +618,76 @@
         StoragePool virtPool = libvirtPool.getPool();
         LibvirtStorageVolumeDef.volFormat libvirtformat = null;
 
+        String volPath = null;
+        String volName = null;
+        long volAllocation = 0;
+        long volCapacity = 0;
+
+        /**
+         * To have RBD function properly we want RBD images of format 2
+         * libvirt currently defaults to format 1
+         *
+         * For that reason we use the native RBD bindings to create the
+         * RBD image until libvirt creates RBD format 2 by default
+         */
         if (pool.getType() == StoragePoolType.RBD) {
             format = PhysicalDiskFormat.RAW;
+
+            try {
+                s_logger.info("Creating RBD image " + pool.getSourcePort() + "/" + name + " with size " + size);
+
+                Rados r = new Rados(pool.getAuthUserName());
+                r.confSet("mon_host", pool.getSourceHost() + ":" + pool.getSourcePort());
+                r.confSet("key", pool.getAuthSecret());
+                r.connect();
+                s_logger.debug("Succesfully connected to Ceph cluster at " + r.confGet("mon_host"));
+
+                IoCTX io = r.ioCtxCreate(pool.getSourceDir());
+                Rbd rbd = new Rbd(io);
+                rbd.create(name, size, this.rbdFeatures, this.rbdOrder);
+
+                r.ioCtxDestroy(io);
+            } catch (RadosException e) {
+                throw new CloudRuntimeException(e.toString());
+            } catch (RbdException e) {
+                throw new CloudRuntimeException(e.toString());
+            }
+
+            volPath = name;
+            volName = name;
+            volCapacity = size;
+            volAllocation = size;
+        } else {
+
+            if (format == PhysicalDiskFormat.QCOW2) {
+                libvirtformat = LibvirtStorageVolumeDef.volFormat.QCOW2;
+            } else if (format == PhysicalDiskFormat.RAW) {
+                libvirtformat = LibvirtStorageVolumeDef.volFormat.RAW;
+            } else if (format == PhysicalDiskFormat.DIR) {
+                libvirtformat = LibvirtStorageVolumeDef.volFormat.DIR;
+            } else if (format == PhysicalDiskFormat.TAR) {
+                libvirtformat = LibvirtStorageVolumeDef.volFormat.TAR;
+            }
+
+            LibvirtStorageVolumeDef volDef = new LibvirtStorageVolumeDef(name,
+                    size, libvirtformat, null, null);
+            s_logger.debug(volDef.toString());
+            try {
+                StorageVol vol = virtPool.storageVolCreateXML(volDef.toString(), 0);
+                volPath = vol.getPath();
+                volName = vol.getName();
+                volAllocation = vol.getInfo().allocation;
+                volCapacity = vol.getInfo().capacity;
+            } catch (LibvirtException e) {
+                throw new CloudRuntimeException(e.toString());
+            }
         }
 
-        if (format == PhysicalDiskFormat.QCOW2) {
-            libvirtformat = LibvirtStorageVolumeDef.volFormat.QCOW2;
-        } else if (format == PhysicalDiskFormat.RAW) {
-            libvirtformat = LibvirtStorageVolumeDef.volFormat.RAW;
-        } else if (format == PhysicalDiskFormat.DIR) {
-            libvirtformat = LibvirtStorageVolumeDef.volFormat.DIR;
-        } else if (format == PhysicalDiskFormat.TAR) {
-            libvirtformat = LibvirtStorageVolumeDef.volFormat.TAR;
-        }
-
-        LibvirtStorageVolumeDef volDef = new LibvirtStorageVolumeDef(name,
-                size, libvirtformat, null, null);
-        s_logger.debug(volDef.toString());
-        try {
-            StorageVol vol = virtPool.storageVolCreateXML(volDef.toString(), 0);
-            KVMPhysicalDisk disk = new KVMPhysicalDisk(vol.getPath(),
-                    vol.getName(), pool);
-            disk.setFormat(format);
-            disk.setSize(vol.getInfo().allocation);
-            disk.setVirtualSize(vol.getInfo().capacity);
-            return disk;
-        } catch (LibvirtException e) {
-            throw new CloudRuntimeException(e.toString());
-        }
+        KVMPhysicalDisk disk = new KVMPhysicalDisk(volPath, volName, pool);
+        disk.setFormat(format);
+        disk.setSize(volAllocation);
+        disk.setVirtualSize(volCapacity);
+        return disk;
     }
 
     @Override
@@ -767,11 +811,6 @@
                      * we want to copy it
                      */
 
-                    /* Feature 1<<0 means layering in RBD format 2 */
-                    int rbdFeatures = (1<<0);
-                    /* Order 0 means 4MB blocks (the default) */
-                    int rbdOrder = 0;
-
                     try {
                         if ((srcPool.getSourceHost().equals(destPool.getSourceHost())) && (srcPool.getSourceDir().equals(destPool.getSourceDir()))) {
                             /* We are on the same Ceph cluster, but we require RBD format 2 on the source image */
@@ -792,7 +831,7 @@
                                 s_logger.debug("The source image " + srcPool.getSourceDir() + "/" + template.getName()
                                                + " is RBD format 1. We have to perform a regular copy (" + template.getVirtualSize() + " bytes)");
 
-                                rbd.create(disk.getName(), template.getVirtualSize(), rbdFeatures, rbdOrder);
+                                rbd.create(disk.getName(), template.getVirtualSize(), this.rbdFeatures, this.rbdOrder);
                                 RbdImage destImage = rbd.open(disk.getName());
 
                                 s_logger.debug("Starting to copy " + srcImage.getName() +  " to " + destImage.getName() + " in Ceph pool " + srcPool.getSourceDir());
@@ -805,7 +844,7 @@
                                                + " is RBD format 2. We will perform a RBD clone using snapshot "
                                                + this.rbdTemplateSnapName);
                                 /* The source image is format 2, we can do a RBD snapshot+clone (layering) */
-                                rbd.clone(template.getName(), this.rbdTemplateSnapName, io, disk.getName(), rbdFeatures, rbdOrder);
+                                rbd.clone(template.getName(), this.rbdTemplateSnapName, io, disk.getName(), this.rbdFeatures, this.rbdOrder);
                                 s_logger.debug("Succesfully cloned " + template.getName() + "@" + this.rbdTemplateSnapName + " to " + disk.getName());
                             }
 
@@ -835,7 +874,7 @@
 
                             s_logger.debug("Creating " + disk.getName() + " on the destination cluster " + rDest.confGet("mon_host")
                                            + " in pool " + destPool.getSourceDir());
-                            dRbd.create(disk.getName(), template.getVirtualSize(), rbdFeatures, rbdOrder);
+                            dRbd.create(disk.getName(), template.getVirtualSize(), this.rbdFeatures, this.rbdOrder);
 
                             RbdImage srcImage = sRbd.open(template.getName());
                             RbdImage destImage = dRbd.open(disk.getName());
@@ -980,8 +1019,6 @@
               */
             s_logger.debug("The source image is not RBD, but the destination is. We will convert into RBD format 2");
             String tmpFile = "/tmp/" + name;
-            int rbdFeatures = (1<<0);
-            int rbdOrder = 0;
 
             try {
                 srcFile = new QemuImgFile(sourcePath, sourceFormat);
@@ -1000,7 +1037,7 @@
                 Rbd rbd = new Rbd(io);
 
                 s_logger.debug("Creating RBD image " + name + " in Ceph pool " + destPool.getSourceDir() + " with RBD format 2");
-                rbd.create(name, disk.getVirtualSize(), rbdFeatures, rbdOrder);
+                rbd.create(name, disk.getVirtualSize(), this.rbdFeatures, this.rbdOrder);
 
                 RbdImage image = rbd.open(name);