dm thin: handle metadata failures more consistently
authorJoe Thornber <ejt@redhat.com>
Thu, 5 Dec 2013 00:51:33 +0000 (19:51 -0500)
committerMike Snitzer <snitzer@redhat.com>
Tue, 7 Jan 2014 15:14:27 +0000 (10:14 -0500)
Introduce metadata_operation_failed() wrappers, around set_pool_mode(),
to assist with improving the consistency of how metadata failures are
handled.  Logging is improved and metadata operation failures trigger
read-only mode immediately.

Also, eliminate redundant set_pool_mode() calls in the two
alloc_data_block() caller's error paths.

Signed-off-by: Joe Thornber <ejt@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
drivers/md/dm-thin.c

index e49c27c91a1f9834816a250f4c0f1e2d24697c17..35d2e41ef82ffc4952d1dba1c17668847ee2949b 100644 (file)
@@ -198,7 +198,7 @@ struct pool {
 };
 
 static enum pool_mode get_pool_mode(struct pool *pool);
-static void set_pool_mode(struct pool *pool, enum pool_mode mode);
+static void metadata_operation_failed(struct pool *pool, const char *op, int r);
 
 /*
  * Target context for a pool.
@@ -641,9 +641,7 @@ static void process_prepared_mapping(struct dm_thin_new_mapping *m)
         */
        r = dm_thin_insert_block(tc->td, m->virt_block, m->data_block);
        if (r) {
-               DMERR_LIMIT("%s: dm_thin_insert_block() failed: error = %d",
-                           dm_device_name(pool->pool_md), r);
-               set_pool_mode(pool, PM_READ_ONLY);
+               metadata_operation_failed(pool, "dm_thin_insert_block", r);
                cell_error(pool, m->cell);
                goto out;
        }
@@ -900,11 +898,8 @@ static int commit(struct pool *pool)
                return -EINVAL;
 
        r = dm_pool_commit_metadata(pool->pmd);
-       if (r) {
-               DMERR_LIMIT("%s: dm_pool_commit_metadata failed: error = %d",
-                           dm_device_name(pool->pool_md), r);
-               set_pool_mode(pool, PM_READ_ONLY);
-       }
+       if (r)
+               metadata_operation_failed(pool, "dm_pool_commit_metadata", r);
 
        return r;
 }
@@ -941,8 +936,10 @@ static int alloc_data_block(struct thin_c *tc, dm_block_t *result)
                return -EINVAL;
 
        r = dm_pool_get_free_block_count(pool->pmd, &free_blocks);
-       if (r)
+       if (r) {
+               metadata_operation_failed(pool, "dm_pool_get_free_block_count", r);
                return r;
+       }
 
        check_low_water_mark(pool, free_blocks);
 
@@ -956,8 +953,10 @@ static int alloc_data_block(struct thin_c *tc, dm_block_t *result)
                        return r;
 
                r = dm_pool_get_free_block_count(pool->pmd, &free_blocks);
-               if (r)
+               if (r) {
+                       metadata_operation_failed(pool, "dm_pool_get_free_block_count", r);
                        return r;
+               }
 
                /*
                 * If we still have no space we set a flag to avoid
@@ -980,11 +979,11 @@ static int alloc_data_block(struct thin_c *tc, dm_block_t *result)
        if (r) {
                if (r == -ENOSPC &&
                    !dm_pool_get_free_metadata_block_count(pool->pmd, &free_blocks) &&
-                   !free_blocks) {
+                   !free_blocks)
                        DMWARN("%s: no free metadata space available.",
                               dm_device_name(pool->pool_md));
-                       set_pool_mode(pool, PM_READ_ONLY);
-               }
+
+               metadata_operation_failed(pool, "dm_pool_alloc_data_block", r);
                return r;
        }
 
@@ -1126,7 +1125,6 @@ static void break_sharing(struct thin_c *tc, struct bio *bio, dm_block_t block,
        default:
                DMERR_LIMIT("%s: alloc_data_block() failed: error = %d",
                            __func__, r);
-               set_pool_mode(pool, PM_READ_ONLY);
                cell_error(pool, cell);
                break;
        }
@@ -1205,7 +1203,6 @@ static void provision_block(struct thin_c *tc, struct bio *bio, dm_block_t block
        default:
                DMERR_LIMIT("%s: alloc_data_block() failed: error = %d",
                            __func__, r);
-               set_pool_mode(pool, PM_READ_ONLY);
                cell_error(pool, cell);
                break;
        }
@@ -1449,6 +1446,18 @@ static void set_pool_mode(struct pool *pool, enum pool_mode mode)
        }
 }
 
+/*
+ * Rather than calling set_pool_mode directly, use these which describe the
+ * reason for mode degradation.
+ */
+static void metadata_operation_failed(struct pool *pool, const char *op, int r)
+{
+       DMERR_LIMIT("%s: metadata operation '%s' failed: error = %d",
+                   dm_device_name(pool->pool_md), op, r);
+
+       set_pool_mode(pool, PM_READ_ONLY);
+}
+
 /*----------------------------------------------------------------*/
 
 /*
@@ -2209,9 +2218,7 @@ static int maybe_resize_data_dev(struct dm_target *ti, bool *need_commit)
        } else if (data_size > sb_data_size) {
                r = dm_pool_resize_data_dev(pool->pmd, data_size);
                if (r) {
-                       DMERR("%s: failed to resize data device",
-                             dm_device_name(pool->pool_md));
-                       set_pool_mode(pool, PM_READ_ONLY);
+                       metadata_operation_failed(pool, "dm_pool_resize_data_dev", r);
                        return r;
                }
 
@@ -2248,8 +2255,7 @@ static int maybe_resize_metadata_dev(struct dm_target *ti, bool *need_commit)
        } else if (metadata_dev_size > sb_metadata_dev_size) {
                r = dm_pool_resize_metadata_dev(pool->pmd, metadata_dev_size);
                if (r) {
-                       DMERR("%s: failed to resize metadata device",
-                             dm_device_name(pool->pool_md));
+                       metadata_operation_failed(pool, "dm_pool_resize_metadata_dev", r);
                        return r;
                }