dm thin: cleanup and improve no space handling
authorMike Snitzer <snitzer@redhat.com>
Thu, 5 Dec 2013 21:03:33 +0000 (16:03 -0500)
committerMike Snitzer <snitzer@redhat.com>
Tue, 7 Jan 2014 15:14:28 +0000 (10:14 -0500)
Factor out_of_data_space() out of alloc_data_block().  Eliminate the use
of 'no_free_space' as a latch in alloc_data_block() -- this is no longer
needed now that we switch to read-only mode when we run out of data or
metadata space.  In a later patch, the 'no_free_space' flag will be
eliminated entirely (in favor of checking metadata rather than relying
on a transient flag).

Move no metdata space handling into metdata_operation_failed().  Set
no_free_space when metadata space is exhausted too.  This is useful,
because it offers consistency, for the following patch that will requeue
data IOs if no_free_space.

Also, rename no_space() to retry_bios_on_resume().

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

index 234696009d7b7dde89f448bfde9d76e7de12cb98..96ce36a1a764216f8768dacd828d802a50dc9d49 100644 (file)
@@ -198,6 +198,7 @@ struct pool {
 };
 
 static enum pool_mode get_pool_mode(struct pool *pool);
+static void out_of_data_space(struct pool *pool);
 static void metadata_operation_failed(struct pool *pool, const char *op, int r);
 
 /*
@@ -922,16 +923,8 @@ static int alloc_data_block(struct thin_c *tc, dm_block_t *result)
 {
        int r;
        dm_block_t free_blocks;
-       unsigned long flags;
        struct pool *pool = tc->pool;
 
-       /*
-        * Once no_free_space is set we must not allow allocation to succeed.
-        * Otherwise it is difficult to explain, debug, test and support.
-        */
-       if (pool->no_free_space)
-               return -ENOSPC;
-
        if (get_pool_mode(pool) != PM_WRITE)
                return -EINVAL;
 
@@ -958,31 +951,14 @@ static int alloc_data_block(struct thin_c *tc, dm_block_t *result)
                        return r;
                }
 
-               /*
-                * If we still have no space we set a flag to avoid
-                * doing all this checking and return -ENOSPC.  This
-                * flag serves as a latch that disallows allocations from
-                * this pool until the admin takes action (e.g. resize or
-                * table reload).
-                */
                if (!free_blocks) {
-                       DMWARN("%s: no free data space available.",
-                              dm_device_name(pool->pool_md));
-                       spin_lock_irqsave(&pool->lock, flags);
-                       pool->no_free_space = true;
-                       spin_unlock_irqrestore(&pool->lock, flags);
+                       out_of_data_space(pool);
                        return -ENOSPC;
                }
        }
 
        r = dm_pool_alloc_data_block(pool->pmd, result);
        if (r) {
-               if (r == -ENOSPC &&
-                   !dm_pool_get_free_metadata_block_count(pool->pmd, &free_blocks) &&
-                   !free_blocks)
-                       DMWARN("%s: no free metadata space available.",
-                              dm_device_name(pool->pool_md));
-
                metadata_operation_failed(pool, "dm_pool_alloc_data_block", r);
                return r;
        }
@@ -1006,7 +982,7 @@ static void retry_on_resume(struct bio *bio)
        spin_unlock_irqrestore(&pool->lock, flags);
 }
 
-static void no_space(struct pool *pool, struct dm_bio_prison_cell *cell)
+static void retry_bios_on_resume(struct pool *pool, struct dm_bio_prison_cell *cell)
 {
        struct bio *bio;
        struct bio_list bios;
@@ -1119,7 +1095,7 @@ static void break_sharing(struct thin_c *tc, struct bio *bio, dm_block_t block,
                break;
 
        case -ENOSPC:
-               no_space(pool, cell);
+               retry_bios_on_resume(pool, cell);
                break;
 
        default:
@@ -1197,7 +1173,7 @@ static void provision_block(struct thin_c *tc, struct bio *bio, dm_block_t block
                break;
 
        case -ENOSPC:
-               no_space(pool, cell);
+               retry_bios_on_resume(pool, cell);
                break;
 
        default:
@@ -1446,15 +1422,42 @@ static void set_pool_mode(struct pool *pool, enum pool_mode mode)
        }
 }
 
+static void set_no_free_space(struct pool *pool)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&pool->lock, flags);
+       pool->no_free_space = true;
+       spin_unlock_irqrestore(&pool->lock, flags);
+}
+
 /*
  * Rather than calling set_pool_mode directly, use these which describe the
  * reason for mode degradation.
  */
+static void out_of_data_space(struct pool *pool)
+{
+       DMERR_LIMIT("%s: no free data space available.",
+                   dm_device_name(pool->pool_md));
+       set_no_free_space(pool);
+       set_pool_mode(pool, PM_READ_ONLY);
+}
+
 static void metadata_operation_failed(struct pool *pool, const char *op, int r)
 {
+       dm_block_t free_blocks;
+
        DMERR_LIMIT("%s: metadata operation '%s' failed: error = %d",
                    dm_device_name(pool->pool_md), op, r);
 
+       if (r == -ENOSPC &&
+           !dm_pool_get_free_metadata_block_count(pool->pmd, &free_blocks) &&
+           !free_blocks) {
+               DMERR_LIMIT("%s: no free metadata space available.",
+                           dm_device_name(pool->pool_md));
+               set_no_free_space(pool);
+       }
+
        set_pool_mode(pool, PM_READ_ONLY);
 }