diff options
Diffstat (limited to 'drivers/staging/zram/zram_drv.c')
-rw-r--r-- | drivers/staging/zram/zram_drv.c | 294 |
1 files changed, 130 insertions, 164 deletions
diff --git a/drivers/staging/zram/zram_drv.c b/drivers/staging/zram/zram_drv.c index f2a73bd739fb..5918fd7d7e36 100644 --- a/drivers/staging/zram/zram_drv.c +++ b/drivers/staging/zram/zram_drv.c @@ -40,17 +40,7 @@ static int zram_major; struct zram *zram_devices; /* Module params (documentation at end) */ -static unsigned int num_devices; - -static void zram_stat_inc(u32 *v) -{ - *v = *v + 1; -} - -static void zram_stat_dec(u32 *v) -{ - *v = *v - 1; -} +static unsigned int num_devices = 1; static void zram_stat64_add(struct zram *zram, u64 *v, u64 inc) { @@ -71,22 +61,22 @@ static void zram_stat64_inc(struct zram *zram, u64 *v) zram_stat64_add(zram, v, 1); } -static int zram_test_flag(struct zram *zram, u32 index, +static int zram_test_flag(struct zram_meta *meta, u32 index, enum zram_pageflags flag) { - return zram->table[index].flags & BIT(flag); + return meta->table[index].flags & BIT(flag); } -static void zram_set_flag(struct zram *zram, u32 index, +static void zram_set_flag(struct zram_meta *meta, u32 index, enum zram_pageflags flag) { - zram->table[index].flags |= BIT(flag); + meta->table[index].flags |= BIT(flag); } -static void zram_clear_flag(struct zram *zram, u32 index, +static void zram_clear_flag(struct zram_meta *meta, u32 index, enum zram_pageflags flag) { - zram->table[index].flags &= ~BIT(flag); + meta->table[index].flags &= ~BIT(flag); } static int page_zero_filled(void *ptr) @@ -104,66 +94,38 @@ static int page_zero_filled(void *ptr) return 1; } -static void zram_set_disksize(struct zram *zram, size_t totalram_bytes) -{ - if (!zram->disksize) { - pr_info( - "disk size not provided. You can use disksize_kb module " - "param to specify size.\nUsing default: (%u%% of RAM).\n", - default_disksize_perc_ram - ); - zram->disksize = default_disksize_perc_ram * - (totalram_bytes / 100); - } - - if (zram->disksize > 2 * (totalram_bytes)) { - pr_info( - "There is little point creating a zram of greater than " - "twice the size of memory since we expect a 2:1 compression " - "ratio. Note that zram uses about 0.1%% of the size of " - "the disk when not in use so a huge zram is " - "wasteful.\n" - "\tMemory Size: %zu kB\n" - "\tSize you selected: %llu kB\n" - "Continuing anyway ...\n", - totalram_bytes >> 10, zram->disksize - ); - } - - zram->disksize &= PAGE_MASK; -} - static void zram_free_page(struct zram *zram, size_t index) { - unsigned long handle = zram->table[index].handle; - u16 size = zram->table[index].size; + struct zram_meta *meta = zram->meta; + unsigned long handle = meta->table[index].handle; + u16 size = meta->table[index].size; if (unlikely(!handle)) { /* * No memory is allocated for zero filled pages. * Simply clear zero page flag. */ - if (zram_test_flag(zram, index, ZRAM_ZERO)) { - zram_clear_flag(zram, index, ZRAM_ZERO); - zram_stat_dec(&zram->stats.pages_zero); + if (zram_test_flag(meta, index, ZRAM_ZERO)) { + zram_clear_flag(meta, index, ZRAM_ZERO); + zram->stats.pages_zero--; } return; } if (unlikely(size > max_zpage_size)) - zram_stat_dec(&zram->stats.bad_compress); + zram->stats.bad_compress--; - zs_free(zram->mem_pool, handle); + zs_free(meta->mem_pool, handle); if (size <= PAGE_SIZE / 2) - zram_stat_dec(&zram->stats.good_compress); + zram->stats.good_compress--; zram_stat64_sub(zram, &zram->stats.compr_size, - zram->table[index].size); - zram_stat_dec(&zram->stats.pages_stored); + meta->table[index].size); + zram->stats.pages_stored--; - zram->table[index].handle = 0; - zram->table[index].size = 0; + meta->table[index].handle = 0; + meta->table[index].size = 0; } static void handle_zero_page(struct bio_vec *bvec) @@ -188,20 +150,21 @@ static int zram_decompress_page(struct zram *zram, char *mem, u32 index) int ret = LZO_E_OK; size_t clen = PAGE_SIZE; unsigned char *cmem; - unsigned long handle = zram->table[index].handle; + struct zram_meta *meta = zram->meta; + unsigned long handle = meta->table[index].handle; - if (!handle || zram_test_flag(zram, index, ZRAM_ZERO)) { + if (!handle || zram_test_flag(meta, index, ZRAM_ZERO)) { memset(mem, 0, PAGE_SIZE); return 0; } - cmem = zs_map_object(zram->mem_pool, handle, ZS_MM_RO); - if (zram->table[index].size == PAGE_SIZE) + cmem = zs_map_object(meta->mem_pool, handle, ZS_MM_RO); + if (meta->table[index].size == PAGE_SIZE) memcpy(mem, cmem, PAGE_SIZE); else - ret = lzo1x_decompress_safe(cmem, zram->table[index].size, + ret = lzo1x_decompress_safe(cmem, meta->table[index].size, mem, &clen); - zs_unmap_object(zram->mem_pool, handle); + zs_unmap_object(meta->mem_pool, handle); /* Should NEVER happen. Return bio error if it does. */ if (unlikely(ret != LZO_E_OK)) { @@ -219,20 +182,21 @@ static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec, int ret; struct page *page; unsigned char *user_mem, *uncmem = NULL; - + struct zram_meta *meta = zram->meta; page = bvec->bv_page; - if (unlikely(!zram->table[index].handle) || - zram_test_flag(zram, index, ZRAM_ZERO)) { + if (unlikely(!meta->table[index].handle) || + zram_test_flag(meta, index, ZRAM_ZERO)) { handle_zero_page(bvec); return 0; } - user_mem = kmap_atomic(page); if (is_partial_io(bvec)) /* Use a temporary buffer to decompress the page */ - uncmem = kmalloc(PAGE_SIZE, GFP_KERNEL); - else + uncmem = kmalloc(PAGE_SIZE, GFP_NOIO); + + user_mem = kmap_atomic(page); + if (!is_partial_io(bvec)) uncmem = user_mem; if (!uncmem) { @@ -270,18 +234,18 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, unsigned long handle; struct page *page; unsigned char *user_mem, *cmem, *src, *uncmem = NULL; + struct zram_meta *meta = zram->meta; page = bvec->bv_page; - src = zram->compress_buffer; + src = meta->compress_buffer; if (is_partial_io(bvec)) { /* * This is a partial IO. We need to read the full page * before to write the changes. */ - uncmem = kmalloc(PAGE_SIZE, GFP_KERNEL); + uncmem = kmalloc(PAGE_SIZE, GFP_NOIO); if (!uncmem) { - pr_info("Error allocating temp memory!\n"); ret = -ENOMEM; goto out; } @@ -294,8 +258,8 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, * System overwrites unused sectors. Free memory associated * with this sector now. */ - if (zram->table[index].handle || - zram_test_flag(zram, index, ZRAM_ZERO)) + if (meta->table[index].handle || + zram_test_flag(meta, index, ZRAM_ZERO)) zram_free_page(zram, index); user_mem = kmap_atomic(page); @@ -310,16 +274,17 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, } if (page_zero_filled(uncmem)) { - if (!is_partial_io(bvec)) - kunmap_atomic(user_mem); - zram_stat_inc(&zram->stats.pages_zero); - zram_set_flag(zram, index, ZRAM_ZERO); + kunmap_atomic(user_mem); + if (is_partial_io(bvec)) + kfree(uncmem); + zram->stats.pages_zero++; + zram_set_flag(meta, index, ZRAM_ZERO); ret = 0; goto out; } ret = lzo1x_1_compress(uncmem, PAGE_SIZE, src, &clen, - zram->compress_workmem); + meta->compress_workmem); if (!is_partial_io(bvec)) { kunmap_atomic(user_mem); @@ -333,21 +298,21 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, } if (unlikely(clen > max_zpage_size)) { - zram_stat_inc(&zram->stats.bad_compress); + zram->stats.bad_compress++; clen = PAGE_SIZE; src = NULL; if (is_partial_io(bvec)) src = uncmem; } - handle = zs_malloc(zram->mem_pool, clen); + handle = zs_malloc(meta->mem_pool, clen); if (!handle) { pr_info("Error allocating memory for compressed " "page: %u, size=%zu\n", index, clen); ret = -ENOMEM; goto out; } - cmem = zs_map_object(zram->mem_pool, handle, ZS_MM_WO); + cmem = zs_map_object(meta->mem_pool, handle, ZS_MM_WO); if ((clen == PAGE_SIZE) && !is_partial_io(bvec)) src = kmap_atomic(page); @@ -355,16 +320,16 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, if ((clen == PAGE_SIZE) && !is_partial_io(bvec)) kunmap_atomic(src); - zs_unmap_object(zram->mem_pool, handle); + zs_unmap_object(meta->mem_pool, handle); - zram->table[index].handle = handle; - zram->table[index].size = clen; + meta->table[index].handle = handle; + meta->table[index].size = clen; /* Update stats */ zram_stat64_add(zram, &zram->stats.compr_size, clen); - zram_stat_inc(&zram->stats.pages_stored); + zram->stats.pages_stored++; if (clen <= PAGE_SIZE / 2) - zram_stat_inc(&zram->stats.good_compress); + zram->stats.good_compress++; out: if (is_partial_io(bvec)) @@ -479,16 +444,13 @@ static void zram_make_request(struct request_queue *queue, struct bio *bio) { struct zram *zram = queue->queuedata; - if (unlikely(!zram->init_done) && zram_init_device(zram)) - goto error; - down_read(&zram->init_lock); if (unlikely(!zram->init_done)) - goto error_unlock; + goto error; if (!valid_io_request(zram, bio)) { zram_stat64_inc(zram, &zram->stats.invalid_io); - goto error_unlock; + goto error; } __zram_make_request(zram, bio, bio_data_dir(bio)); @@ -496,44 +458,38 @@ static void zram_make_request(struct request_queue *queue, struct bio *bio) return; -error_unlock: - up_read(&zram->init_lock); error: + up_read(&zram->init_lock); bio_io_error(bio); } -void __zram_reset_device(struct zram *zram) +static void __zram_reset_device(struct zram *zram) { size_t index; + struct zram_meta *meta; - zram->init_done = 0; - - /* Free various per-device buffers */ - kfree(zram->compress_workmem); - free_pages((unsigned long)zram->compress_buffer, 1); + if (!zram->init_done) + return; - zram->compress_workmem = NULL; - zram->compress_buffer = NULL; + meta = zram->meta; + zram->init_done = 0; /* Free all pages that are still in this zram device */ for (index = 0; index < zram->disksize >> PAGE_SHIFT; index++) { - unsigned long handle = zram->table[index].handle; + unsigned long handle = meta->table[index].handle; if (!handle) continue; - zs_free(zram->mem_pool, handle); + zs_free(meta->mem_pool, handle); } - vfree(zram->table); - zram->table = NULL; - - zs_destroy_pool(zram->mem_pool); - zram->mem_pool = NULL; - + zram_meta_free(zram->meta); + zram->meta = NULL; /* Reset stats */ memset(&zram->stats, 0, sizeof(zram->stats)); zram->disksize = 0; + set_capacity(zram->disk, 0); } void zram_reset_device(struct zram *zram) @@ -543,69 +499,84 @@ void zram_reset_device(struct zram *zram) up_write(&zram->init_lock); } -int zram_init_device(struct zram *zram) +void zram_meta_free(struct zram_meta *meta) { - int ret; - size_t num_pages; - - down_write(&zram->init_lock); - - if (zram->init_done) { - up_write(&zram->init_lock); - return 0; - } + zs_destroy_pool(meta->mem_pool); + kfree(meta->compress_workmem); + free_pages((unsigned long)meta->compress_buffer, 1); + vfree(meta->table); + kfree(meta); +} - zram_set_disksize(zram, totalram_pages << PAGE_SHIFT); +struct zram_meta *zram_meta_alloc(u64 disksize) +{ + size_t num_pages; + struct zram_meta *meta = kmalloc(sizeof(*meta), GFP_KERNEL); + if (!meta) + goto out; - zram->compress_workmem = kzalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL); - if (!zram->compress_workmem) { - pr_err("Error allocating compressor working memory!\n"); - ret = -ENOMEM; - goto fail_no_table; - } + meta->compress_workmem = kzalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL); + if (!meta->compress_workmem) + goto free_meta; - zram->compress_buffer = + meta->compress_buffer = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 1); - if (!zram->compress_buffer) { + if (!meta->compress_buffer) { pr_err("Error allocating compressor buffer space\n"); - ret = -ENOMEM; - goto fail_no_table; + goto free_workmem; } - num_pages = zram->disksize >> PAGE_SHIFT; - zram->table = vzalloc(num_pages * sizeof(*zram->table)); - if (!zram->table) { + num_pages = disksize >> PAGE_SHIFT; + meta->table = vzalloc(num_pages * sizeof(*meta->table)); + if (!meta->table) { pr_err("Error allocating zram address table\n"); - ret = -ENOMEM; - goto fail_no_table; + goto free_buffer; } - set_capacity(zram->disk, zram->disksize >> SECTOR_SHIFT); + meta->mem_pool = zs_create_pool(GFP_NOIO | __GFP_HIGHMEM); + if (!meta->mem_pool) { + pr_err("Error creating memory pool\n"); + goto free_table; + } - /* zram devices sort of resembles non-rotational disks */ - queue_flag_set_unlocked(QUEUE_FLAG_NONROT, zram->disk->queue); + return meta; - zram->mem_pool = zs_create_pool("zram", GFP_NOIO | __GFP_HIGHMEM); - if (!zram->mem_pool) { - pr_err("Error creating memory pool\n"); - ret = -ENOMEM; - goto fail; +free_table: + vfree(meta->table); +free_buffer: + free_pages((unsigned long)meta->compress_buffer, 1); +free_workmem: + kfree(meta->compress_workmem); +free_meta: + kfree(meta); + meta = NULL; +out: + return meta; +} + +void zram_init_device(struct zram *zram, struct zram_meta *meta) +{ + if (zram->disksize > 2 * (totalram_pages << PAGE_SHIFT)) { + pr_info( + "There is little point creating a zram of greater than " + "twice the size of memory since we expect a 2:1 compression " + "ratio. Note that zram uses about 0.1%% of the size of " + "the disk when not in use so a huge zram is " + "wasteful.\n" + "\tMemory Size: %lu kB\n" + "\tSize you selected: %llu kB\n" + "Continuing anyway ...\n", + (totalram_pages << PAGE_SHIFT) >> 10, zram->disksize >> 10 + ); } + /* zram devices sort of resembles non-rotational disks */ + queue_flag_set_unlocked(QUEUE_FLAG_NONROT, zram->disk->queue); + + zram->meta = meta; zram->init_done = 1; - up_write(&zram->init_lock); pr_debug("Initialization done!\n"); - return 0; - -fail_no_table: - /* To prevent accessing table entries during cleanup */ - zram->disksize = 0; -fail: - __zram_reset_device(zram); - up_write(&zram->init_lock); - pr_err("Initialization failed: err=%d\n", ret); - return ret; } static void zram_slot_free_notify(struct block_device *bdev, @@ -724,13 +695,7 @@ static int __init zram_init(void) goto out; } - if (!num_devices) { - pr_info("num_devices not specified. Using default: 1\n"); - num_devices = 1; - } - /* Allocate the device array and initialize each one */ - pr_info("Creating %u devices ...\n", num_devices); zram_devices = kzalloc(num_devices * sizeof(struct zram), GFP_KERNEL); if (!zram_devices) { ret = -ENOMEM; @@ -743,6 +708,8 @@ static int __init zram_init(void) goto free_devices; } + pr_info("Created %u device(s) ...\n", num_devices); + return 0; free_devices: @@ -764,8 +731,7 @@ static void __exit zram_exit(void) zram = &zram_devices[i]; destroy_device(zram); - if (zram->init_done) - zram_reset_device(zram); + zram_reset_device(zram); } unregister_blkdev(zram_major, "zram"); |