Merge tag 'libnvdimm-for-4.19_misc' of gitolite.kernel.org:pub/scm/linux/kernel/git...
[platform/kernel/linux-rpi.git] / drivers / md / dm-writecache.c
index 1839236..5f1f80d 100644 (file)
@@ -136,6 +136,7 @@ struct dm_writecache {
        struct dm_target *ti;
        struct dm_dev *dev;
        struct dm_dev *ssd_dev;
+       sector_t start_sector;
        void *memory_map;
        uint64_t memory_map_size;
        size_t metadata_sectors;
@@ -259,7 +260,7 @@ static int persistent_memory_claim(struct dm_writecache *wc)
        if (da != p) {
                long i;
                wc->memory_map = NULL;
-               pages = kvmalloc(p * sizeof(struct page *), GFP_KERNEL);
+               pages = kvmalloc_array(p, sizeof(struct page *), GFP_KERNEL);
                if (!pages) {
                        r = -ENOMEM;
                        goto err2;
@@ -292,6 +293,10 @@ static int persistent_memory_claim(struct dm_writecache *wc)
        }
 
        dax_read_unlock(id);
+
+       wc->memory_map += (size_t)wc->start_sector << SECTOR_SHIFT;
+       wc->memory_map_size -= (size_t)wc->start_sector << SECTOR_SHIFT;
+
        return 0;
 err3:
        kvfree(pages);
@@ -310,7 +315,7 @@ static int persistent_memory_claim(struct dm_writecache *wc)
 static void persistent_memory_release(struct dm_writecache *wc)
 {
        if (wc->memory_vmapped)
-               vunmap(wc->memory_map);
+               vunmap(wc->memory_map - ((size_t)wc->start_sector << SECTOR_SHIFT));
 }
 
 static struct page *persistent_memory_page(void *addr)
@@ -358,7 +363,7 @@ static void *memory_data(struct dm_writecache *wc, struct wc_entry *e)
 
 static sector_t cache_sector(struct dm_writecache *wc, struct wc_entry *e)
 {
-       return wc->metadata_sectors +
+       return wc->start_sector + wc->metadata_sectors +
                ((sector_t)e->index << (wc->block_size_bits - SECTOR_SHIFT));
 }
 
@@ -451,7 +456,7 @@ static void ssd_commit_flushed(struct dm_writecache *wc)
                COMPLETION_INITIALIZER_ONSTACK(endio.c),
                ATOMIC_INIT(1),
        };
-       unsigned bitmap_bits = wc->dirty_bitmap_size * BITS_PER_LONG;
+       unsigned bitmap_bits = wc->dirty_bitmap_size * 8;
        unsigned i = 0;
 
        while (1) {
@@ -470,6 +475,7 @@ static void ssd_commit_flushed(struct dm_writecache *wc)
                if (unlikely(region.sector + region.count > wc->metadata_sectors))
                        region.count = wc->metadata_sectors - region.sector;
 
+               region.sector += wc->start_sector;
                atomic_inc(&endio.count);
                req.bi_op = REQ_OP_WRITE;
                req.bi_op_flags = REQ_SYNC;
@@ -858,7 +864,7 @@ static int writecache_alloc_entries(struct dm_writecache *wc)
 
        if (wc->entries)
                return 0;
-       wc->entries = vmalloc(sizeof(struct wc_entry) * wc->n_blocks);
+       wc->entries = vmalloc(array_size(sizeof(struct wc_entry), wc->n_blocks));
        if (!wc->entries)
                return -ENOMEM;
        for (b = 0; b < wc->n_blocks; b++) {
@@ -1480,9 +1486,9 @@ static void __writecache_writeback_pmem(struct dm_writecache *wc, struct writeba
                wb->bio.bi_iter.bi_sector = read_original_sector(wc, e);
                wb->page_offset = PAGE_SIZE;
                if (max_pages <= WB_LIST_INLINE ||
-                   unlikely(!(wb->wc_list = kmalloc(max_pages * sizeof(struct wc_entry *),
-                                                    GFP_NOIO | __GFP_NORETRY |
-                                                    __GFP_NOMEMALLOC | __GFP_NOWARN)))) {
+                   unlikely(!(wb->wc_list = kmalloc_array(max_pages, sizeof(struct wc_entry *),
+                                                          GFP_NOIO | __GFP_NORETRY |
+                                                          __GFP_NOMEMALLOC | __GFP_NOWARN)))) {
                        wb->wc_list = wb->wc_list_inline;
                        max_pages = WB_LIST_INLINE;
                }
@@ -1945,14 +1951,6 @@ static int writecache_ctr(struct dm_target *ti, unsigned argc, char **argv)
        }
        wc->memory_map_size = i_size_read(wc->ssd_dev->bdev->bd_inode);
 
-       if (WC_MODE_PMEM(wc)) {
-               r = persistent_memory_claim(wc);
-               if (r) {
-                       ti->error = "Unable to map persistent memory for cache";
-                       goto bad;
-               }
-       }
-
        /*
         * Parse the cache block size
         */
@@ -1981,7 +1979,16 @@ static int writecache_ctr(struct dm_target *ti, unsigned argc, char **argv)
 
        while (opt_params) {
                string = dm_shift_arg(&as), opt_params--;
-               if (!strcasecmp(string, "high_watermark") && opt_params >= 1) {
+               if (!strcasecmp(string, "start_sector") && opt_params >= 1) {
+                       unsigned long long start_sector;
+                       string = dm_shift_arg(&as), opt_params--;
+                       if (sscanf(string, "%llu%c", &start_sector, &dummy) != 1)
+                               goto invalid_optional;
+                       wc->start_sector = start_sector;
+                       if (wc->start_sector != start_sector ||
+                           wc->start_sector >= wc->memory_map_size >> SECTOR_SHIFT)
+                               goto invalid_optional;
+               } else if (!strcasecmp(string, "high_watermark") && opt_params >= 1) {
                        string = dm_shift_arg(&as), opt_params--;
                        if (sscanf(string, "%d%c", &high_wm_percent, &dummy) != 1)
                                goto invalid_optional;
@@ -2038,12 +2045,20 @@ invalid_optional:
                goto bad;
        }
 
-       if (!WC_MODE_PMEM(wc)) {
+       if (WC_MODE_PMEM(wc)) {
+               r = persistent_memory_claim(wc);
+               if (r) {
+                       ti->error = "Unable to map persistent memory for cache";
+                       goto bad;
+               }
+       } else {
                struct dm_io_region region;
                struct dm_io_request req;
                size_t n_blocks, n_metadata_blocks;
                uint64_t n_bitmap_bits;
 
+               wc->memory_map_size -= (uint64_t)wc->start_sector << SECTOR_SHIFT;
+
                bio_list_init(&wc->flush_list);
                wc->flush_thread = kthread_create(writecache_flush_thread, wc, "dm_writecache_flush");
                if (IS_ERR(wc->flush_thread)) {
@@ -2096,7 +2111,7 @@ invalid_optional:
                }
 
                region.bdev = wc->ssd_dev->bdev;
-               region.sector = 0;
+               region.sector = wc->start_sector;
                region.count = wc->metadata_sectors;
                req.bi_op = REQ_OP_READ;
                req.bi_op_flags = REQ_SYNC;
@@ -2224,6 +2239,8 @@ static void writecache_status(struct dm_target *ti, status_type_t type,
                DMEMIT("%c %s %s %u ", WC_MODE_PMEM(wc) ? 'p' : 's',
                                wc->dev->name, wc->ssd_dev->name, wc->block_size);
                extra_args = 0;
+               if (wc->start_sector)
+                       extra_args += 2;
                if (wc->high_wm_percent_set)
                        extra_args += 2;
                if (wc->low_wm_percent_set)
@@ -2238,6 +2255,8 @@ static void writecache_status(struct dm_target *ti, status_type_t type,
                        extra_args++;
 
                DMEMIT("%u", extra_args);
+               if (wc->start_sector)
+                       DMEMIT(" start_sector %llu", (unsigned long long)wc->start_sector);
                if (wc->high_wm_percent_set) {
                        x = (uint64_t)wc->freelist_high_watermark * 100;
                        x += wc->n_blocks / 2;
@@ -2264,7 +2283,7 @@ static void writecache_status(struct dm_target *ti, status_type_t type,
 
 static struct target_type writecache_target = {
        .name                   = "writecache",
-       .version                = {1, 0, 0},
+       .version                = {1, 1, 1},
        .module                 = THIS_MODULE,
        .ctr                    = writecache_ctr,
        .dtr                    = writecache_dtr,