dm cache: cache shrinking support
[firefly-linux-kernel-4.4.55.git] / drivers / md / dm-cache-target.c
index 29569768ffbf97259e327ee09b5ce50349ae203e..183dfc9db297f58739990dc64459c1e329e97b56 100644 (file)
@@ -61,6 +61,34 @@ static void free_bitset(unsigned long *bits)
 
 /*----------------------------------------------------------------*/
 
+/*
+ * There are a couple of places where we let a bio run, but want to do some
+ * work before calling its endio function.  We do this by temporarily
+ * changing the endio fn.
+ */
+struct dm_hook_info {
+       bio_end_io_t *bi_end_io;
+       void *bi_private;
+};
+
+static void dm_hook_bio(struct dm_hook_info *h, struct bio *bio,
+                       bio_end_io_t *bi_end_io, void *bi_private)
+{
+       h->bi_end_io = bio->bi_end_io;
+       h->bi_private = bio->bi_private;
+
+       bio->bi_end_io = bi_end_io;
+       bio->bi_private = bi_private;
+}
+
+static void dm_unhook_bio(struct dm_hook_info *h, struct bio *bio)
+{
+       bio->bi_end_io = h->bi_end_io;
+       bio->bi_private = h->bi_private;
+}
+
+/*----------------------------------------------------------------*/
+
 #define PRISON_CELLS 1024
 #define MIGRATION_POOL_SIZE 128
 #define COMMIT_PERIOD HZ
