You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by wi...@apache.org on 2013/11/20 17:13:42 UTC

git commit: updated refs/heads/master to 1edaa36

Updated Branches:
  refs/heads/master 31758ed8d -> 1edaa36cc


CLOUDSTACK-1302: Allow a cache mode per disk offering

Per disk offering the setting none, writeback or writethrough can be set

This allows for both safety and performance for writes.


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/1edaa36c
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/1edaa36c
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/1edaa36c

Branch: refs/heads/master
Commit: 1edaa36cc68e845a42339d5f267d49c82343aefb
Parents: 31758ed
Author: Wido den Hollander <wi...@widodh.nl>
Authored: Thu Aug 1 16:49:15 2013 +0200
Committer: Wido den Hollander <wi...@widodh.nl>
Committed: Wed Nov 20 17:11:10 2013 +0100

----------------------------------------------------------------------
 api/src/com/cloud/agent/api/to/VolumeTO.java    |  9 +++++
 api/src/com/cloud/offering/DiskOffering.java    | 19 +++++++++++
 api/src/com/cloud/vm/DiskProfile.java           |  9 +++++
 .../api/response/DiskOfferingResponse.java      | 11 ++++++
 .../classes/resources/messages.properties       |  1 +
 .../cloud/agent/api/AttachVolumeCommand.java    |  9 +++++
 .../cloudstack/storage/to/VolumeObjectTO.java   | 10 ++++++
 .../subsystem/api/storage/VolumeInfo.java       |  3 ++
 .../src/com/cloud/storage/DiskOfferingVO.java   | 36 +++++++++++++++++++-
 .../cloudstack/storage/volume/VolumeObject.java | 10 ++++++
 .../kvm/resource/LibvirtComputingResource.java  | 13 +++++--
 .../kvm/resource/LibvirtDomainXMLParser.java    |  8 ++++-
 .../hypervisor/kvm/resource/LibvirtVMDef.java   | 24 ++++++++++++-
 .../api/query/dao/DiskOfferingJoinDaoImpl.java  |  1 +
 .../cloud/api/query/vo/DiskOfferingJoinVO.java  | 15 ++++++++
 ui/dictionary.jsp                               |  1 +
 ui/scripts/configuration.js                     | 26 ++++++++++++++
 ui/scripts/docs.js                              |  3 ++
 18 files changed, 203 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1edaa36c/api/src/com/cloud/agent/api/to/VolumeTO.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/agent/api/to/VolumeTO.java b/api/src/com/cloud/agent/api/to/VolumeTO.java
