dm thin: commit outstanding data every second
Joe Thornber [Wed, 28 Mar 2012 17:41:27 +0000 (18:41 +0100)]
Commit unwritten data every second to prevent too much building up.

Released blocks don't become available until after the next commit
(for crash resilience).  Prior to this patch commits were only
triggered by a message to the target or a REQ_{FLUSH,FUA} bio.  This
allowed far too big a position to build up.

The interval is hard-coded to 1 second.  This is a sensible setting.
I'm not making this user configurable, since there isn't much to be
gained by tweaking this - and a lot lost by setting it far too high.

Signed-off-by: Joe Thornber <ejt@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>

drivers/md/dm-thin.c

index 1791134..bcb1433 100644 (file)
@@ -23,6 +23,7 @@
 #define DEFERRED_SET_SIZE 64
 #define MAPPING_POOL_SIZE 1024
 #define PRISON_CELLS 1024
+#define COMMIT_PERIOD HZ
 
 /*
  * The block size of the device holding pool data must be
@@ -520,8 +521,10 @@ struct pool {
 
        struct workqueue_struct *wq;
        struct work_struct worker;
+       struct delayed_work waker;
 
        unsigned ref_count;
+       unsigned long last_commit_jiffies;
 
        spinlock_t lock;
        struct bio_list deferred_bios;
@@ -1271,6 +1274,12 @@ static void process_bio(struct thin_c *tc, struct bio *bio)
        }
 }
 
+static int need_commit_due_to_time(struct pool *pool)
+{
+       return jiffies < pool->last_commit_jiffies ||
+              jiffies > pool->last_commit_jiffies + COMMIT_PERIOD;
+}
+
 static void process_deferred_bios(struct pool *pool)
 {
        unsigned long flags;
@@ -1312,7 +1321,7 @@ static void process_deferred_bios(struct pool *pool)
        bio_list_init(&pool->deferred_flush_bios);
        spin_unlock_irqrestore(&pool->lock, flags);
 
-       if (bio_list_empty(&bios))
+       if (bio_list_empty(&bios) && !need_commit_due_to_time(pool))
                return;
 
        r = dm_pool_commit_metadata(pool->pmd);
@@ -1323,6 +1332,7 @@ static void process_deferred_bios(struct pool *pool)
                        bio_io_error(bio);
                return;
        }
+       pool->last_commit_jiffies = jiffies;
 
        while ((bio = bio_list_pop(&bios)))
                generic_make_request(bio);
@@ -1336,6 +1346,17 @@ static void do_worker(struct work_struct *ws)
        process_deferred_bios(pool);
 }
 
+/*
+ * We want to commit periodically so that not too much
+ * unwritten data builds up.
+ */
+static void do_waker(struct work_struct *ws)
+{
+       struct pool *pool = container_of(to_delayed_work(ws), struct pool, waker);
+       wake_worker(pool);
+       queue_delayed_work(pool->wq, &pool->waker, COMMIT_PERIOD);
+}
+
 /*----------------------------------------------------------------*/
 
 /*
@@ -1545,6 +1566,7 @@ static struct pool *pool_create(struct mapped_device *pool_md,
        }
 
        INIT_WORK(&pool->worker, do_worker);
+       INIT_DELAYED_WORK(&pool->waker, do_waker);
        spin_lock_init(&pool->lock);
        bio_list_init(&pool->deferred_bios);
        bio_list_init(&pool->deferred_flush_bios);
@@ -1571,6 +1593,7 @@ static struct pool *pool_create(struct mapped_device *pool_md,
                goto bad_endio_hook_pool;
        }
        pool->ref_count = 1;
+       pool->last_commit_jiffies = jiffies;
        pool->pool_md = pool_md;
        pool->md_dev = metadata_dev;
        __pool_table_insert(pool);
@@ -1900,7 +1923,7 @@ static void pool_resume(struct dm_target *ti)
        __requeue_bios(pool);
        spin_unlock_irqrestore(&pool->lock, flags);
 
-       wake_worker(pool);
+       do_waker(&pool->waker.work);
 }
 
 static void pool_postsuspend(struct dm_target *ti)
@@ -1909,6 +1932,7 @@ static void pool_postsuspend(struct dm_target *ti)
        struct pool_c *pt = ti->private;
        struct pool *pool = pt->pool;
 
+       cancel_delayed_work(&pool->waker);
        flush_workqueue(pool->wq);
 
        r = dm_pool_commit_metadata(pool->pmd);