@@ -148,6 +176,10 @@ struct cache {
        wait_queue_head_t migration_wait;
        atomic_t nr_migrations;
 
+       wait_queue_head_t quiescing_wait;
+       atomic_t quiescing;
+       atomic_t quiescing_ack;
+
        /*
         * cache_size entries, dirty if set
         */
@@ -186,7 +218,6 @@ struct cache {
 
        bool need_tick_bio:1;
        bool sized:1;
-       bool quiescing:1;
        bool commit_requested:1;
        bool loaded_mappings:1;
        bool loaded_discards:1;
@@ -211,7 +242,7 @@ struct per_bio_data {
         */
        struct cache *cache;
        dm_cblock_t cblock;
-       bio_end_io_t *saved_bi_end_io;
+       struct dm_hook_info hook_info;
        struct dm_bio_details bio_details;
 };
 
@@ -228,6 +259,7 @@ struct dm_cache_migration {
        bool writeback:1;
        bool demote:1;
        bool promote:1;
+       bool requeue_holder:1;
 
        struct dm_bio_prison_cell *old_ocell;
        struct dm_bio_prison_cell *new_ocell;
@@ -605,6 +637,7 @@ static void remap_to_origin_clear_discard(struct cache *cache, struct bio *bio,
 static void remap_to_cache_dirty(struct cache *cache, struct bio *bio,
                                 dm_oblock_t oblock, dm_cblock_t cblock)
 {
+       check_if_tick_bio_needed(cache, bio);
        remap_to_cache(cache, bio, cblock);
        if (bio_data_dir(bio) == WRITE) {
                set_dirty(cache, oblock, cblock);
@@ -662,7 +695,8 @@ static void defer_writethrough_bio(struct cache *cache, struct bio *bio)
 static void writethrough_endio(struct bio *bio, int err)
 {
        struct per_bio_data *pb = get_per_bio_data(bio, PB_DATA_SIZE_WT);
-       bio->bi_end_io = pb->saved_bi_end_io;
+
+       dm_unhook_bio(&pb->hook_info, bio);
 
        if (err) {
                bio_endio(bio, err);
@@ -693,9 +727,8 @@ static void remap_to_origin_then_cache(struct cache *cache, struct bio *bio,
 
        pb->cache = cache;
        pb->cblock = cblock;
-       pb->saved_bi_end_io = bio->bi_end_io;
+       dm_hook_bio(&pb->hook_info, bio, writethrough_endio, NULL);
        dm_bio_record(&pb->bio_details, bio);
-       bio->bi_end_io = writethrough_endio;
 
        remap_to_origin_clear_discard(pb->cache, bio, oblock);
 }
@@ -748,8 +781,9 @@ static void cell_defer(struct cache *cache, struct dm_bio_prison_cell *cell,
 
 static void cleanup_migration(struct dm_cache_migration *mg)
 {
-       dec_nr_migrations(mg->cache);
+       struct cache *cache = mg->cache;
        free_migration(mg);
+       dec_nr_migrations(cache);
 }
 
 static void migration_failure(struct dm_cache_migration *mg)
@@ -765,13 +799,13 @@ static void migration_failure(struct dm_cache_migration *mg)
                DMWARN_LIMIT("demotion failed; couldn't copy block");
                policy_force_mapping(cache->policy, mg->new_oblock, mg->old_oblock);
 
-               cell_defer(cache, mg->old_ocell, mg->promote ? 0 : 1);
+               cell_defer(cache, mg->old_ocell, mg->promote ? false : true);
                if (mg->promote)
-                       cell_defer(cache, mg->new_ocell, 1);
+                       cell_defer(cache, mg->new_ocell, true);
        } else {
                DMWARN_LIMIT("promotion failed; couldn't copy block");
                policy_remove_mapping(cache->policy, mg->new_oblock);
-               cell_defer(cache, mg->new_ocell, 1);
+               cell_defer(cache, mg->new_ocell, true);
        }
 
        cleanup_migration(mg);
@@ -823,7 +857,7 @@ static void migration_success_post_commit(struct dm_cache_migration *mg)
                return;
 
        } else if (mg->demote) {
-               cell_defer(cache, mg->old_ocell, mg->promote ? 0 : 1);
+               cell_defer(cache, mg->old_ocell, mg->promote ? false : true);
 
                if (mg->promote) {
                        mg->demote = false;
@@ -836,7 +870,12 @@ static void migration_success_post_commit(struct dm_cache_migration *mg)
                        cleanup_migration(mg);
 
        } else {
-               cell_defer(cache, mg->new_ocell, true);
+               if (mg->requeue_holder)
+                       cell_defer(cache, mg->new_ocell, true);
+               else {
+                       bio_endio(mg->new_ocell->holder, 0);
+                       cell_defer(cache, mg->new_ocell, false);
+               }
                clear_dirty(cache, mg->new_oblock, mg->cblock);
                cleanup_migration(mg);
        }
@@ -881,8 +920,46 @@ static void issue_copy_real(struct dm_cache_migration *mg)
                r = dm_kcopyd_copy(cache->copier, &o_region, 1, &c_region, 0, copy_complete, mg);
        }
 
-       if (r < 0)
+       if (r < 0) {
+               DMERR_LIMIT("issuing migration failed");
                migration_failure(mg);
+       }
+}
+
+static void overwrite_endio(struct bio *bio, int err)
+{
+       struct dm_cache_migration *mg = bio->bi_private;
+       struct cache *cache = mg->cache;
+       size_t pb_data_size = get_per_bio_data_size(cache);
+       struct per_bio_data *pb = get_per_bio_data(bio, pb_data_size);
+       unsigned long flags;
+
+       if (err)
+               mg->err = true;
+
+       spin_lock_irqsave(&cache->lock, flags);
+       list_add_tail(&mg->list, &cache->completed_migrations);
+       dm_unhook_bio(&pb->hook_info, bio);
+       mg->requeue_holder = false;
+       spin_unlock_irqrestore(&cache->lock, flags);
+
+       wake_worker(cache);
+}
+
+static void issue_overwrite(struct dm_cache_migration *mg, struct bio *bio)
+{
+       size_t pb_data_size = get_per_bio_data_size(mg->cache);
+       struct per_bio_data *pb = get_per_bio_data(bio, pb_data_size);
+
+       dm_hook_bio(&pb->hook_info, bio, overwrite_endio, mg);
+       remap_to_cache_dirty(mg->cache, bio, mg->new_oblock, mg->cblock);
+       generic_make_request(bio);
+}
+
+static bool bio_writes_complete_block(struct cache *cache, struct bio *bio)
+{
+       return (bio_data_dir(bio) == WRITE) &&
+               (bio->bi_size == (cache->sectors_per_block << SECTOR_SHIFT));
 }
 
 static void avoid_copy(struct dm_cache_migration *mg)
@@ -899,9 +976,17 @@ static void issue_copy(struct dm_cache_migration *mg)
        if (mg->writeback || mg->demote)
                avoid = !is_dirty(cache, mg->cblock) ||
                        is_discarded_oblock(cache, mg->old_oblock);
-       else
+       else {
+               struct bio *bio = mg->new_ocell->holder;
+
                avoid = is_discarded_oblock(cache, mg->new_oblock);
 
+               if (!avoid && bio_writes_complete_block(cache, bio)) {
+                       issue_overwrite(mg, bio);
+                       return;
+               }
+       }
+
        avoid ? avoid_copy(mg) : issue_copy_real(mg);
 }
 
@@ -991,6 +1076,7 @@ static void promote(struct cache *cache, struct prealloc *structs,
        mg->writeback = false;
        mg->demote = false;
        mg->promote = true;
+       mg->requeue_holder = true;
        mg->cache = cache;
        mg->new_oblock = oblock;
        mg->cblock = cblock;
@@ -1012,6 +1098,7 @@ static void writeback(struct cache *cache, struct prealloc *structs,
        mg->writeback = true;
        mg->demote = false;
        mg->promote = false;
+       mg->requeue_holder = true;
        mg->cache = cache;
        mg->old_oblock = oblock;
        mg->cblock = cblock;
@@ -1035,6 +1122,7 @@ static void demote_then_promote(struct cache *cache, struct prealloc *structs,
        mg->writeback = false;
        mg->demote = true;
        mg->promote = true;
+       mg->requeue_holder = true;
        mg->cache = cache;
        mg->old_oblock = old_oblock;
        mg->new_oblock = new_oblock;
@@ -1227,15 +1315,17 @@ static int need_commit_due_to_time(struct cache *cache)
 
 static int commit_if_needed(struct cache *cache)
 {
-       if (dm_cache_changed_this_transaction(cache->cmd) &&
-           (cache->commit_requested || need_commit_due_to_time(cache))) {
+       int r = 0;
+
+       if ((cache->commit_requested || need_commit_due_to_time(cache)) &&
+           dm_cache_changed_this_transaction(cache->cmd)) {
                atomic_inc(&cache->stats.commit_count);
-               cache->last_commit_jiffies = jiffies;
                cache->commit_requested = false;
-               return dm_cache_commit(cache->cmd, false);
+               r = dm_cache_commit(cache->cmd, false);
+               cache->last_commit_jiffies = jiffies;
        }
 
-       return 0;
+       return r;
 }
 
 static void process_deferred_bios(struct cache *cache)
@@ -1346,34 +1436,34 @@ static void writeback_some_dirty_blocks(struct cache *cache)
 /*----------------------------------------------------------------
  * Main worker loop
  *--------------------------------------------------------------*/
-static void start_quiescing(struct cache *cache)
+static bool is_quiescing(struct cache *cache)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&cache->lock, flags);
-       cache->quiescing = 1;
-       spin_unlock_irqrestore(&cache->lock, flags);
+       return atomic_read(&cache->quiescing);
 }
 
-static void stop_quiescing(struct cache *cache)
+static void ack_quiescing(struct cache *cache)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&cache->lock, flags);
-       cache->quiescing = 0;
-       spin_unlock_irqrestore(&cache->lock, flags);
+       if (is_quiescing(cache)) {
+               atomic_inc(&cache->quiescing_ack);
+               wake_up(&cache->quiescing_wait);
+       }
 }
 
-static bool is_quiescing(struct cache *cache)
+static void wait_for_quiescing_ack(struct cache *cache)
 {
-       int r;
-       unsigned long flags;
+       wait_event(cache->quiescing_wait, atomic_read(&cache->quiescing_ack));
+}
 
-       spin_lock_irqsave(&cache->lock, flags);
-       r = cache->quiescing;
-       spin_unlock_irqrestore(&cache->lock, flags);
+static void start_quiescing(struct cache *cache)
+{
+       atomic_inc(&cache->quiescing);
+       wait_for_quiescing_ack(cache);
+}
 
-       return r;
+static void stop_quiescing(struct cache *cache)
+{
+       atomic_set(&cache->quiescing, 0);
+       atomic_set(&cache->quiescing_ack, 0);
 }
 
 static void wait_for_migrations(struct cache *cache)
@@ -1420,16 +1510,15 @@ static void do_worker(struct work_struct *ws)
        struct cache *cache = container_of(ws, struct cache, worker);
 
        do {
-               if (!is_quiescing(cache))
+               if (!is_quiescing(cache)) {
+                       writeback_some_dirty_blocks(cache);
+                       process_deferred_writethrough_bios(cache);
                        process_deferred_bios(cache);
+               }
 
                process_migrations(cache, &cache->quiesced_migrations, issue_copy);
                process_migrations(cache, &cache->completed_migrations, complete_migration);
 
-               writeback_some_dirty_blocks(cache);
-
-               process_deferred_writethrough_bios(cache);
-
                if (commit_if_needed(cache)) {
                        process_deferred_flush_bios(cache, false);
 
@@ -1442,6 +1531,9 @@ static void do_worker(struct work_struct *ws)
                        process_migrations(cache, &cache->need_commit_migrations,
                                           migration_success_post_commit);
                }
+
+               ack_quiescing(cache);
+
        } while (more_work(cache));
 }
 
@@ -1872,14 +1964,15 @@ static int set_config_values(struct cache *cache, int argc, const char **argv)
 static int create_cache_policy(struct cache *cache, struct cache_args *ca,
                               char **error)
 {
-       cache->policy = dm_cache_policy_create(ca->policy_name,
-                                              cache->cache_size,
-                                              cache->origin_sectors,
-                                              cache->sectors_per_block);
-       if (!cache->policy) {
+       struct dm_cache_policy *p = dm_cache_policy_create(ca->policy_name,
+                                                          cache->cache_size,
+                                                          cache->origin_sectors,
+                                                          cache->sectors_per_block);
+       if (IS_ERR(p)) {
                *error = "Error creating cache's policy";
-               return -ENOMEM;
+               return PTR_ERR(p);
        }
+       cache->policy = p;
 
        return 0;
 }
@@ -2005,6 +2098,10 @@ static int cache_create(struct cache_args *ca, struct cache **result)
        atomic_set(&cache->nr_migrations, 0);
        init_waitqueue_head(&cache->migration_wait);
 
+       init_waitqueue_head(&cache->quiescing_wait);
+       atomic_set(&cache->quiescing, 0);
+       atomic_set(&cache->quiescing_ack, 0);
+
        r = -ENOMEM;
        cache->nr_dirty = 0;
        cache->dirty_bitset = alloc_bitset(from_cblock(cache->cache_size));
@@ -2064,7 +2161,6 @@ static int cache_create(struct cache_args *ca, struct cache **result)
 
        cache->need_tick_bio = true;
        cache->sized = false;
-       cache->quiescing = false;
        cache->commit_requested = false;
        cache->loaded_mappings = false;
        cache->loaded_discards = false;
@@ -2406,26 +2502,71 @@ static int load_discard(void *context, sector_t discard_block_size,
        return 0;
 }
 
+static dm_cblock_t get_cache_dev_size(struct cache *cache)
+{
+       sector_t size = get_dev_size(cache->cache_dev);
+       (void) sector_div(size, cache->sectors_per_block);
+       return to_cblock(size);
+}
+
+static bool can_resize(struct cache *cache, dm_cblock_t new_size)
+{
+       if (from_cblock(new_size) > from_cblock(cache->cache_size))
+               return true;
+
+       /*
+        * We can't drop a dirty block when shrinking the cache.
+        */
+       while (from_cblock(new_size) < from_cblock(cache->cache_size)) {
+               new_size = to_cblock(from_cblock(new_size) + 1);
+               if (is_dirty(cache, new_size)) {
+                       DMERR("unable to shrink cache; cache block %llu is dirty",
+                             (unsigned long long) from_cblock(new_size));
+                       return false;
+               }
+       }
+
+       return true;
+}
+
+static int resize_cache_dev(struct cache *cache, dm_cblock_t new_size)
+{
+       int r;
+
+       r = dm_cache_resize(cache->cmd, cache->cache_size);
+       if (r) {
+               DMERR("could not resize cache metadata");
+               return r;
+       }
+
+       cache->cache_size = new_size;
+
+       return 0;
+}
+
 static int cache_preresume(struct dm_target *ti)
 {
        int r = 0;
        struct cache *cache = ti->private;
-       sector_t actual_cache_size = get_dev_size(cache->cache_dev);
-       (void) sector_div(actual_cache_size, cache->sectors_per_block);
+       dm_cblock_t csize = get_cache_dev_size(cache);
 
        /*
         * Check to see if the cache has resized.
         */
-       if (from_cblock(cache->cache_size) != actual_cache_size || !cache->sized) {
-               cache->cache_size = to_cblock(actual_cache_size);
-
-               r = dm_cache_resize(cache->cmd, cache->cache_size);
-               if (r) {
-                       DMERR("could not resize cache metadata");
+       if (!cache->sized) {
+               r = resize_cache_dev(cache, csize);
+               if (r)
                        return r;
-               }
 
                cache->sized = true;
+
+       } else if (csize != cache->cache_size) {
+               if (!can_resize(cache, csize))
+                       return -EINVAL;
+
+               r = resize_cache_dev(cache, csize);
+               if (r)
+                       return r;
        }
 
        if (!cache->loaded_mappings) {