raid5-cache: use a mempool for the metadata block
[deliverable/linux.git] / drivers / md / raid5-cache.c
index b887e04d7e5c2554b3112de0f9fa5e61b93ed40b..fa2d6321f3a4b73e065fdc963828b3e25e168154 100644 (file)
 #define RECLAIM_MAX_FREE_SPACE (10 * 1024 * 1024 * 2) /* sector */
 #define RECLAIM_MAX_FREE_SPACE_SHIFT (2)
 
+/*
+ * We only need 2 bios per I/O unit to make progress, but ensure we
+ * have a few more available to not get too tight.
+ */
+#define R5L_POOL_SIZE  4
+
 struct r5l_log {
        struct md_rdev *rdev;
 
@@ -70,6 +76,8 @@ struct r5l_log {
        struct bio flush_bio;
 
        struct kmem_cache *io_kc;
+       struct bio_set *bs;
+       mempool_t *meta_pool;
 
        struct md_thread *reclaim_thread;
        unsigned long reclaim_target;   /* number of space that need to be
@@ -150,27 +158,6 @@ static bool r5l_has_free_space(struct r5l_log *log, sector_t size)
        return log->device_size > used_size + size;
 }
 
-static void r5l_free_io_unit(struct r5l_log *log, struct r5l_io_unit *io)
-{
-       __free_page(io->meta_page);
-       kmem_cache_free(log->io_kc, io);
-}
-
-static void r5l_move_io_unit_list(struct list_head *from, struct list_head *to,
-                                 enum r5l_io_unit_state state)
-{
-       struct r5l_io_unit *io;
-
-       while (!list_empty(from)) {
-               io = list_first_entry(from, struct r5l_io_unit, log_sibling);
-               /* don't change list order */
-               if (io->state >= state)
-                       list_move_tail(&io->log_sibling, to);
-               else
-                       break;
-       }
-}
-
 static void __r5l_set_io_unit_state(struct r5l_io_unit *io,
                                    enum r5l_io_unit_state state)
 {
@@ -206,6 +193,20 @@ static void r5l_log_run_stripes(struct r5l_log *log)
        }
 }
 
+static void r5l_move_to_end_ios(struct r5l_log *log)
+{
+       struct r5l_io_unit *io, *next;
+
+       assert_spin_locked(&log->io_list_lock);
+
+       list_for_each_entry_safe(io, next, &log->running_ios, log_sibling) {
+               /* don't change list order */
+               if (io->state < IO_UNIT_IO_END)
+                       break;
+               list_move_tail(&io->log_sibling, &log->io_end_ios);
+       }
+}
+
 static void r5l_log_endio(struct bio *bio)
 {
        struct r5l_io_unit *io = bio->bi_private;
@@ -216,12 +217,12 @@ static void r5l_log_endio(struct bio *bio)
                md_error(log->rdev->mddev, log->rdev);
 
        bio_put(bio);
+       mempool_free(io->meta_page, log->meta_pool);
 
        spin_lock_irqsave(&log->io_list_lock, flags);
        __r5l_set_io_unit_state(io, IO_UNIT_IO_END);
        if (log->need_cache_flush)
-               r5l_move_io_unit_list(&log->running_ios, &log->io_end_ios,
-                                     IO_UNIT_IO_END);
+               r5l_move_to_end_ios(log);
        else
                r5l_log_run_stripes(log);
        spin_unlock_irqrestore(&log->io_list_lock, flags);
@@ -255,7 +256,7 @@ static void r5l_submit_current_io(struct r5l_log *log)
 
 static struct bio *r5l_bio_alloc(struct r5l_log *log)
 {
-       struct bio *bio = bio_kmalloc(GFP_NOIO | __GFP_NOFAIL, BIO_MAX_PAGES);
+       struct bio *bio = bio_alloc_bioset(GFP_NOIO, BIO_MAX_PAGES, log->bs);
 
        bio->bi_rw = WRITE;
        bio->bi_bdev = log->rdev->bdev;
@@ -293,8 +294,9 @@ static struct r5l_io_unit *r5l_new_meta(struct r5l_log *log)
        INIT_LIST_HEAD(&io->stripe_list);
        io->state = IO_UNIT_RUNNING;
 
-       io->meta_page = alloc_page(GFP_NOIO | __GFP_NOFAIL | __GFP_ZERO);
+       io->meta_page = mempool_alloc(log->meta_pool, GFP_NOIO);
        block = page_address(io->meta_page);
+       clear_page(block);
        block->magic = cpu_to_le32(R5LOG_MAGIC);
        block->version = R5LOG_VERSION;
        block->seq = cpu_to_le64(log->seq);
@@ -554,7 +556,7 @@ static bool r5l_complete_finished_ios(struct r5l_log *log)
                log->next_cp_seq = io->seq;
 
                list_del(&io->log_sibling);
-               r5l_free_io_unit(log, io);
+               kmem_cache_free(log->io_kc, io);
 
                found = true;
        }
@@ -806,10 +808,18 @@ void r5l_quiesce(struct r5l_log *log, int state)
 
 bool r5l_log_disk_error(struct r5conf *conf)
 {
+       struct r5l_log *log;
+       bool ret;
        /* don't allow write if journal disk is missing */
-       if (!conf->log)
-               return test_bit(MD_HAS_JOURNAL, &conf->mddev->flags);
-       return test_bit(Faulty, &conf->log->rdev->flags);
+       rcu_read_lock();
+       log = rcu_dereference(conf->log);
+
+       if (!log)
+               ret = test_bit(MD_HAS_JOURNAL, &conf->mddev->flags);
+       else
+               ret = test_bit(Faulty, &log->rdev->flags);
+       rcu_read_unlock();
+       return ret;
 }
 
 struct r5l_recovery_ctx {
@@ -1160,6 +1170,14 @@ int r5l_init_log(struct r5conf *conf, struct md_rdev *rdev)
        if (!log->io_kc)
                goto io_kc;
 
+       log->bs = bioset_create(R5L_POOL_SIZE, 0);
+       if (!log->bs)
+               goto io_bs;
+
+       log->meta_pool = mempool_create_page_pool(R5L_POOL_SIZE, 0);
+       if (!log->meta_pool)
+               goto out_mempool;
+
        log->reclaim_thread = md_register_thread(r5l_reclaim_thread,
                                                 log->rdev->mddev, "reclaim");
        if (!log->reclaim_thread)
@@ -1172,11 +1190,16 @@ int r5l_init_log(struct r5conf *conf, struct md_rdev *rdev)
        if (r5l_load_log(log))
                goto error;
 
-       conf->log = log;
+       rcu_assign_pointer(conf->log, log);
        return 0;
+
 error:
        md_unregister_thread(&log->reclaim_thread);
 reclaim_thread:
+       mempool_destroy(log->meta_pool);
+out_mempool:
+       bioset_free(log->bs);
+io_bs:
        kmem_cache_destroy(log->io_kc);
 io_kc:
        kfree(log);
@@ -1186,6 +1209,8 @@ io_kc:
 void r5l_exit_log(struct r5l_log *log)
 {
        md_unregister_thread(&log->reclaim_thread);
+       mempool_destroy(log->meta_pool);
+       bioset_free(log->bs);
        kmem_cache_destroy(log->io_kc);
        kfree(log);
 }
This page took 0.027753 seconds and 5 git commands to generate.