From 2448ffd53bd224564b8fca17e4cbbace2e039597 Mon Sep 17 00:00:00 2001
From: "vitas.yuzhou" <vitas.yuzhou@huawei.com>
Date: Tue, 13 May 2014 02:57:48 +0800
Subject: [PATCH] Check whether O_DIRECT is supported to iflag and oflag
 separately

The problem is when this is used for volume clear and the clear method
specifies use of the 'zero' option (/dev/zero) setting iflag direct is
not a valid option for that input file, but oflag direct is a valid
option for output file, so we should check iflag and oflag separately.

Change-Id: I4b627e95b68d56e3011cddc577c62fad0c384dba
Close-Bug: 1318748
---
 cinder/tests/test_volume_utils.py | 17 +++++++++++++++++
 cinder/volume/utils.py            | 17 +++++++++--------
 2 files changed, 26 insertions(+), 8 deletions(-)

diff --git a/cinder/tests/test_volume_utils.py b/cinder/tests/test_volume_utils.py
index fd120013c..358a5e66a 100644
--- a/cinder/tests/test_volume_utils.py
+++ b/cinder/tests/test_volume_utils.py
@@ -25,6 +25,7 @@ from cinder import db
 from cinder import exception
 from cinder.openstack.common import importutils
 from cinder.openstack.common import log as logging
+from cinder.openstack.common import processutils
 from cinder import test
 from cinder.tests import fake_notifier
 from cinder import utils
@@ -200,3 +201,19 @@ class ClearVolumeTestCase(test.TestCase):
 
         self.stubs.Set(volume_utils, 'copy_volume', fake_copy_volume)
         volume_utils.clear_volume(123, vol_path)
+
+
+class CopyVolumeTestCase(test.TestCase):
+
+    def test_copy_volume_dd_iflag_and_oflag(self):
+        def fake_utils_execute(*cmd, **kwargs):
+            if 'if=/dev/zero' in cmd and 'iflag=direct' in cmd:
+                raise processutils.ProcessExecutionError()
+            if 'of=/dev/null' in cmd and 'oflag=direct' in cmd:
+                raise processutils.ProcessExecutionError()
+            if 'iflag=direct' in cmd and 'oflag=direct' in cmd:
+                raise exception.InvalidInput(message='iflag/oflag error')
+
+        volume_utils.copy_volume('/dev/zero', '/dev/null', 1024,
+                                 CONF.volume_dd_blocksize, sync=True,
+                                 ionice=None, execute=fake_utils_execute)
diff --git a/cinder/volume/utils.py b/cinder/volume/utils.py
index 967bcee53..0ca7b68b5 100644
--- a/cinder/volume/utils.py
+++ b/cinder/volume/utils.py
@@ -131,14 +131,15 @@ def _calculate_count(size_in_m, blocksize):
 def copy_volume(srcstr, deststr, size_in_m, blocksize, sync=False,
                 execute=utils.execute, ionice=None):
     # Use O_DIRECT to avoid thrashing the system buffer cache
-    extra_flags = ['iflag=direct', 'oflag=direct']
-
-    # Check whether O_DIRECT is supported
-    try:
-        execute('dd', 'count=0', 'if=%s' % srcstr, 'of=%s' % deststr,
-                *extra_flags, run_as_root=True)
-    except processutils.ProcessExecutionError:
-        extra_flags = []
+    extra_flags = []
+    # Check whether O_DIRECT is supported to iflag and oflag separately
+    for flag in ['iflag=direct', 'oflag=direct']:
+        try:
+            execute('dd', 'count=0', 'if=%s' % srcstr, 'of=%s' % deststr,
+                    flag, run_as_root=True)
+            extra_flags.append(flag)
+        except processutils.ProcessExecutionError:
+            pass
 
     # If the volume is being unprovisioned then
     # request the data is persisted before returning,
-- 
2.45.2