4.4-stable review patch.  If anyone has any objections, please let me know.

------------------

From: Mike Snitzer <snit...@redhat.com>

commit 9567366fefddeaea4ed1d713270535d93a3b3c76 upstream.

The READ_LOCK macro was incorrectly returning -EINVAL if
dm_bm_is_read_only() was true -- it will always be true once the cache
metadata transitions to read-only by dm_cache_metadata_set_read_only().

Wrap READ_LOCK and WRITE_LOCK multi-statement macros in do {} while(0).
Also, all accesses of the 'cmd' argument passed to these related macros
are now encapsulated in parenthesis.

A follow-up patch can be developed to eliminate the use of macros in
favor of pure C code.  Avoiding that now given that this needs to apply
to stable@.

Reported-by: Ben Hutchings <b...@decadent.org.uk>
Signed-off-by: Mike Snitzer <snit...@redhat.com>
Fixes: d14fcf3dd79 ("dm cache: make sure every metadata function checks 
fail_io")
Signed-off-by: Greg Kroah-Hartman <gre...@linuxfoundation.org>

---
 drivers/md/dm-cache-metadata.c |   64 +++++++++++++++++++++++++----------------
 1 file changed, 40 insertions(+), 24 deletions(-)

--- a/drivers/md/dm-cache-metadata.c
+++ b/drivers/md/dm-cache-metadata.c
@@ -867,39 +867,55 @@ static int blocks_are_unmapped_or_clean(
        return 0;
 }
 
-#define WRITE_LOCK(cmd)        \
-       down_write(&cmd->root_lock); \
-       if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) { \
-               up_write(&cmd->root_lock); \
-               return -EINVAL; \
+static bool cmd_write_lock(struct dm_cache_metadata *cmd)
+{
+       down_write(&cmd->root_lock);
+       if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) {
+               up_write(&cmd->root_lock);
+               return false;
        }
+       return true;
+}
 
-#define WRITE_LOCK_VOID(cmd) \
-       down_write(&cmd->root_lock); \
-       if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) { \
-               up_write(&cmd->root_lock); \
-               return; \
-       }
+#define WRITE_LOCK(cmd)                                \
+       do {                                    \
+               if (!cmd_write_lock((cmd)))     \
+                       return -EINVAL;         \
+       } while(0)
+
+#define WRITE_LOCK_VOID(cmd)                   \
+       do {                                    \
+               if (!cmd_write_lock((cmd)))     \
+                       return;                 \
+       } while(0)
 
 #define WRITE_UNLOCK(cmd) \
-       up_write(&cmd->root_lock)
+       up_write(&(cmd)->root_lock)
 
-#define READ_LOCK(cmd) \
-       down_read(&cmd->root_lock); \
-       if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) { \
-               up_read(&cmd->root_lock); \
-               return -EINVAL; \
+static bool cmd_read_lock(struct dm_cache_metadata *cmd)
+{
+       down_write(&cmd->root_lock);
+       if (cmd->fail_io) {
+               up_write(&cmd->root_lock);
+               return false;
        }
+       return true;
+}
 
-#define READ_LOCK_VOID(cmd)    \
-       down_read(&cmd->root_lock); \
-       if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) { \
-               up_read(&cmd->root_lock); \
-               return; \
-       }
+#define READ_LOCK(cmd)                         \
+       do {                                    \
+               if (!cmd_read_lock((cmd)))      \
+                       return -EINVAL;         \
+       } while(0)
+
+#define READ_LOCK_VOID(cmd)                    \
+       do {                                    \
+               if (!cmd_read_lock((cmd)))      \
+                       return;                 \
+       } while(0)
 
 #define READ_UNLOCK(cmd) \
-       up_read(&cmd->root_lock)
+       up_read(&(cmd)->root_lock)
 
 int dm_cache_resize(struct dm_cache_metadata *cmd, dm_cblock_t new_cache_size)
 {


Reply via email to