index fb08384..4dec4d8 100644
--- a/api/src/com/cloud/agent/api/to/VolumeTO.java
+++ b/api/src/com/cloud/agent/api/to/VolumeTO.java
@@ -41,6 +41,7 @@ public class VolumeTO implements InternalIdentity {
     private Long bytesWriteRate;
     private Long iopsReadRate;
     private Long iopsWriteRate;
+    private String cacheMode;
     private Long chainSize;
 
     public VolumeTO(long id, Volume.Type type, StoragePoolType poolType, String poolUuid, String name, String mountPoint, String path, long size, String chainInfo) {
@@ -176,6 +177,14 @@ public class VolumeTO implements InternalIdentity {
         return iopsWriteRate;
     }
 
+    public void setCacheMode(String cacheMode) {
+        this.cacheMode = cacheMode;
+    }
+
+    public String getCacheMode() {
+        return cacheMode;
+    }
+
     public Long getChainSize() {
         return chainSize;
     }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1edaa36c/api/src/com/cloud/offering/DiskOffering.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/offering/DiskOffering.java b/api/src/com/cloud/offering/DiskOffering.java
index fa6d66b..31bcfb3 100644
--- a/api/src/com/cloud/offering/DiskOffering.java
+++ b/api/src/com/cloud/offering/DiskOffering.java
@@ -35,6 +35,21 @@ public interface DiskOffering extends InfrastructureEntity, Identity, InternalId
 
     State getState();
 
+    public enum DiskCacheMode {
+        NONE("none"), WRITEBACK("writeback"), WRITETHROUGH("writethrough");
+        
+        private final String _diskCacheMode;
+
+        DiskCacheMode(String cacheMode) {
+            _diskCacheMode = cacheMode;
+        }
+
+        @Override
+        public String toString() {
+            return _diskCacheMode;
+        }
+    };
+
     String getUniqueName();
 
     boolean getUseLocalStorage();
@@ -92,4 +107,8 @@ public interface DiskOffering extends InfrastructureEntity, Identity, InternalId
     void setHypervisorSnapshotReserve(Integer hypervisorSnapshotReserve);
 
     Integer getHypervisorSnapshotReserve();
+
+    DiskCacheMode getCacheMode();
+
+    void setCacheMode(DiskCacheMode cacheMode);
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1edaa36c/api/src/com/cloud/vm/DiskProfile.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/vm/DiskProfile.java b/api/src/com/cloud/vm/DiskProfile.java
index 3d4c9e7..4412e3f 100644
--- a/api/src/com/cloud/vm/DiskProfile.java
+++ b/api/src/com/cloud/vm/DiskProfile.java
@@ -39,6 +39,7 @@ public class DiskProfile {
     private Long bytesWriteRate;
     private Long iopsReadRate;
     private Long iopsWriteRate;
+    private String cacheMode;
 
     private HypervisorType hyperType;
 
@@ -190,4 +191,12 @@ public class DiskProfile {
     public Long getIopsWriteRate() {
         return iopsWriteRate;
     }
+
+    public void setCacheMode(String cacheMode) {
+        this.cacheMode = cacheMode;
+    }
+
+    public String getCacheMode() {
+        return cacheMode;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1edaa36c/api/src/org/apache/cloudstack/api/response/DiskOfferingResponse.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/response/DiskOfferingResponse.java b/api/src/org/apache/cloudstack/api/response/DiskOfferingResponse.java
index 4291d85..8649890 100644
--- a/api/src/org/apache/cloudstack/api/response/DiskOfferingResponse.java
+++ b/api/src/org/apache/cloudstack/api/response/DiskOfferingResponse.java
@@ -79,6 +79,9 @@ public class DiskOfferingResponse extends BaseResponse {
     @SerializedName("diskIopsWriteRate") @Param(description="io requests write rate of the disk offering")
     private Long iopsWriteRate;
 
+    @SerializedName("cacheMode") @Param(description="the cache mode to use for this disk offering. none, writeback or writethrough")
+    private String cacheMode;
+
     @SerializedName("displayoffering") @Param(description="whether to display the offering to the end user or not.")
     private Boolean displayOffering;
 
@@ -187,6 +190,14 @@ public class DiskOfferingResponse extends BaseResponse {
         this.maxIops = maxIops;
     }
 
+    public String getCacheMode() {
+        return this.cacheMode;
+    }
+
+    public void setCacheMode(String cacheMode) {
+        this.cacheMode = cacheMode;
+    }
+
     public String getStorageType() {
         return storageType;
     }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1edaa36c/client/WEB-INF/classes/resources/messages.properties
----------------------------------------------------------------------
diff --git a/client/WEB-INF/classes/resources/messages.properties b/client/WEB-INF/classes/resources/messages.properties
index 1303562..461aa84 100644
--- a/client/WEB-INF/classes/resources/messages.properties
+++ b/client/WEB-INF/classes/resources/messages.properties
@@ -1096,6 +1096,7 @@ label.storage.tags=Storage Tags
 label.storage.traffic=Storage Traffic
 label.storage.type=Storage Type
 label.qos.type=QoS Type
+label.cache.mode=Write-cache Type
 label.storage=Storage
 label.subdomain.access=Subdomain Access
 label.submit=Submit

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1edaa36c/core/src/com/cloud/agent/api/AttachVolumeCommand.java
----------------------------------------------------------------------
diff --git a/core/src/com/cloud/agent/api/AttachVolumeCommand.java b/core/src/com/cloud/agent/api/AttachVolumeCommand.java
index e927619..e879897 100644
--- a/core/src/com/cloud/agent/api/AttachVolumeCommand.java
+++ b/core/src/com/cloud/agent/api/AttachVolumeCommand.java
@@ -40,6 +40,7 @@ public class AttachVolumeCommand extends Command {
     private Long bytesWriteRate;
     private Long iopsReadRate;
     private Long iopsWriteRate;
+    private String cacheMode;
 
     protected AttachVolumeCommand() {
     }
@@ -202,4 +203,12 @@ public class AttachVolumeCommand extends Command {
     public Long getIopsWriteRate() {
         return iopsWriteRate;
     }
+
+    public void setCacheMode(String cacheMode) {
+        this.cacheMode = cacheMode;
+    }
+
+    public String getCacheMode() {
+        return cacheMode;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1edaa36c/core/src/org/apache/cloudstack/storage/to/VolumeObjectTO.java
----------------------------------------------------------------------
diff --git a/core/src/org/apache/cloudstack/storage/to/VolumeObjectTO.java b/core/src/org/apache/cloudstack/storage/to/VolumeObjectTO.java
index 46659a3..732fa7b 100644
--- a/core/src/org/apache/cloudstack/storage/to/VolumeObjectTO.java
+++ b/core/src/org/apache/cloudstack/storage/to/VolumeObjectTO.java
@@ -17,6 +17,7 @@
 package org.apache.cloudstack.storage.to;
 
 import com.cloud.hypervisor.Hypervisor;
+import com.cloud.offering.DiskOffering.DiskCacheMode;
 import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
 
 import com.cloud.agent.api.to.DataObjectType;
@@ -44,6 +45,7 @@ public class VolumeObjectTO implements DataTO {
     private Long bytesWriteRate;
     private Long iopsReadRate;
     private Long iopsWriteRate;
+    private DiskCacheMode cacheMode;
     private Hypervisor.HypervisorType hypervisorType;
 
     public VolumeObjectTO() {
@@ -71,6 +73,7 @@ public class VolumeObjectTO implements DataTO {
         this.bytesWriteRate = volume.getBytesWriteRate();
         this.iopsReadRate = volume.getIopsReadRate();
         this.iopsWriteRate = volume.getIopsWriteRate();
+        this.cacheMode = volume.getCacheMode();
         this.hypervisorType = volume.getHypervisorType();
         setDeviceId(volume.getDeviceId());
     }
@@ -231,5 +234,12 @@ public class VolumeObjectTO implements DataTO {
         this.deviceId = deviceId;
     }
 
+    public void setCacheMode(DiskCacheMode cacheMode) {
+        this.cacheMode = cacheMode;
+    }
+
+    public DiskCacheMode getCacheMode() {
+        return cacheMode;
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1edaa36c/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeInfo.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeInfo.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeInfo.java
index 3b4aba9..a7dbf79 100644
--- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeInfo.java
+++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeInfo.java
@@ -20,6 +20,7 @@ package org.apache.cloudstack.engine.subsystem.api.storage;
 
 import com.cloud.agent.api.Answer;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
+import com.cloud.offering.DiskOffering.DiskCacheMode;
 import com.cloud.storage.Volume;
 
 public interface VolumeInfo extends DataObject, Volume {
@@ -45,4 +46,6 @@ public interface VolumeInfo extends DataObject, Volume {
     Long getBytesWriteRate();
     Long getIopsReadRate();
     Long getIopsWriteRate();
+
+    DiskCacheMode getCacheMode();
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1edaa36c/engine/schema/src/com/cloud/storage/DiskOfferingVO.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/com/cloud/storage/DiskOfferingVO.java b/engine/schema/src/com/cloud/storage/DiskOfferingVO.java
index b5b3451..5960df4 100755
--- a/engine/schema/src/com/cloud/storage/DiskOfferingVO.java
+++ b/engine/schema/src/com/cloud/storage/DiskOfferingVO.java
@@ -24,8 +24,8 @@ import javax.persistence.Column;
 import javax.persistence.DiscriminatorColumn;
 import javax.persistence.DiscriminatorType;
 import javax.persistence.Entity;
-import javax.persistence.EnumType;
 import javax.persistence.Enumerated;
+import javax.persistence.EnumType;
 import javax.persistence.GeneratedValue;
 import javax.persistence.GenerationType;
 import javax.persistence.Id;
@@ -37,7 +37,9 @@ import javax.persistence.TemporalType;
 import javax.persistence.Transient;
 
 import com.cloud.offering.DiskOffering;
+import com.cloud.offering.DiskOffering.DiskCacheMode;
 import com.cloud.utils.db.GenericDao;
+import org.apache.cloudstack.api.Identity;
 
 @Entity
 @Table(name = "disk_offering")
@@ -120,6 +122,10 @@ public class DiskOfferingVO implements DiskOffering {
     @Column(name="iops_write_rate")
     Long iopsWriteRate;
 
+    @Column(name="cache_mode", updatable = true, nullable=false)
+    @Enumerated(value=EnumType.STRING)
+    private DiskCacheMode cacheMode;
+
     @Column(name="display_offering")
     boolean displayOffering = true;
 
@@ -135,6 +141,24 @@ public class DiskOfferingVO implements DiskOffering {
     }
 
     public DiskOfferingVO(Long domainId, String name, String displayText, long diskSize, String tags, boolean isCustomized,
+            Boolean isCustomizedIops, Long minIops, Long maxIops, DiskCacheMode cacheMode) {
+        this.domainId = domainId;
+        this.name = name;
+        this.displayText = displayText;
+        this.diskSize = diskSize;
+        this.tags = tags;
+        this.recreatable = false;
+        this.type = Type.Disk;
+        this.useLocalStorage = false;
+        this.customized = isCustomized;
+        this.uuid = UUID.randomUUID().toString();
+        this.customizedIops = isCustomizedIops;
+        this.minIops = minIops;
+        this.maxIops = maxIops;
+        this.cacheMode = cacheMode;
+    }
+
+    public DiskOfferingVO(Long domainId, String name, String displayText, long diskSize, String tags, boolean isCustomized,
     		Boolean isCustomizedIops, Long minIops, Long maxIops) {
         this.domainId = domainId;
         this.name = name;
@@ -237,6 +261,16 @@ public class DiskOfferingVO implements DiskOffering {
         this.maxIops = maxIops;
     }
 
+    @Override
+    public DiskCacheMode getCacheMode() {
+        return cacheMode;
+    }
+
+    @Override
+    public void setCacheMode(DiskCacheMode cacheMode) {
+        this.cacheMode = cacheMode;
+    }
+
 	@Override
     public String getUniqueName() {
         return uniqueName;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1edaa36c/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java
----------------------------------------------------------------------
diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java
index f761a0c..cec76c0 100644
--- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java
+++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java
@@ -39,6 +39,7 @@ import com.cloud.agent.api.storage.DownloadAnswer;
 import com.cloud.agent.api.to.DataObjectType;
 import com.cloud.agent.api.to.DataTO;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
+import com.cloud.offering.DiskOffering.DiskCacheMode;
 import com.cloud.storage.DataStoreRole;
 import com.cloud.storage.Storage.ImageFormat;
 import com.cloud.storage.Volume;
@@ -214,6 +215,15 @@ public class VolumeObject implements VolumeInfo {
         return null;
     }
 
+    @Override
+    public DiskCacheMode getCacheMode() {
+        DiskOfferingVO diskOfferingVO = getDiskOfferingVO();
+        if (diskOfferingVO != null) {
+            return diskOfferingVO.getCacheMode();
+        }
+        return null;
+    }
+
     public void update() {
         volumeDao.update(volumeVO.getId(), volumeVO);
         volumeVO = volumeDao.findById(volumeVO.getId());

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1edaa36c/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
index 50561a9..0000bef 100755
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
@@ -193,6 +193,7 @@ import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.CpuTuneDef;
 import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DevicesDef;
 import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef;
 import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef.diskProtocol;
+import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef.diskCacheMode;
 import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.FeaturesDef;
 import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.FilesystemDef;
 import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.GraphicDef;
@@ -1510,6 +1511,7 @@ ServerResource {
             volume.setBytesWriteRate(dskch.getBytesWriteRate());
             volume.setIopsReadRate(dskch.getIopsReadRate());
             volume.setIopsWriteRate(dskch.getIopsWriteRate());
+            volume.setCacheMode(dskch.getCacheMode());
             return new CreateAnswer(cmd, volume);
         } catch (CloudRuntimeException e) {
             s_logger.debug("Failed to create volume: " + e.toString());
@@ -2815,7 +2817,8 @@ ServerResource {
                     cmd.getPoolUuid());
             KVMPhysicalDisk disk = primary.getPhysicalDisk(cmd.getVolumePath());
             attachOrDetachDisk(conn, cmd.getAttach(), cmd.getVmName(), disk,
-                    cmd.getDeviceId().intValue(), cmd.getBytesReadRate(), cmd.getBytesWriteRate(), cmd.getIopsReadRate(), cmd.getIopsWriteRate());
+                    cmd.getDeviceId().intValue(), cmd.getBytesReadRate(), cmd.getBytesWriteRate(), cmd.getIopsReadRate(), cmd.getIopsWriteRate(),
+                    cmd.getCacheMode());
         } catch (LibvirtException e) {
             return new AttachVolumeAnswer(cmd, e.toString());
         } catch (InternalErrorException e) {
@@ -3775,6 +3778,8 @@ ServerResource {
                     disk.setIopsReadRate(volumeObjectTO.getIopsReadRate());
                 if ((volumeObjectTO.getIopsWriteRate() != null) && (volumeObjectTO.getIopsWriteRate() > 0))
                     disk.setIopsWriteRate(volumeObjectTO.getIopsWriteRate());
+                if (volumeObjectTO.getCacheMode() != null)
+                    disk.setCacheMode(DiskDef.diskCacheMode.valueOf(volumeObjectTO.getCacheMode().toString()));
             }
             vm.getDevices().addDevice(disk);
         }
@@ -3886,7 +3891,7 @@ ServerResource {
 
     protected synchronized String attachOrDetachDisk(Connect conn,
             boolean attach, String vmName, KVMPhysicalDisk attachingDisk,
-            int devId, Long bytesReadRate, Long bytesWriteRate, Long iopsReadRate, Long iopsWriteRate) throws LibvirtException, InternalErrorException {
+            int devId, Long bytesReadRate, Long bytesWriteRate, Long iopsReadRate, Long iopsWriteRate, String cacheMode) throws LibvirtException, InternalErrorException {
         List<DiskDef> disks = null;
         Domain dm = null;
         DiskDef diskdef = null;
@@ -3934,6 +3939,10 @@ ServerResource {
                     diskdef.setIopsReadRate(iopsReadRate);
                 if ((iopsWriteRate != null) && (iopsWriteRate > 0))
                     diskdef.setIopsWriteRate(iopsWriteRate);
+
+                if (cacheMode != null) {
+                    diskdef.setCacheMode(DiskDef.diskCacheMode.valueOf(cacheMode));
+                }
             }
 
             String xml = diskdef.toString();

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1edaa36c/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java
index a283768..d0b0b61 100644
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java
@@ -36,6 +36,7 @@ import org.xml.sax.SAXException;
 
 import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef;
 import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef.diskProtocol;
+import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef.diskCacheMode;
 import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef;
 import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef.nicModel;
 
@@ -69,6 +70,7 @@ public class LibvirtDomainXMLParser {
                 DiskDef def = new DiskDef();
                 if (type.equalsIgnoreCase("network")) {
                     String diskFmtType = getAttrValue("driver", "type", disk);
+                    String diskCacheMode = getAttrValue("driver", "cache", disk);
                     String diskPath = getAttrValue("source", "name", disk);
                     String protocol = getAttrValue("source", "protocol", disk);
                     String authUserName = getAttrValue("auth", "username", disk);
@@ -78,9 +80,12 @@ public class LibvirtDomainXMLParser {
                     String diskLabel = getAttrValue("target", "dev", disk);
                     String bus = getAttrValue("target", "bus", disk);
                     def.defNetworkBasedDisk(diskPath, host, port, authUserName, poolUuid, diskLabel,
-                                            DiskDef.diskBus.valueOf(bus.toUpperCase()), DiskDef.diskProtocol.valueOf(protocol.toUpperCase()));
+                                            DiskDef.diskBus.valueOf(bus.toUpperCase()),
+                                            DiskDef.diskProtocol.valueOf(protocol.toUpperCase()));
+                    def.setCacheMode(DiskDef.diskCacheMode.valueOf(diskCacheMode));
                 } else {
                     String diskFmtType = getAttrValue("driver", "type", disk);
+                    String diskCacheMode = getAttrValue("driver", "cache", disk);
                     String diskFile = getAttrValue("source", "file", disk);
                     String diskDev = getAttrValue("source", "dev", disk);
 
@@ -103,6 +108,7 @@ public class LibvirtDomainXMLParser {
                     } else if (type.equalsIgnoreCase("block")) {
                         def.defBlockBasedDisk(diskDev, diskLabel,
                                 DiskDef.diskBus.valueOf(bus.toUpperCase()));
+                        def.setCacheMode(DiskDef.diskCacheMode.valueOf(diskCacheMode));
                     }
                 }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1edaa36c/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java
index 6aaabc5..80dbb23 100644
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java
@@ -427,6 +427,23 @@ public class LibvirtVMDef {
             }
         }
 
+        public enum diskCacheMode {
+            NONE("none"), WRITEBACK("writeback"), WRITETHROUGH("writethrough");
+            String _diskCacheMode;
+
+            diskCacheMode(String cacheMode) {
+                _diskCacheMode = cacheMode;
+            }
+
+            @Override
+            public String toString() {
+                if (_diskCacheMode == null) {
+                    return "none";
+                }
+                return _diskCacheMode;
+            }
+        }
+
         private deviceType _deviceType; /* floppy, disk, cdrom */
         private diskType _diskType;
         private diskProtocol _diskProtocol;
@@ -445,6 +462,7 @@ public class LibvirtVMDef {
         private Long _bytesWriteRate;
         private Long _iopsReadRate;
         private Long _iopsWriteRate;
+        private diskCacheMode _diskCacheMode;
 
         public void setDeviceType(deviceType deviceType) {
             _deviceType = deviceType;
@@ -606,6 +624,10 @@ public class LibvirtVMDef {
             _iopsWriteRate = iopsWriteRate;
         }
 
+        public void setCacheMode(diskCacheMode cacheMode) {
+            _diskCacheMode = cacheMode;
+        }
+
         @Override
         public String toString() {
             StringBuilder diskBuilder = new StringBuilder();
@@ -616,7 +638,7 @@ public class LibvirtVMDef {
             diskBuilder.append(" type='" + _diskType + "'");
             diskBuilder.append(">\n");
             diskBuilder.append("<driver name='qemu'" + " type='" + _diskFmtType
-                    + "' cache='none' " + "/>\n");
+                    + "' cache='" + _diskCacheMode + "' " + "/>\n");
             if (_diskType == diskType.FILE) {
                 diskBuilder.append("<source ");
                 if (_sourcePath != null) {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1edaa36c/server/src/com/cloud/api/query/dao/DiskOfferingJoinDaoImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/query/dao/DiskOfferingJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/DiskOfferingJoinDaoImpl.java
index e29bb2b..fa620a7 100644
--- a/server/src/com/cloud/api/query/dao/DiskOfferingJoinDaoImpl.java
+++ b/server/src/com/cloud/api/query/dao/DiskOfferingJoinDaoImpl.java
@@ -79,6 +79,7 @@ public class DiskOfferingJoinDaoImpl extends GenericDaoBase<DiskOfferingJoinVO,
         diskOfferingResponse.setBytesWriteRate(offering.getBytesWriteRate());
         diskOfferingResponse.setIopsReadRate(offering.getIopsReadRate());
         diskOfferingResponse.setIopsWriteRate(offering.getIopsWriteRate());
+        diskOfferingResponse.setCacheMode(offering.getCacheMode());
         diskOfferingResponse.setObjectName("diskoffering");
 
         return diskOfferingResponse;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1edaa36c/server/src/com/cloud/api/query/vo/DiskOfferingJoinVO.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/query/vo/DiskOfferingJoinVO.java b/server/src/com/cloud/api/query/vo/DiskOfferingJoinVO.java
index 9a679de..e925cd1 100644
--- a/server/src/com/cloud/api/query/vo/DiskOfferingJoinVO.java
+++ b/server/src/com/cloud/api/query/vo/DiskOfferingJoinVO.java
@@ -85,6 +85,9 @@ public class DiskOfferingJoinVO extends BaseViewVO implements InternalIdentity,
     @Column(name="iops_write_rate")
     Long iopsWriteRate;
 
+    @Column(name="cache_mode")
+    String cacheMode;
+
     @Column(name="type")
     Type type;
 
@@ -162,6 +165,18 @@ public class DiskOfferingJoinVO extends BaseViewVO implements InternalIdentity,
         return maxIops;
     }
 
+    public void setMaxIops(Long maxIops) {
+        this.maxIops = maxIops;
+    }
+
+    public String getCacheMode() {
+        return cacheMode;
+    }
+
+    public void setCacheMode(String cacheMode) {
+        this.cacheMode = cacheMode;
+    }
+
     public boolean isDisplayOffering() {
         return displayOffering;
     }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1edaa36c/ui/dictionary.jsp
----------------------------------------------------------------------
diff --git a/ui/dictionary.jsp b/ui/dictionary.jsp
index f069588..c870f12 100644
--- a/ui/dictionary.jsp
+++ b/ui/dictionary.jsp
@@ -1078,6 +1078,7 @@ dictionary = {
 'label.storage.tags': '<fmt:message key="label.storage.tags" />',
 'label.storage.type': '<fmt:message key="label.storage.type" />',
 'label.qos.type': '<fmt:message key="label.qos.type" />',
+'label.cache.mode': '<fmt:message key="label.cache.mode" />',
 'label.subdomain.access': '<fmt:message key="label.subdomain.access" />',
 'label.submit': '<fmt:message key="label.submit" />',
 'label.submitted.by': '<fmt:message key="label.submitted.by" />',

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1edaa36c/ui/scripts/configuration.js
----------------------------------------------------------------------
diff --git a/ui/scripts/configuration.js b/ui/scripts/configuration.js
index 9c05169..8144466 100644
--- a/ui/scripts/configuration.js
+++ b/ui/scripts/configuration.js
@@ -1354,6 +1354,28 @@
                                             number: true
                                         }
                                     },
+                                    cacheMode: {
+                                        label: 'label.cache.mode',
+                                        docID: 'helpDiskOfferingCacheMode',
+                                        select: function(args) {
+                                            var items = [];
+                                            items.push({
+                                                id: 'none',
+                                                description: 'No disk cache'
+                                            });
+                                            items.push({
+                                                id: 'writeback',
+                                                description: 'Write-back disk caching'
+                                            });
+                                            items.push({
+                                                id: 'writethrough',
+                                                description: 'Write-through disk caching'
+                                            });
+                                            args.response.success({
+                                                data: items
+                                            });
+                                        }
+                                    },
                                     tags: {
                                         label: 'label.storage.tags',
                                         docID: 'helpDiskOfferingStorageTags'
@@ -1400,6 +1422,7 @@
                                     name: args.data.name,
                                     displaytext: args.data.description,
                                     storageType: args.data.storageType,
+                                    cacheMode: args.data.cacheMode,
                                     customized: (args.data.isCustomized == "on")
                                 };
 
@@ -1626,6 +1649,9 @@
                                     diskIopsWriteRate: {
                                         label: 'label.disk.iops.write.rate'
                                     },
+                                    cacheMode: {
+                                        label: 'label.cache.mode',
+                                    },
                                     tags: {
                                         label: 'label.storage.tags'
                                     },

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1edaa36c/ui/scripts/docs.js
----------------------------------------------------------------------
diff --git a/ui/scripts/docs.js b/ui/scripts/docs.js
index 8e7ea75..e898a96 100755
--- a/ui/scripts/docs.js
+++ b/ui/scripts/docs.js
@@ -328,6 +328,9 @@ cloudStack.docs = {
     },
     helpDiskOfferingHypervisorSnapshotReserve: {
         desc: 'Hypervisor snapshot reserve space as a percent of a volume (for managed storage using Xen or VMware) (Ex. The value 25 means 25%.)).',
+    },
+    helpDiskOfferingCacheMode: {
+        desc: 'The write caching mode to use for disks created with this disk offering. This can improve write performance.',
         externalLink: ''
     },
     helpDiskOfferingStorageTags: {