18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Compressed RAM block device 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2008, 2009, 2010 Nitin Gupta 58c2ecf20Sopenharmony_ci * 2012, 2013 Minchan Kim 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * This code is released using a dual license strategy: BSD/GPL 88c2ecf20Sopenharmony_ci * You can choose the licence that better fits your requirements. 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Released under the terms of 3-clause BSD License 118c2ecf20Sopenharmony_ci * Released under the terms of GNU General Public License Version 2.0 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#define KMSG_COMPONENT "zram" 168c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <linux/module.h> 198c2ecf20Sopenharmony_ci#include <linux/kernel.h> 208c2ecf20Sopenharmony_ci#include <linux/bio.h> 218c2ecf20Sopenharmony_ci#include <linux/bitops.h> 228c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 238c2ecf20Sopenharmony_ci#include <linux/buffer_head.h> 248c2ecf20Sopenharmony_ci#include <linux/device.h> 258c2ecf20Sopenharmony_ci#include <linux/genhd.h> 268c2ecf20Sopenharmony_ci#include <linux/highmem.h> 278c2ecf20Sopenharmony_ci#include <linux/slab.h> 288c2ecf20Sopenharmony_ci#include <linux/backing-dev.h> 298c2ecf20Sopenharmony_ci#include <linux/string.h> 308c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 318c2ecf20Sopenharmony_ci#include <linux/err.h> 328c2ecf20Sopenharmony_ci#include <linux/idr.h> 338c2ecf20Sopenharmony_ci#include <linux/sysfs.h> 348c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 358c2ecf20Sopenharmony_ci#include <linux/cpuhotplug.h> 368c2ecf20Sopenharmony_ci#include <linux/part_stat.h> 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#ifdef CONFIG_ZRAM_GROUP 398c2ecf20Sopenharmony_ci#include <linux/memcontrol.h> 408c2ecf20Sopenharmony_ci#endif 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#include "zram_drv.h" 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic DEFINE_IDR(zram_index_idr); 458c2ecf20Sopenharmony_ci/* idr index must be protected */ 468c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(zram_index_mutex); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic int zram_major; 498c2ecf20Sopenharmony_cistatic const char *default_compressor = "lzo-rle"; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci/* Module params (documentation at end) */ 528c2ecf20Sopenharmony_cistatic unsigned int num_devices = 1; 538c2ecf20Sopenharmony_ci/* 548c2ecf20Sopenharmony_ci * Pages that compress to sizes equals or greater than this are stored 558c2ecf20Sopenharmony_ci * uncompressed in memory. 568c2ecf20Sopenharmony_ci */ 578c2ecf20Sopenharmony_cistatic size_t huge_class_size; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic const struct block_device_operations zram_devops; 608c2ecf20Sopenharmony_cistatic const struct block_device_operations zram_wb_devops; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic void zram_free_page(struct zram *zram, size_t index); 638c2ecf20Sopenharmony_cistatic int zram_bvec_read(struct zram *zram, struct bio_vec *bvec, 648c2ecf20Sopenharmony_ci u32 index, int offset, struct bio *bio); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic inline bool init_done(struct zram *zram) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci return zram->disksize; 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic inline struct zram *dev_to_zram(struct device *dev) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci return (struct zram *)dev_to_disk(dev)->private_data; 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic inline void zram_set_element(struct zram *zram, u32 index, 778c2ecf20Sopenharmony_ci unsigned long element) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci zram->table[index].element = element; 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic unsigned long zram_get_element(struct zram *zram, u32 index) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci return zram->table[index].element; 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic inline bool zram_allocated(struct zram *zram, u32 index) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci return zram_get_obj_size(zram, index) || 908c2ecf20Sopenharmony_ci zram_test_flag(zram, index, ZRAM_SAME) || 918c2ecf20Sopenharmony_ci zram_test_flag(zram, index, ZRAM_WB); 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci#if PAGE_SIZE != 4096 958c2ecf20Sopenharmony_cistatic inline bool is_partial_io(struct bio_vec *bvec) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci return bvec->bv_len != PAGE_SIZE; 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci#else 1008c2ecf20Sopenharmony_cistatic inline bool is_partial_io(struct bio_vec *bvec) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci return false; 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci#endif 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci/* 1078c2ecf20Sopenharmony_ci * Check if request is within bounds and aligned on zram logical blocks. 1088c2ecf20Sopenharmony_ci */ 1098c2ecf20Sopenharmony_cistatic inline bool valid_io_request(struct zram *zram, 1108c2ecf20Sopenharmony_ci sector_t start, unsigned int size) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci u64 end, bound; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci /* unaligned request */ 1158c2ecf20Sopenharmony_ci if (unlikely(start & (ZRAM_SECTOR_PER_LOGICAL_BLOCK - 1))) 1168c2ecf20Sopenharmony_ci return false; 1178c2ecf20Sopenharmony_ci if (unlikely(size & (ZRAM_LOGICAL_BLOCK_SIZE - 1))) 1188c2ecf20Sopenharmony_ci return false; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci end = start + (size >> SECTOR_SHIFT); 1218c2ecf20Sopenharmony_ci bound = zram->disksize >> SECTOR_SHIFT; 1228c2ecf20Sopenharmony_ci /* out of range range */ 1238c2ecf20Sopenharmony_ci if (unlikely(start >= bound || end > bound || start > end)) 1248c2ecf20Sopenharmony_ci return false; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci /* I/O request is valid */ 1278c2ecf20Sopenharmony_ci return true; 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic void update_position(u32 *index, int *offset, struct bio_vec *bvec) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci *index += (*offset + bvec->bv_len) / PAGE_SIZE; 1338c2ecf20Sopenharmony_ci *offset = (*offset + bvec->bv_len) % PAGE_SIZE; 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic inline void update_used_max(struct zram *zram, 1378c2ecf20Sopenharmony_ci const unsigned long pages) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci unsigned long old_max, cur_max; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci old_max = atomic_long_read(&zram->stats.max_used_pages); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci do { 1448c2ecf20Sopenharmony_ci cur_max = old_max; 1458c2ecf20Sopenharmony_ci if (pages > cur_max) 1468c2ecf20Sopenharmony_ci old_max = atomic_long_cmpxchg( 1478c2ecf20Sopenharmony_ci &zram->stats.max_used_pages, cur_max, pages); 1488c2ecf20Sopenharmony_ci } while (old_max != cur_max); 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_cistatic inline void zram_fill_page(void *ptr, unsigned long len, 1528c2ecf20Sopenharmony_ci unsigned long value) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci WARN_ON_ONCE(!IS_ALIGNED(len, sizeof(unsigned long))); 1558c2ecf20Sopenharmony_ci memset_l(ptr, value, len / sizeof(unsigned long)); 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic bool page_same_filled(void *ptr, unsigned long *element) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci unsigned long *page; 1618c2ecf20Sopenharmony_ci unsigned long val; 1628c2ecf20Sopenharmony_ci unsigned int pos, last_pos = PAGE_SIZE / sizeof(*page) - 1; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci page = (unsigned long *)ptr; 1658c2ecf20Sopenharmony_ci val = page[0]; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci if (val != page[last_pos]) 1688c2ecf20Sopenharmony_ci return false; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci for (pos = 1; pos < last_pos; pos++) { 1718c2ecf20Sopenharmony_ci if (val != page[pos]) 1728c2ecf20Sopenharmony_ci return false; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci *element = val; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci return true; 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cistatic ssize_t initstate_show(struct device *dev, 1818c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci u32 val; 1848c2ecf20Sopenharmony_ci struct zram *zram = dev_to_zram(dev); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci down_read(&zram->init_lock); 1878c2ecf20Sopenharmony_ci val = init_done(zram); 1888c2ecf20Sopenharmony_ci up_read(&zram->init_lock); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%u\n", val); 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic ssize_t disksize_show(struct device *dev, 1948c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci struct zram *zram = dev_to_zram(dev); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%llu\n", zram->disksize); 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic ssize_t mem_limit_store(struct device *dev, 2028c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t len) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci u64 limit; 2058c2ecf20Sopenharmony_ci char *tmp; 2068c2ecf20Sopenharmony_ci struct zram *zram = dev_to_zram(dev); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci limit = memparse(buf, &tmp); 2098c2ecf20Sopenharmony_ci if (buf == tmp) /* no chars parsed, invalid input */ 2108c2ecf20Sopenharmony_ci return -EINVAL; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci down_write(&zram->init_lock); 2138c2ecf20Sopenharmony_ci zram->limit_pages = PAGE_ALIGN(limit) >> PAGE_SHIFT; 2148c2ecf20Sopenharmony_ci up_write(&zram->init_lock); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci return len; 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_cistatic ssize_t mem_used_max_store(struct device *dev, 2208c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t len) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci int err; 2238c2ecf20Sopenharmony_ci unsigned long val; 2248c2ecf20Sopenharmony_ci struct zram *zram = dev_to_zram(dev); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci err = kstrtoul(buf, 10, &val); 2278c2ecf20Sopenharmony_ci if (err || val != 0) 2288c2ecf20Sopenharmony_ci return -EINVAL; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci down_read(&zram->init_lock); 2318c2ecf20Sopenharmony_ci if (init_done(zram)) { 2328c2ecf20Sopenharmony_ci atomic_long_set(&zram->stats.max_used_pages, 2338c2ecf20Sopenharmony_ci zs_get_total_pages(zram->mem_pool)); 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci up_read(&zram->init_lock); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci return len; 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cistatic ssize_t idle_store(struct device *dev, 2418c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t len) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci struct zram *zram = dev_to_zram(dev); 2448c2ecf20Sopenharmony_ci unsigned long nr_pages = zram->disksize >> PAGE_SHIFT; 2458c2ecf20Sopenharmony_ci int index; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (!sysfs_streq(buf, "all")) 2488c2ecf20Sopenharmony_ci return -EINVAL; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci down_read(&zram->init_lock); 2518c2ecf20Sopenharmony_ci if (!init_done(zram)) { 2528c2ecf20Sopenharmony_ci up_read(&zram->init_lock); 2538c2ecf20Sopenharmony_ci return -EINVAL; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci for (index = 0; index < nr_pages; index++) { 2578c2ecf20Sopenharmony_ci /* 2588c2ecf20Sopenharmony_ci * Do not mark ZRAM_UNDER_WB slot as ZRAM_IDLE to close race. 2598c2ecf20Sopenharmony_ci * See the comment in writeback_store. 2608c2ecf20Sopenharmony_ci */ 2618c2ecf20Sopenharmony_ci zram_slot_lock(zram, index); 2628c2ecf20Sopenharmony_ci if (zram_allocated(zram, index) && 2638c2ecf20Sopenharmony_ci !zram_test_flag(zram, index, ZRAM_UNDER_WB)) 2648c2ecf20Sopenharmony_ci zram_set_flag(zram, index, ZRAM_IDLE); 2658c2ecf20Sopenharmony_ci zram_slot_unlock(zram, index); 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci up_read(&zram->init_lock); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci return len; 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci#ifdef CONFIG_ZRAM_WRITEBACK 2748c2ecf20Sopenharmony_cistatic ssize_t writeback_limit_enable_store(struct device *dev, 2758c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t len) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci struct zram *zram = dev_to_zram(dev); 2788c2ecf20Sopenharmony_ci u64 val; 2798c2ecf20Sopenharmony_ci ssize_t ret = -EINVAL; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci if (kstrtoull(buf, 10, &val)) 2828c2ecf20Sopenharmony_ci return ret; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci down_read(&zram->init_lock); 2858c2ecf20Sopenharmony_ci spin_lock(&zram->wb_limit_lock); 2868c2ecf20Sopenharmony_ci zram->wb_limit_enable = val; 2878c2ecf20Sopenharmony_ci spin_unlock(&zram->wb_limit_lock); 2888c2ecf20Sopenharmony_ci up_read(&zram->init_lock); 2898c2ecf20Sopenharmony_ci ret = len; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci return ret; 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistatic ssize_t writeback_limit_enable_show(struct device *dev, 2958c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci bool val; 2988c2ecf20Sopenharmony_ci struct zram *zram = dev_to_zram(dev); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci down_read(&zram->init_lock); 3018c2ecf20Sopenharmony_ci spin_lock(&zram->wb_limit_lock); 3028c2ecf20Sopenharmony_ci val = zram->wb_limit_enable; 3038c2ecf20Sopenharmony_ci spin_unlock(&zram->wb_limit_lock); 3048c2ecf20Sopenharmony_ci up_read(&zram->init_lock); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%d\n", val); 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_cistatic ssize_t writeback_limit_store(struct device *dev, 3108c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t len) 3118c2ecf20Sopenharmony_ci{ 3128c2ecf20Sopenharmony_ci struct zram *zram = dev_to_zram(dev); 3138c2ecf20Sopenharmony_ci u64 val; 3148c2ecf20Sopenharmony_ci ssize_t ret = -EINVAL; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci if (kstrtoull(buf, 10, &val)) 3178c2ecf20Sopenharmony_ci return ret; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci down_read(&zram->init_lock); 3208c2ecf20Sopenharmony_ci spin_lock(&zram->wb_limit_lock); 3218c2ecf20Sopenharmony_ci zram->bd_wb_limit = val; 3228c2ecf20Sopenharmony_ci spin_unlock(&zram->wb_limit_lock); 3238c2ecf20Sopenharmony_ci up_read(&zram->init_lock); 3248c2ecf20Sopenharmony_ci ret = len; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci return ret; 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistatic ssize_t writeback_limit_show(struct device *dev, 3308c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 3318c2ecf20Sopenharmony_ci{ 3328c2ecf20Sopenharmony_ci u64 val; 3338c2ecf20Sopenharmony_ci struct zram *zram = dev_to_zram(dev); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci down_read(&zram->init_lock); 3368c2ecf20Sopenharmony_ci spin_lock(&zram->wb_limit_lock); 3378c2ecf20Sopenharmony_ci val = zram->bd_wb_limit; 3388c2ecf20Sopenharmony_ci spin_unlock(&zram->wb_limit_lock); 3398c2ecf20Sopenharmony_ci up_read(&zram->init_lock); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%llu\n", val); 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cistatic void reset_bdev(struct zram *zram) 3458c2ecf20Sopenharmony_ci{ 3468c2ecf20Sopenharmony_ci struct block_device *bdev; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci if (!zram->backing_dev) 3498c2ecf20Sopenharmony_ci return; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci bdev = zram->bdev; 3528c2ecf20Sopenharmony_ci if (zram->old_block_size) 3538c2ecf20Sopenharmony_ci set_blocksize(bdev, zram->old_block_size); 3548c2ecf20Sopenharmony_ci blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL); 3558c2ecf20Sopenharmony_ci /* hope filp_close flush all of IO */ 3568c2ecf20Sopenharmony_ci filp_close(zram->backing_dev, NULL); 3578c2ecf20Sopenharmony_ci zram->backing_dev = NULL; 3588c2ecf20Sopenharmony_ci zram->old_block_size = 0; 3598c2ecf20Sopenharmony_ci zram->bdev = NULL; 3608c2ecf20Sopenharmony_ci zram->disk->fops = &zram_devops; 3618c2ecf20Sopenharmony_ci kvfree(zram->bitmap); 3628c2ecf20Sopenharmony_ci zram->bitmap = NULL; 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_cistatic ssize_t backing_dev_show(struct device *dev, 3668c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci struct file *file; 3698c2ecf20Sopenharmony_ci struct zram *zram = dev_to_zram(dev); 3708c2ecf20Sopenharmony_ci char *p; 3718c2ecf20Sopenharmony_ci ssize_t ret; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci down_read(&zram->init_lock); 3748c2ecf20Sopenharmony_ci file = zram->backing_dev; 3758c2ecf20Sopenharmony_ci if (!file) { 3768c2ecf20Sopenharmony_ci memcpy(buf, "none\n", 5); 3778c2ecf20Sopenharmony_ci up_read(&zram->init_lock); 3788c2ecf20Sopenharmony_ci return 5; 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci p = file_path(file, buf, PAGE_SIZE - 1); 3828c2ecf20Sopenharmony_ci if (IS_ERR(p)) { 3838c2ecf20Sopenharmony_ci ret = PTR_ERR(p); 3848c2ecf20Sopenharmony_ci goto out; 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci ret = strlen(p); 3888c2ecf20Sopenharmony_ci memmove(buf, p, ret); 3898c2ecf20Sopenharmony_ci buf[ret++] = '\n'; 3908c2ecf20Sopenharmony_ciout: 3918c2ecf20Sopenharmony_ci up_read(&zram->init_lock); 3928c2ecf20Sopenharmony_ci return ret; 3938c2ecf20Sopenharmony_ci} 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_cistatic ssize_t backing_dev_store(struct device *dev, 3968c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t len) 3978c2ecf20Sopenharmony_ci{ 3988c2ecf20Sopenharmony_ci char *file_name; 3998c2ecf20Sopenharmony_ci size_t sz; 4008c2ecf20Sopenharmony_ci struct file *backing_dev = NULL; 4018c2ecf20Sopenharmony_ci struct inode *inode; 4028c2ecf20Sopenharmony_ci struct address_space *mapping; 4038c2ecf20Sopenharmony_ci unsigned int bitmap_sz, old_block_size = 0; 4048c2ecf20Sopenharmony_ci unsigned long nr_pages, *bitmap = NULL; 4058c2ecf20Sopenharmony_ci struct block_device *bdev = NULL; 4068c2ecf20Sopenharmony_ci int err; 4078c2ecf20Sopenharmony_ci struct zram *zram = dev_to_zram(dev); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci file_name = kmalloc(PATH_MAX, GFP_KERNEL); 4108c2ecf20Sopenharmony_ci if (!file_name) 4118c2ecf20Sopenharmony_ci return -ENOMEM; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci down_write(&zram->init_lock); 4148c2ecf20Sopenharmony_ci if (init_done(zram)) { 4158c2ecf20Sopenharmony_ci pr_info("Can't setup backing device for initialized device\n"); 4168c2ecf20Sopenharmony_ci err = -EBUSY; 4178c2ecf20Sopenharmony_ci goto out; 4188c2ecf20Sopenharmony_ci } 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci strlcpy(file_name, buf, PATH_MAX); 4218c2ecf20Sopenharmony_ci /* ignore trailing newline */ 4228c2ecf20Sopenharmony_ci sz = strlen(file_name); 4238c2ecf20Sopenharmony_ci if (sz > 0 && file_name[sz - 1] == '\n') 4248c2ecf20Sopenharmony_ci file_name[sz - 1] = 0x00; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci backing_dev = filp_open(file_name, O_RDWR|O_LARGEFILE, 0); 4278c2ecf20Sopenharmony_ci if (IS_ERR(backing_dev)) { 4288c2ecf20Sopenharmony_ci err = PTR_ERR(backing_dev); 4298c2ecf20Sopenharmony_ci backing_dev = NULL; 4308c2ecf20Sopenharmony_ci goto out; 4318c2ecf20Sopenharmony_ci } 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci mapping = backing_dev->f_mapping; 4348c2ecf20Sopenharmony_ci inode = mapping->host; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci /* Support only block device in this moment */ 4378c2ecf20Sopenharmony_ci if (!S_ISBLK(inode->i_mode)) { 4388c2ecf20Sopenharmony_ci err = -ENOTBLK; 4398c2ecf20Sopenharmony_ci goto out; 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci bdev = blkdev_get_by_dev(inode->i_rdev, 4438c2ecf20Sopenharmony_ci FMODE_READ | FMODE_WRITE | FMODE_EXCL, zram); 4448c2ecf20Sopenharmony_ci if (IS_ERR(bdev)) { 4458c2ecf20Sopenharmony_ci err = PTR_ERR(bdev); 4468c2ecf20Sopenharmony_ci bdev = NULL; 4478c2ecf20Sopenharmony_ci goto out; 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci nr_pages = i_size_read(inode) >> PAGE_SHIFT; 4518c2ecf20Sopenharmony_ci bitmap_sz = BITS_TO_LONGS(nr_pages) * sizeof(long); 4528c2ecf20Sopenharmony_ci bitmap = kvzalloc(bitmap_sz, GFP_KERNEL); 4538c2ecf20Sopenharmony_ci if (!bitmap) { 4548c2ecf20Sopenharmony_ci err = -ENOMEM; 4558c2ecf20Sopenharmony_ci goto out; 4568c2ecf20Sopenharmony_ci } 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci old_block_size = block_size(bdev); 4598c2ecf20Sopenharmony_ci err = set_blocksize(bdev, PAGE_SIZE); 4608c2ecf20Sopenharmony_ci if (err) 4618c2ecf20Sopenharmony_ci goto out; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci reset_bdev(zram); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci zram->old_block_size = old_block_size; 4668c2ecf20Sopenharmony_ci zram->bdev = bdev; 4678c2ecf20Sopenharmony_ci zram->backing_dev = backing_dev; 4688c2ecf20Sopenharmony_ci zram->bitmap = bitmap; 4698c2ecf20Sopenharmony_ci zram->nr_pages = nr_pages; 4708c2ecf20Sopenharmony_ci /* 4718c2ecf20Sopenharmony_ci * With writeback feature, zram does asynchronous IO so it's no longer 4728c2ecf20Sopenharmony_ci * synchronous device so let's remove synchronous io flag. Othewise, 4738c2ecf20Sopenharmony_ci * upper layer(e.g., swap) could wait IO completion rather than 4748c2ecf20Sopenharmony_ci * (submit and return), which will cause system sluggish. 4758c2ecf20Sopenharmony_ci * Furthermore, when the IO function returns(e.g., swap_readpage), 4768c2ecf20Sopenharmony_ci * upper layer expects IO was done so it could deallocate the page 4778c2ecf20Sopenharmony_ci * freely but in fact, IO is going on so finally could cause 4788c2ecf20Sopenharmony_ci * use-after-free when the IO is really done. 4798c2ecf20Sopenharmony_ci */ 4808c2ecf20Sopenharmony_ci zram->disk->fops = &zram_wb_devops; 4818c2ecf20Sopenharmony_ci up_write(&zram->init_lock); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci pr_info("setup backing device %s\n", file_name); 4848c2ecf20Sopenharmony_ci kfree(file_name); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci return len; 4878c2ecf20Sopenharmony_ciout: 4888c2ecf20Sopenharmony_ci if (bitmap) 4898c2ecf20Sopenharmony_ci kvfree(bitmap); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci if (bdev) 4928c2ecf20Sopenharmony_ci blkdev_put(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL); 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci if (backing_dev) 4958c2ecf20Sopenharmony_ci filp_close(backing_dev, NULL); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci up_write(&zram->init_lock); 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci kfree(file_name); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci return err; 5028c2ecf20Sopenharmony_ci} 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_cistatic unsigned long alloc_block_bdev(struct zram *zram) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci unsigned long blk_idx = 1; 5078c2ecf20Sopenharmony_ciretry: 5088c2ecf20Sopenharmony_ci /* skip 0 bit to confuse zram.handle = 0 */ 5098c2ecf20Sopenharmony_ci blk_idx = find_next_zero_bit(zram->bitmap, zram->nr_pages, blk_idx); 5108c2ecf20Sopenharmony_ci if (blk_idx == zram->nr_pages) 5118c2ecf20Sopenharmony_ci return 0; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci if (test_and_set_bit(blk_idx, zram->bitmap)) 5148c2ecf20Sopenharmony_ci goto retry; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci atomic64_inc(&zram->stats.bd_count); 5178c2ecf20Sopenharmony_ci return blk_idx; 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_cistatic void free_block_bdev(struct zram *zram, unsigned long blk_idx) 5218c2ecf20Sopenharmony_ci{ 5228c2ecf20Sopenharmony_ci int was_set; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci was_set = test_and_clear_bit(blk_idx, zram->bitmap); 5258c2ecf20Sopenharmony_ci WARN_ON_ONCE(!was_set); 5268c2ecf20Sopenharmony_ci atomic64_dec(&zram->stats.bd_count); 5278c2ecf20Sopenharmony_ci} 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_cistatic void zram_page_end_io(struct bio *bio) 5308c2ecf20Sopenharmony_ci{ 5318c2ecf20Sopenharmony_ci struct page *page = bio_first_page_all(bio); 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci page_endio(page, op_is_write(bio_op(bio)), 5348c2ecf20Sopenharmony_ci blk_status_to_errno(bio->bi_status)); 5358c2ecf20Sopenharmony_ci bio_put(bio); 5368c2ecf20Sopenharmony_ci} 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci/* 5398c2ecf20Sopenharmony_ci * Returns 1 if the submission is successful. 5408c2ecf20Sopenharmony_ci */ 5418c2ecf20Sopenharmony_cistatic int read_from_bdev_async(struct zram *zram, struct bio_vec *bvec, 5428c2ecf20Sopenharmony_ci unsigned long entry, struct bio *parent) 5438c2ecf20Sopenharmony_ci{ 5448c2ecf20Sopenharmony_ci struct bio *bio; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci bio = bio_alloc(GFP_ATOMIC, 1); 5478c2ecf20Sopenharmony_ci if (!bio) 5488c2ecf20Sopenharmony_ci return -ENOMEM; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci bio->bi_iter.bi_sector = entry * (PAGE_SIZE >> 9); 5518c2ecf20Sopenharmony_ci bio_set_dev(bio, zram->bdev); 5528c2ecf20Sopenharmony_ci if (!bio_add_page(bio, bvec->bv_page, bvec->bv_len, bvec->bv_offset)) { 5538c2ecf20Sopenharmony_ci bio_put(bio); 5548c2ecf20Sopenharmony_ci return -EIO; 5558c2ecf20Sopenharmony_ci } 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci if (!parent) { 5588c2ecf20Sopenharmony_ci bio->bi_opf = REQ_OP_READ; 5598c2ecf20Sopenharmony_ci bio->bi_end_io = zram_page_end_io; 5608c2ecf20Sopenharmony_ci } else { 5618c2ecf20Sopenharmony_ci bio->bi_opf = parent->bi_opf; 5628c2ecf20Sopenharmony_ci bio_chain(bio, parent); 5638c2ecf20Sopenharmony_ci } 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci submit_bio(bio); 5668c2ecf20Sopenharmony_ci return 1; 5678c2ecf20Sopenharmony_ci} 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci#define HUGE_WRITEBACK 1 5708c2ecf20Sopenharmony_ci#define IDLE_WRITEBACK 2 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_cistatic ssize_t writeback_store(struct device *dev, 5738c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t len) 5748c2ecf20Sopenharmony_ci{ 5758c2ecf20Sopenharmony_ci struct zram *zram = dev_to_zram(dev); 5768c2ecf20Sopenharmony_ci unsigned long nr_pages = zram->disksize >> PAGE_SHIFT; 5778c2ecf20Sopenharmony_ci unsigned long index; 5788c2ecf20Sopenharmony_ci struct bio bio; 5798c2ecf20Sopenharmony_ci struct bio_vec bio_vec; 5808c2ecf20Sopenharmony_ci struct page *page; 5818c2ecf20Sopenharmony_ci ssize_t ret = len; 5828c2ecf20Sopenharmony_ci int mode, err; 5838c2ecf20Sopenharmony_ci unsigned long blk_idx = 0; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci if (sysfs_streq(buf, "idle")) 5868c2ecf20Sopenharmony_ci mode = IDLE_WRITEBACK; 5878c2ecf20Sopenharmony_ci else if (sysfs_streq(buf, "huge")) 5888c2ecf20Sopenharmony_ci mode = HUGE_WRITEBACK; 5898c2ecf20Sopenharmony_ci else 5908c2ecf20Sopenharmony_ci return -EINVAL; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci down_read(&zram->init_lock); 5938c2ecf20Sopenharmony_ci if (!init_done(zram)) { 5948c2ecf20Sopenharmony_ci ret = -EINVAL; 5958c2ecf20Sopenharmony_ci goto release_init_lock; 5968c2ecf20Sopenharmony_ci } 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci if (!zram->backing_dev) { 5998c2ecf20Sopenharmony_ci ret = -ENODEV; 6008c2ecf20Sopenharmony_ci goto release_init_lock; 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci page = alloc_page(GFP_KERNEL); 6048c2ecf20Sopenharmony_ci if (!page) { 6058c2ecf20Sopenharmony_ci ret = -ENOMEM; 6068c2ecf20Sopenharmony_ci goto release_init_lock; 6078c2ecf20Sopenharmony_ci } 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci for (index = 0; index < nr_pages; index++) { 6108c2ecf20Sopenharmony_ci struct bio_vec bvec; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci bvec.bv_page = page; 6138c2ecf20Sopenharmony_ci bvec.bv_len = PAGE_SIZE; 6148c2ecf20Sopenharmony_ci bvec.bv_offset = 0; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci spin_lock(&zram->wb_limit_lock); 6178c2ecf20Sopenharmony_ci if (zram->wb_limit_enable && !zram->bd_wb_limit) { 6188c2ecf20Sopenharmony_ci spin_unlock(&zram->wb_limit_lock); 6198c2ecf20Sopenharmony_ci ret = -EIO; 6208c2ecf20Sopenharmony_ci break; 6218c2ecf20Sopenharmony_ci } 6228c2ecf20Sopenharmony_ci spin_unlock(&zram->wb_limit_lock); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci if (!blk_idx) { 6258c2ecf20Sopenharmony_ci blk_idx = alloc_block_bdev(zram); 6268c2ecf20Sopenharmony_ci if (!blk_idx) { 6278c2ecf20Sopenharmony_ci ret = -ENOSPC; 6288c2ecf20Sopenharmony_ci break; 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci } 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci zram_slot_lock(zram, index); 6338c2ecf20Sopenharmony_ci if (!zram_allocated(zram, index)) 6348c2ecf20Sopenharmony_ci goto next; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci if (zram_test_flag(zram, index, ZRAM_WB) || 6378c2ecf20Sopenharmony_ci zram_test_flag(zram, index, ZRAM_SAME) || 6388c2ecf20Sopenharmony_ci zram_test_flag(zram, index, ZRAM_UNDER_WB)) 6398c2ecf20Sopenharmony_ci goto next; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci if (mode == IDLE_WRITEBACK && 6428c2ecf20Sopenharmony_ci !zram_test_flag(zram, index, ZRAM_IDLE)) 6438c2ecf20Sopenharmony_ci goto next; 6448c2ecf20Sopenharmony_ci if (mode == HUGE_WRITEBACK && 6458c2ecf20Sopenharmony_ci !zram_test_flag(zram, index, ZRAM_HUGE)) 6468c2ecf20Sopenharmony_ci goto next; 6478c2ecf20Sopenharmony_ci /* 6488c2ecf20Sopenharmony_ci * Clearing ZRAM_UNDER_WB is duty of caller. 6498c2ecf20Sopenharmony_ci * IOW, zram_free_page never clear it. 6508c2ecf20Sopenharmony_ci */ 6518c2ecf20Sopenharmony_ci zram_set_flag(zram, index, ZRAM_UNDER_WB); 6528c2ecf20Sopenharmony_ci /* Need for hugepage writeback racing */ 6538c2ecf20Sopenharmony_ci zram_set_flag(zram, index, ZRAM_IDLE); 6548c2ecf20Sopenharmony_ci zram_slot_unlock(zram, index); 6558c2ecf20Sopenharmony_ci if (zram_bvec_read(zram, &bvec, index, 0, NULL)) { 6568c2ecf20Sopenharmony_ci zram_slot_lock(zram, index); 6578c2ecf20Sopenharmony_ci zram_clear_flag(zram, index, ZRAM_UNDER_WB); 6588c2ecf20Sopenharmony_ci zram_clear_flag(zram, index, ZRAM_IDLE); 6598c2ecf20Sopenharmony_ci zram_slot_unlock(zram, index); 6608c2ecf20Sopenharmony_ci continue; 6618c2ecf20Sopenharmony_ci } 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci bio_init(&bio, &bio_vec, 1); 6648c2ecf20Sopenharmony_ci bio_set_dev(&bio, zram->bdev); 6658c2ecf20Sopenharmony_ci bio.bi_iter.bi_sector = blk_idx * (PAGE_SIZE >> 9); 6668c2ecf20Sopenharmony_ci bio.bi_opf = REQ_OP_WRITE | REQ_SYNC; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci bio_add_page(&bio, bvec.bv_page, bvec.bv_len, 6698c2ecf20Sopenharmony_ci bvec.bv_offset); 6708c2ecf20Sopenharmony_ci /* 6718c2ecf20Sopenharmony_ci * XXX: A single page IO would be inefficient for write 6728c2ecf20Sopenharmony_ci * but it would be not bad as starter. 6738c2ecf20Sopenharmony_ci */ 6748c2ecf20Sopenharmony_ci err = submit_bio_wait(&bio); 6758c2ecf20Sopenharmony_ci if (err) { 6768c2ecf20Sopenharmony_ci zram_slot_lock(zram, index); 6778c2ecf20Sopenharmony_ci zram_clear_flag(zram, index, ZRAM_UNDER_WB); 6788c2ecf20Sopenharmony_ci zram_clear_flag(zram, index, ZRAM_IDLE); 6798c2ecf20Sopenharmony_ci zram_slot_unlock(zram, index); 6808c2ecf20Sopenharmony_ci /* 6818c2ecf20Sopenharmony_ci * Return last IO error unless every IO were 6828c2ecf20Sopenharmony_ci * not suceeded. 6838c2ecf20Sopenharmony_ci */ 6848c2ecf20Sopenharmony_ci ret = err; 6858c2ecf20Sopenharmony_ci continue; 6868c2ecf20Sopenharmony_ci } 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci atomic64_inc(&zram->stats.bd_writes); 6898c2ecf20Sopenharmony_ci /* 6908c2ecf20Sopenharmony_ci * We released zram_slot_lock so need to check if the slot was 6918c2ecf20Sopenharmony_ci * changed. If there is freeing for the slot, we can catch it 6928c2ecf20Sopenharmony_ci * easily by zram_allocated. 6938c2ecf20Sopenharmony_ci * A subtle case is the slot is freed/reallocated/marked as 6948c2ecf20Sopenharmony_ci * ZRAM_IDLE again. To close the race, idle_store doesn't 6958c2ecf20Sopenharmony_ci * mark ZRAM_IDLE once it found the slot was ZRAM_UNDER_WB. 6968c2ecf20Sopenharmony_ci * Thus, we could close the race by checking ZRAM_IDLE bit. 6978c2ecf20Sopenharmony_ci */ 6988c2ecf20Sopenharmony_ci zram_slot_lock(zram, index); 6998c2ecf20Sopenharmony_ci if (!zram_allocated(zram, index) || 7008c2ecf20Sopenharmony_ci !zram_test_flag(zram, index, ZRAM_IDLE)) { 7018c2ecf20Sopenharmony_ci zram_clear_flag(zram, index, ZRAM_UNDER_WB); 7028c2ecf20Sopenharmony_ci zram_clear_flag(zram, index, ZRAM_IDLE); 7038c2ecf20Sopenharmony_ci goto next; 7048c2ecf20Sopenharmony_ci } 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci zram_free_page(zram, index); 7078c2ecf20Sopenharmony_ci zram_clear_flag(zram, index, ZRAM_UNDER_WB); 7088c2ecf20Sopenharmony_ci zram_set_flag(zram, index, ZRAM_WB); 7098c2ecf20Sopenharmony_ci zram_set_element(zram, index, blk_idx); 7108c2ecf20Sopenharmony_ci blk_idx = 0; 7118c2ecf20Sopenharmony_ci atomic64_inc(&zram->stats.pages_stored); 7128c2ecf20Sopenharmony_ci spin_lock(&zram->wb_limit_lock); 7138c2ecf20Sopenharmony_ci if (zram->wb_limit_enable && zram->bd_wb_limit > 0) 7148c2ecf20Sopenharmony_ci zram->bd_wb_limit -= 1UL << (PAGE_SHIFT - 12); 7158c2ecf20Sopenharmony_ci spin_unlock(&zram->wb_limit_lock); 7168c2ecf20Sopenharmony_cinext: 7178c2ecf20Sopenharmony_ci zram_slot_unlock(zram, index); 7188c2ecf20Sopenharmony_ci } 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci if (blk_idx) 7218c2ecf20Sopenharmony_ci free_block_bdev(zram, blk_idx); 7228c2ecf20Sopenharmony_ci __free_page(page); 7238c2ecf20Sopenharmony_cirelease_init_lock: 7248c2ecf20Sopenharmony_ci up_read(&zram->init_lock); 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci return ret; 7278c2ecf20Sopenharmony_ci} 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_cistruct zram_work { 7308c2ecf20Sopenharmony_ci struct work_struct work; 7318c2ecf20Sopenharmony_ci struct zram *zram; 7328c2ecf20Sopenharmony_ci unsigned long entry; 7338c2ecf20Sopenharmony_ci struct bio *bio; 7348c2ecf20Sopenharmony_ci struct bio_vec bvec; 7358c2ecf20Sopenharmony_ci}; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci#if PAGE_SIZE != 4096 7388c2ecf20Sopenharmony_cistatic void zram_sync_read(struct work_struct *work) 7398c2ecf20Sopenharmony_ci{ 7408c2ecf20Sopenharmony_ci struct zram_work *zw = container_of(work, struct zram_work, work); 7418c2ecf20Sopenharmony_ci struct zram *zram = zw->zram; 7428c2ecf20Sopenharmony_ci unsigned long entry = zw->entry; 7438c2ecf20Sopenharmony_ci struct bio *bio = zw->bio; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci read_from_bdev_async(zram, &zw->bvec, entry, bio); 7468c2ecf20Sopenharmony_ci} 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci/* 7498c2ecf20Sopenharmony_ci * Block layer want one ->submit_bio to be active at a time, so if we use 7508c2ecf20Sopenharmony_ci * chained IO with parent IO in same context, it's a deadlock. To avoid that, 7518c2ecf20Sopenharmony_ci * use a worker thread context. 7528c2ecf20Sopenharmony_ci */ 7538c2ecf20Sopenharmony_cistatic int read_from_bdev_sync(struct zram *zram, struct bio_vec *bvec, 7548c2ecf20Sopenharmony_ci unsigned long entry, struct bio *bio) 7558c2ecf20Sopenharmony_ci{ 7568c2ecf20Sopenharmony_ci struct zram_work work; 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci work.bvec = *bvec; 7598c2ecf20Sopenharmony_ci work.zram = zram; 7608c2ecf20Sopenharmony_ci work.entry = entry; 7618c2ecf20Sopenharmony_ci work.bio = bio; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci INIT_WORK_ONSTACK(&work.work, zram_sync_read); 7648c2ecf20Sopenharmony_ci queue_work(system_unbound_wq, &work.work); 7658c2ecf20Sopenharmony_ci flush_work(&work.work); 7668c2ecf20Sopenharmony_ci destroy_work_on_stack(&work.work); 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci return 1; 7698c2ecf20Sopenharmony_ci} 7708c2ecf20Sopenharmony_ci#else 7718c2ecf20Sopenharmony_cistatic int read_from_bdev_sync(struct zram *zram, struct bio_vec *bvec, 7728c2ecf20Sopenharmony_ci unsigned long entry, struct bio *bio) 7738c2ecf20Sopenharmony_ci{ 7748c2ecf20Sopenharmony_ci WARN_ON(1); 7758c2ecf20Sopenharmony_ci return -EIO; 7768c2ecf20Sopenharmony_ci} 7778c2ecf20Sopenharmony_ci#endif 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_cistatic int read_from_bdev(struct zram *zram, struct bio_vec *bvec, 7808c2ecf20Sopenharmony_ci unsigned long entry, struct bio *parent, bool sync) 7818c2ecf20Sopenharmony_ci{ 7828c2ecf20Sopenharmony_ci atomic64_inc(&zram->stats.bd_reads); 7838c2ecf20Sopenharmony_ci if (sync) 7848c2ecf20Sopenharmony_ci return read_from_bdev_sync(zram, bvec, entry, parent); 7858c2ecf20Sopenharmony_ci else 7868c2ecf20Sopenharmony_ci return read_from_bdev_async(zram, bvec, entry, parent); 7878c2ecf20Sopenharmony_ci} 7888c2ecf20Sopenharmony_ci#else 7898c2ecf20Sopenharmony_cistatic inline void reset_bdev(struct zram *zram) {}; 7908c2ecf20Sopenharmony_cistatic int read_from_bdev(struct zram *zram, struct bio_vec *bvec, 7918c2ecf20Sopenharmony_ci unsigned long entry, struct bio *parent, bool sync) 7928c2ecf20Sopenharmony_ci{ 7938c2ecf20Sopenharmony_ci return -EIO; 7948c2ecf20Sopenharmony_ci} 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_cistatic void free_block_bdev(struct zram *zram, unsigned long blk_idx) {}; 7978c2ecf20Sopenharmony_ci#endif 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci#ifdef CONFIG_ZRAM_MEMORY_TRACKING 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_cistatic struct dentry *zram_debugfs_root; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_cistatic void zram_debugfs_create(void) 8048c2ecf20Sopenharmony_ci{ 8058c2ecf20Sopenharmony_ci zram_debugfs_root = debugfs_create_dir("zram", NULL); 8068c2ecf20Sopenharmony_ci} 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_cistatic void zram_debugfs_destroy(void) 8098c2ecf20Sopenharmony_ci{ 8108c2ecf20Sopenharmony_ci debugfs_remove_recursive(zram_debugfs_root); 8118c2ecf20Sopenharmony_ci} 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_cistatic void zram_accessed(struct zram *zram, u32 index) 8148c2ecf20Sopenharmony_ci{ 8158c2ecf20Sopenharmony_ci zram_clear_flag(zram, index, ZRAM_IDLE); 8168c2ecf20Sopenharmony_ci zram->table[index].ac_time = ktime_get_boottime(); 8178c2ecf20Sopenharmony_ci} 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_cistatic ssize_t read_block_state(struct file *file, char __user *buf, 8208c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 8218c2ecf20Sopenharmony_ci{ 8228c2ecf20Sopenharmony_ci char *kbuf; 8238c2ecf20Sopenharmony_ci ssize_t index, written = 0; 8248c2ecf20Sopenharmony_ci struct zram *zram = file->private_data; 8258c2ecf20Sopenharmony_ci unsigned long nr_pages = zram->disksize >> PAGE_SHIFT; 8268c2ecf20Sopenharmony_ci struct timespec64 ts; 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci kbuf = kvmalloc(count, GFP_KERNEL); 8298c2ecf20Sopenharmony_ci if (!kbuf) 8308c2ecf20Sopenharmony_ci return -ENOMEM; 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci down_read(&zram->init_lock); 8338c2ecf20Sopenharmony_ci if (!init_done(zram)) { 8348c2ecf20Sopenharmony_ci up_read(&zram->init_lock); 8358c2ecf20Sopenharmony_ci kvfree(kbuf); 8368c2ecf20Sopenharmony_ci return -EINVAL; 8378c2ecf20Sopenharmony_ci } 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci for (index = *ppos; index < nr_pages; index++) { 8408c2ecf20Sopenharmony_ci int copied; 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci zram_slot_lock(zram, index); 8438c2ecf20Sopenharmony_ci if (!zram_allocated(zram, index)) 8448c2ecf20Sopenharmony_ci goto next; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci ts = ktime_to_timespec64(zram->table[index].ac_time); 8478c2ecf20Sopenharmony_ci copied = snprintf(kbuf + written, count, 8488c2ecf20Sopenharmony_ci "%12zd %12lld.%06lu %c%c%c%c\n", 8498c2ecf20Sopenharmony_ci index, (s64)ts.tv_sec, 8508c2ecf20Sopenharmony_ci ts.tv_nsec / NSEC_PER_USEC, 8518c2ecf20Sopenharmony_ci zram_test_flag(zram, index, ZRAM_SAME) ? 's' : '.', 8528c2ecf20Sopenharmony_ci zram_test_flag(zram, index, ZRAM_WB) ? 'w' : '.', 8538c2ecf20Sopenharmony_ci zram_test_flag(zram, index, ZRAM_HUGE) ? 'h' : '.', 8548c2ecf20Sopenharmony_ci zram_test_flag(zram, index, ZRAM_IDLE) ? 'i' : '.'); 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci if (count <= copied) { 8578c2ecf20Sopenharmony_ci zram_slot_unlock(zram, index); 8588c2ecf20Sopenharmony_ci break; 8598c2ecf20Sopenharmony_ci } 8608c2ecf20Sopenharmony_ci written += copied; 8618c2ecf20Sopenharmony_ci count -= copied; 8628c2ecf20Sopenharmony_cinext: 8638c2ecf20Sopenharmony_ci zram_slot_unlock(zram, index); 8648c2ecf20Sopenharmony_ci *ppos += 1; 8658c2ecf20Sopenharmony_ci } 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci up_read(&zram->init_lock); 8688c2ecf20Sopenharmony_ci if (copy_to_user(buf, kbuf, written)) 8698c2ecf20Sopenharmony_ci written = -EFAULT; 8708c2ecf20Sopenharmony_ci kvfree(kbuf); 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci return written; 8738c2ecf20Sopenharmony_ci} 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_cistatic const struct file_operations proc_zram_block_state_op = { 8768c2ecf20Sopenharmony_ci .open = simple_open, 8778c2ecf20Sopenharmony_ci .read = read_block_state, 8788c2ecf20Sopenharmony_ci .llseek = default_llseek, 8798c2ecf20Sopenharmony_ci}; 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_cistatic void zram_debugfs_register(struct zram *zram) 8828c2ecf20Sopenharmony_ci{ 8838c2ecf20Sopenharmony_ci if (!zram_debugfs_root) 8848c2ecf20Sopenharmony_ci return; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci zram->debugfs_dir = debugfs_create_dir(zram->disk->disk_name, 8878c2ecf20Sopenharmony_ci zram_debugfs_root); 8888c2ecf20Sopenharmony_ci debugfs_create_file("block_state", 0400, zram->debugfs_dir, 8898c2ecf20Sopenharmony_ci zram, &proc_zram_block_state_op); 8908c2ecf20Sopenharmony_ci} 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_cistatic void zram_debugfs_unregister(struct zram *zram) 8938c2ecf20Sopenharmony_ci{ 8948c2ecf20Sopenharmony_ci debugfs_remove_recursive(zram->debugfs_dir); 8958c2ecf20Sopenharmony_ci} 8968c2ecf20Sopenharmony_ci#else 8978c2ecf20Sopenharmony_cistatic void zram_debugfs_create(void) {}; 8988c2ecf20Sopenharmony_cistatic void zram_debugfs_destroy(void) {}; 8998c2ecf20Sopenharmony_cistatic void zram_accessed(struct zram *zram, u32 index) 9008c2ecf20Sopenharmony_ci{ 9018c2ecf20Sopenharmony_ci zram_clear_flag(zram, index, ZRAM_IDLE); 9028c2ecf20Sopenharmony_ci}; 9038c2ecf20Sopenharmony_cistatic void zram_debugfs_register(struct zram *zram) {}; 9048c2ecf20Sopenharmony_cistatic void zram_debugfs_unregister(struct zram *zram) {}; 9058c2ecf20Sopenharmony_ci#endif 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci/* 9088c2ecf20Sopenharmony_ci * We switched to per-cpu streams and this attr is not needed anymore. 9098c2ecf20Sopenharmony_ci * However, we will keep it around for some time, because: 9108c2ecf20Sopenharmony_ci * a) we may revert per-cpu streams in the future 9118c2ecf20Sopenharmony_ci * b) it's visible to user space and we need to follow our 2 years 9128c2ecf20Sopenharmony_ci * retirement rule; but we already have a number of 'soon to be 9138c2ecf20Sopenharmony_ci * altered' attrs, so max_comp_streams need to wait for the next 9148c2ecf20Sopenharmony_ci * layoff cycle. 9158c2ecf20Sopenharmony_ci */ 9168c2ecf20Sopenharmony_cistatic ssize_t max_comp_streams_show(struct device *dev, 9178c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 9188c2ecf20Sopenharmony_ci{ 9198c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%d\n", num_online_cpus()); 9208c2ecf20Sopenharmony_ci} 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_cistatic ssize_t max_comp_streams_store(struct device *dev, 9238c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t len) 9248c2ecf20Sopenharmony_ci{ 9258c2ecf20Sopenharmony_ci return len; 9268c2ecf20Sopenharmony_ci} 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_cistatic ssize_t comp_algorithm_show(struct device *dev, 9298c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 9308c2ecf20Sopenharmony_ci{ 9318c2ecf20Sopenharmony_ci size_t sz; 9328c2ecf20Sopenharmony_ci struct zram *zram = dev_to_zram(dev); 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci down_read(&zram->init_lock); 9358c2ecf20Sopenharmony_ci sz = zcomp_available_show(zram->compressor, buf); 9368c2ecf20Sopenharmony_ci up_read(&zram->init_lock); 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci return sz; 9398c2ecf20Sopenharmony_ci} 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_cistatic ssize_t comp_algorithm_store(struct device *dev, 9428c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t len) 9438c2ecf20Sopenharmony_ci{ 9448c2ecf20Sopenharmony_ci struct zram *zram = dev_to_zram(dev); 9458c2ecf20Sopenharmony_ci char compressor[ARRAY_SIZE(zram->compressor)]; 9468c2ecf20Sopenharmony_ci size_t sz; 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci strlcpy(compressor, buf, sizeof(compressor)); 9498c2ecf20Sopenharmony_ci /* ignore trailing newline */ 9508c2ecf20Sopenharmony_ci sz = strlen(compressor); 9518c2ecf20Sopenharmony_ci if (sz > 0 && compressor[sz - 1] == '\n') 9528c2ecf20Sopenharmony_ci compressor[sz - 1] = 0x00; 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci if (!zcomp_available_algorithm(compressor)) 9558c2ecf20Sopenharmony_ci return -EINVAL; 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci down_write(&zram->init_lock); 9588c2ecf20Sopenharmony_ci if (init_done(zram)) { 9598c2ecf20Sopenharmony_ci up_write(&zram->init_lock); 9608c2ecf20Sopenharmony_ci pr_info("Can't change algorithm for initialized device\n"); 9618c2ecf20Sopenharmony_ci return -EBUSY; 9628c2ecf20Sopenharmony_ci } 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci strcpy(zram->compressor, compressor); 9658c2ecf20Sopenharmony_ci up_write(&zram->init_lock); 9668c2ecf20Sopenharmony_ci return len; 9678c2ecf20Sopenharmony_ci} 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_cistatic ssize_t compact_store(struct device *dev, 9708c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t len) 9718c2ecf20Sopenharmony_ci{ 9728c2ecf20Sopenharmony_ci struct zram *zram = dev_to_zram(dev); 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci down_read(&zram->init_lock); 9758c2ecf20Sopenharmony_ci if (!init_done(zram)) { 9768c2ecf20Sopenharmony_ci up_read(&zram->init_lock); 9778c2ecf20Sopenharmony_ci return -EINVAL; 9788c2ecf20Sopenharmony_ci } 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci zs_compact(zram->mem_pool); 9818c2ecf20Sopenharmony_ci up_read(&zram->init_lock); 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci return len; 9848c2ecf20Sopenharmony_ci} 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_cistatic ssize_t io_stat_show(struct device *dev, 9878c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 9888c2ecf20Sopenharmony_ci{ 9898c2ecf20Sopenharmony_ci struct zram *zram = dev_to_zram(dev); 9908c2ecf20Sopenharmony_ci ssize_t ret; 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci down_read(&zram->init_lock); 9938c2ecf20Sopenharmony_ci ret = scnprintf(buf, PAGE_SIZE, 9948c2ecf20Sopenharmony_ci "%8llu %8llu %8llu %8llu\n", 9958c2ecf20Sopenharmony_ci (u64)atomic64_read(&zram->stats.failed_reads), 9968c2ecf20Sopenharmony_ci (u64)atomic64_read(&zram->stats.failed_writes), 9978c2ecf20Sopenharmony_ci (u64)atomic64_read(&zram->stats.invalid_io), 9988c2ecf20Sopenharmony_ci (u64)atomic64_read(&zram->stats.notify_free)); 9998c2ecf20Sopenharmony_ci up_read(&zram->init_lock); 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci return ret; 10028c2ecf20Sopenharmony_ci} 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_cistatic ssize_t mm_stat_show(struct device *dev, 10058c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 10068c2ecf20Sopenharmony_ci{ 10078c2ecf20Sopenharmony_ci struct zram *zram = dev_to_zram(dev); 10088c2ecf20Sopenharmony_ci struct zs_pool_stats pool_stats; 10098c2ecf20Sopenharmony_ci u64 orig_size, mem_used = 0; 10108c2ecf20Sopenharmony_ci long max_used; 10118c2ecf20Sopenharmony_ci ssize_t ret; 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci memset(&pool_stats, 0x00, sizeof(struct zs_pool_stats)); 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci down_read(&zram->init_lock); 10168c2ecf20Sopenharmony_ci if (init_done(zram)) { 10178c2ecf20Sopenharmony_ci mem_used = zs_get_total_pages(zram->mem_pool); 10188c2ecf20Sopenharmony_ci zs_pool_stats(zram->mem_pool, &pool_stats); 10198c2ecf20Sopenharmony_ci } 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci orig_size = atomic64_read(&zram->stats.pages_stored); 10228c2ecf20Sopenharmony_ci max_used = atomic_long_read(&zram->stats.max_used_pages); 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci ret = scnprintf(buf, PAGE_SIZE, 10258c2ecf20Sopenharmony_ci "%8llu %8llu %8llu %8lu %8ld %8llu %8lu %8llu\n", 10268c2ecf20Sopenharmony_ci orig_size << PAGE_SHIFT, 10278c2ecf20Sopenharmony_ci (u64)atomic64_read(&zram->stats.compr_data_size), 10288c2ecf20Sopenharmony_ci mem_used << PAGE_SHIFT, 10298c2ecf20Sopenharmony_ci zram->limit_pages << PAGE_SHIFT, 10308c2ecf20Sopenharmony_ci max_used << PAGE_SHIFT, 10318c2ecf20Sopenharmony_ci (u64)atomic64_read(&zram->stats.same_pages), 10328c2ecf20Sopenharmony_ci atomic_long_read(&pool_stats.pages_compacted), 10338c2ecf20Sopenharmony_ci (u64)atomic64_read(&zram->stats.huge_pages)); 10348c2ecf20Sopenharmony_ci up_read(&zram->init_lock); 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci return ret; 10378c2ecf20Sopenharmony_ci} 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci#ifdef CONFIG_ZRAM_WRITEBACK 10408c2ecf20Sopenharmony_ci#define FOUR_K(x) ((x) * (1 << (PAGE_SHIFT - 12))) 10418c2ecf20Sopenharmony_cistatic ssize_t bd_stat_show(struct device *dev, 10428c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 10438c2ecf20Sopenharmony_ci{ 10448c2ecf20Sopenharmony_ci struct zram *zram = dev_to_zram(dev); 10458c2ecf20Sopenharmony_ci ssize_t ret; 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci down_read(&zram->init_lock); 10488c2ecf20Sopenharmony_ci ret = scnprintf(buf, PAGE_SIZE, 10498c2ecf20Sopenharmony_ci "%8llu %8llu %8llu\n", 10508c2ecf20Sopenharmony_ci FOUR_K((u64)atomic64_read(&zram->stats.bd_count)), 10518c2ecf20Sopenharmony_ci FOUR_K((u64)atomic64_read(&zram->stats.bd_reads)), 10528c2ecf20Sopenharmony_ci FOUR_K((u64)atomic64_read(&zram->stats.bd_writes))); 10538c2ecf20Sopenharmony_ci up_read(&zram->init_lock); 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci return ret; 10568c2ecf20Sopenharmony_ci} 10578c2ecf20Sopenharmony_ci#endif 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_cistatic ssize_t debug_stat_show(struct device *dev, 10608c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 10618c2ecf20Sopenharmony_ci{ 10628c2ecf20Sopenharmony_ci int version = 1; 10638c2ecf20Sopenharmony_ci struct zram *zram = dev_to_zram(dev); 10648c2ecf20Sopenharmony_ci ssize_t ret; 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci down_read(&zram->init_lock); 10678c2ecf20Sopenharmony_ci ret = scnprintf(buf, PAGE_SIZE, 10688c2ecf20Sopenharmony_ci "version: %d\n%8llu %8llu\n", 10698c2ecf20Sopenharmony_ci version, 10708c2ecf20Sopenharmony_ci (u64)atomic64_read(&zram->stats.writestall), 10718c2ecf20Sopenharmony_ci (u64)atomic64_read(&zram->stats.miss_free)); 10728c2ecf20Sopenharmony_ci up_read(&zram->init_lock); 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci return ret; 10758c2ecf20Sopenharmony_ci} 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(io_stat); 10788c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(mm_stat); 10798c2ecf20Sopenharmony_ci#ifdef CONFIG_ZRAM_WRITEBACK 10808c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(bd_stat); 10818c2ecf20Sopenharmony_ci#endif 10828c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(debug_stat); 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci#ifdef CONFIG_ZRAM_GROUP 10858c2ecf20Sopenharmony_cistatic ssize_t group_show(struct device *dev, struct device_attribute *attr, char *buf) 10868c2ecf20Sopenharmony_ci{ 10878c2ecf20Sopenharmony_ci struct zram *zram = dev_to_zram(dev); 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci down_read(&zram->init_lock); 10908c2ecf20Sopenharmony_ci if (zram->zgrp_ctrl == ZGRP_NONE) 10918c2ecf20Sopenharmony_ci strcpy(buf, "disable\n"); 10928c2ecf20Sopenharmony_ci else if (zram->zgrp_ctrl == ZGRP_TRACK) 10938c2ecf20Sopenharmony_ci strcpy(buf, "readonly\n"); 10948c2ecf20Sopenharmony_ci#ifdef CONFIG_ZRAM_GROUP_WRITEBACK 10958c2ecf20Sopenharmony_ci else if (zram->zgrp_ctrl == ZGRP_WRITE) 10968c2ecf20Sopenharmony_ci strcpy(buf, "readwrite"); 10978c2ecf20Sopenharmony_ci#endif 10988c2ecf20Sopenharmony_ci up_read(&zram->init_lock); 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci return strlen(buf); 11018c2ecf20Sopenharmony_ci} 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_cistatic ssize_t group_store(struct device *dev, struct device_attribute *attr, 11048c2ecf20Sopenharmony_ci const char *buf, size_t len) 11058c2ecf20Sopenharmony_ci{ 11068c2ecf20Sopenharmony_ci struct zram *zram = dev_to_zram(dev); 11078c2ecf20Sopenharmony_ci int ret; 11088c2ecf20Sopenharmony_ci#ifdef CONFIG_ZRAM_GROUP_DEBUG 11098c2ecf20Sopenharmony_ci u32 op, gid, index; 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci ret = sscanf(buf, "%u %u %u", &op, &index, &gid); 11128c2ecf20Sopenharmony_ci if (ret == 3) { 11138c2ecf20Sopenharmony_ci pr_info("op[%u] index[%u] gid[%u].\n", op, index, gid); 11148c2ecf20Sopenharmony_ci group_debug(zram, op, index, gid); 11158c2ecf20Sopenharmony_ci return len; 11168c2ecf20Sopenharmony_ci } 11178c2ecf20Sopenharmony_ci#endif 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci ret = len; 11208c2ecf20Sopenharmony_ci down_write(&zram->init_lock); 11218c2ecf20Sopenharmony_ci if (init_done(zram)) { 11228c2ecf20Sopenharmony_ci pr_info("Can't setup group ctrl for initialized device!\n"); 11238c2ecf20Sopenharmony_ci ret = -EBUSY; 11248c2ecf20Sopenharmony_ci goto out; 11258c2ecf20Sopenharmony_ci } 11268c2ecf20Sopenharmony_ci if (!strcmp(buf, "disable\n")) 11278c2ecf20Sopenharmony_ci zram->zgrp_ctrl = ZGRP_NONE; 11288c2ecf20Sopenharmony_ci else if (!strcmp(buf, "readonly\n")) 11298c2ecf20Sopenharmony_ci zram->zgrp_ctrl = ZGRP_TRACK; 11308c2ecf20Sopenharmony_ci#ifdef CONFIG_ZRAM_GROUP_WRITEBACK 11318c2ecf20Sopenharmony_ci else if (!strcmp(buf, "readwrite\n")) 11328c2ecf20Sopenharmony_ci zram->zgrp_ctrl = ZGRP_WRITE; 11338c2ecf20Sopenharmony_ci#endif 11348c2ecf20Sopenharmony_ci else 11358c2ecf20Sopenharmony_ci ret = -EINVAL; 11368c2ecf20Sopenharmony_ciout: 11378c2ecf20Sopenharmony_ci up_write(&zram->init_lock); 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci return ret; 11408c2ecf20Sopenharmony_ci} 11418c2ecf20Sopenharmony_ci#endif 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_cistatic void zram_meta_free(struct zram *zram, u64 disksize) 11448c2ecf20Sopenharmony_ci{ 11458c2ecf20Sopenharmony_ci size_t num_pages = disksize >> PAGE_SHIFT; 11468c2ecf20Sopenharmony_ci size_t index; 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci /* Free all pages that are still in this zram device */ 11498c2ecf20Sopenharmony_ci for (index = 0; index < num_pages; index++) 11508c2ecf20Sopenharmony_ci zram_free_page(zram, index); 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci zs_destroy_pool(zram->mem_pool); 11538c2ecf20Sopenharmony_ci vfree(zram->table); 11548c2ecf20Sopenharmony_ci#ifdef CONFIG_ZRAM_GROUP 11558c2ecf20Sopenharmony_ci zram_group_deinit(zram); 11568c2ecf20Sopenharmony_ci#endif 11578c2ecf20Sopenharmony_ci} 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_cistatic bool zram_meta_alloc(struct zram *zram, u64 disksize) 11608c2ecf20Sopenharmony_ci{ 11618c2ecf20Sopenharmony_ci size_t num_pages; 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci num_pages = disksize >> PAGE_SHIFT; 11648c2ecf20Sopenharmony_ci zram->table = vzalloc(array_size(num_pages, sizeof(*zram->table))); 11658c2ecf20Sopenharmony_ci if (!zram->table) 11668c2ecf20Sopenharmony_ci return false; 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci zram->mem_pool = zs_create_pool(zram->disk->disk_name); 11698c2ecf20Sopenharmony_ci if (!zram->mem_pool) { 11708c2ecf20Sopenharmony_ci vfree(zram->table); 11718c2ecf20Sopenharmony_ci return false; 11728c2ecf20Sopenharmony_ci } 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci if (!huge_class_size) 11758c2ecf20Sopenharmony_ci huge_class_size = zs_huge_class_size(zram->mem_pool); 11768c2ecf20Sopenharmony_ci#ifdef CONFIG_ZRAM_GROUP 11778c2ecf20Sopenharmony_ci zram_group_init(zram, num_pages); 11788c2ecf20Sopenharmony_ci#endif 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci return true; 11818c2ecf20Sopenharmony_ci} 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci/* 11848c2ecf20Sopenharmony_ci * To protect concurrent access to the same index entry, 11858c2ecf20Sopenharmony_ci * caller should hold this table index entry's bit_spinlock to 11868c2ecf20Sopenharmony_ci * indicate this index entry is accessing. 11878c2ecf20Sopenharmony_ci */ 11888c2ecf20Sopenharmony_cistatic void zram_free_page(struct zram *zram, size_t index) 11898c2ecf20Sopenharmony_ci{ 11908c2ecf20Sopenharmony_ci unsigned long handle; 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci#ifdef CONFIG_ZRAM_GROUP 11938c2ecf20Sopenharmony_ci zram_group_untrack_obj(zram, index); 11948c2ecf20Sopenharmony_ci#endif 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci#ifdef CONFIG_ZRAM_MEMORY_TRACKING 11978c2ecf20Sopenharmony_ci zram->table[index].ac_time = 0; 11988c2ecf20Sopenharmony_ci#endif 11998c2ecf20Sopenharmony_ci if (zram_test_flag(zram, index, ZRAM_IDLE)) 12008c2ecf20Sopenharmony_ci zram_clear_flag(zram, index, ZRAM_IDLE); 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci if (zram_test_flag(zram, index, ZRAM_HUGE)) { 12038c2ecf20Sopenharmony_ci zram_clear_flag(zram, index, ZRAM_HUGE); 12048c2ecf20Sopenharmony_ci atomic64_dec(&zram->stats.huge_pages); 12058c2ecf20Sopenharmony_ci } 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci if (zram_test_flag(zram, index, ZRAM_WB)) { 12088c2ecf20Sopenharmony_ci zram_clear_flag(zram, index, ZRAM_WB); 12098c2ecf20Sopenharmony_ci free_block_bdev(zram, zram_get_element(zram, index)); 12108c2ecf20Sopenharmony_ci goto out; 12118c2ecf20Sopenharmony_ci } 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci /* 12148c2ecf20Sopenharmony_ci * No memory is allocated for same element filled pages. 12158c2ecf20Sopenharmony_ci * Simply clear same page flag. 12168c2ecf20Sopenharmony_ci */ 12178c2ecf20Sopenharmony_ci if (zram_test_flag(zram, index, ZRAM_SAME)) { 12188c2ecf20Sopenharmony_ci zram_clear_flag(zram, index, ZRAM_SAME); 12198c2ecf20Sopenharmony_ci atomic64_dec(&zram->stats.same_pages); 12208c2ecf20Sopenharmony_ci goto out; 12218c2ecf20Sopenharmony_ci } 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci handle = zram_get_handle(zram, index); 12248c2ecf20Sopenharmony_ci if (!handle) 12258c2ecf20Sopenharmony_ci return; 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci zs_free(zram->mem_pool, handle); 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci atomic64_sub(zram_get_obj_size(zram, index), 12308c2ecf20Sopenharmony_ci &zram->stats.compr_data_size); 12318c2ecf20Sopenharmony_ciout: 12328c2ecf20Sopenharmony_ci atomic64_dec(&zram->stats.pages_stored); 12338c2ecf20Sopenharmony_ci zram_set_handle(zram, index, 0); 12348c2ecf20Sopenharmony_ci zram_set_obj_size(zram, index, 0); 12358c2ecf20Sopenharmony_ci WARN_ON_ONCE(zram->table[index].flags & 12368c2ecf20Sopenharmony_ci ~(1UL << ZRAM_LOCK | 1UL << ZRAM_UNDER_WB)); 12378c2ecf20Sopenharmony_ci} 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_cistatic int __zram_bvec_read(struct zram *zram, struct page *page, u32 index, 12408c2ecf20Sopenharmony_ci struct bio *bio, bool partial_io) 12418c2ecf20Sopenharmony_ci{ 12428c2ecf20Sopenharmony_ci struct zcomp_strm *zstrm; 12438c2ecf20Sopenharmony_ci unsigned long handle; 12448c2ecf20Sopenharmony_ci unsigned int size; 12458c2ecf20Sopenharmony_ci void *src, *dst; 12468c2ecf20Sopenharmony_ci int ret; 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci zram_slot_lock(zram, index); 12498c2ecf20Sopenharmony_ci if (zram_test_flag(zram, index, ZRAM_WB)) { 12508c2ecf20Sopenharmony_ci struct bio_vec bvec; 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci zram_slot_unlock(zram, index); 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci bvec.bv_page = page; 12558c2ecf20Sopenharmony_ci bvec.bv_len = PAGE_SIZE; 12568c2ecf20Sopenharmony_ci bvec.bv_offset = 0; 12578c2ecf20Sopenharmony_ci return read_from_bdev(zram, &bvec, 12588c2ecf20Sopenharmony_ci zram_get_element(zram, index), 12598c2ecf20Sopenharmony_ci bio, partial_io); 12608c2ecf20Sopenharmony_ci } 12618c2ecf20Sopenharmony_ci#ifdef CONFIG_ZRAM_GROUP_WRITEBACK 12628c2ecf20Sopenharmony_ci if (!bio) { 12638c2ecf20Sopenharmony_ci ret = zram_group_fault_obj(zram, index); 12648c2ecf20Sopenharmony_ci if (ret) { 12658c2ecf20Sopenharmony_ci zram_slot_unlock(zram, index); 12668c2ecf20Sopenharmony_ci return ret; 12678c2ecf20Sopenharmony_ci } 12688c2ecf20Sopenharmony_ci } 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci if (zram_test_flag(zram, index, ZRAM_GWB)) { 12718c2ecf20Sopenharmony_ci zram_slot_unlock(zram, index); 12728c2ecf20Sopenharmony_ci return -EIO; 12738c2ecf20Sopenharmony_ci } 12748c2ecf20Sopenharmony_ci#endif 12758c2ecf20Sopenharmony_ci handle = zram_get_handle(zram, index); 12768c2ecf20Sopenharmony_ci if (!handle || zram_test_flag(zram, index, ZRAM_SAME)) { 12778c2ecf20Sopenharmony_ci unsigned long value; 12788c2ecf20Sopenharmony_ci void *mem; 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci value = handle ? zram_get_element(zram, index) : 0; 12818c2ecf20Sopenharmony_ci mem = kmap_atomic(page); 12828c2ecf20Sopenharmony_ci zram_fill_page(mem, PAGE_SIZE, value); 12838c2ecf20Sopenharmony_ci kunmap_atomic(mem); 12848c2ecf20Sopenharmony_ci zram_slot_unlock(zram, index); 12858c2ecf20Sopenharmony_ci return 0; 12868c2ecf20Sopenharmony_ci } 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci size = zram_get_obj_size(zram, index); 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci if (size != PAGE_SIZE) 12918c2ecf20Sopenharmony_ci zstrm = zcomp_stream_get(zram->comp); 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci src = zs_map_object(zram->mem_pool, handle, ZS_MM_RO); 12948c2ecf20Sopenharmony_ci if (size == PAGE_SIZE) { 12958c2ecf20Sopenharmony_ci dst = kmap_atomic(page); 12968c2ecf20Sopenharmony_ci memcpy(dst, src, PAGE_SIZE); 12978c2ecf20Sopenharmony_ci kunmap_atomic(dst); 12988c2ecf20Sopenharmony_ci ret = 0; 12998c2ecf20Sopenharmony_ci } else { 13008c2ecf20Sopenharmony_ci dst = kmap_atomic(page); 13018c2ecf20Sopenharmony_ci ret = zcomp_decompress(zstrm, src, size, dst); 13028c2ecf20Sopenharmony_ci kunmap_atomic(dst); 13038c2ecf20Sopenharmony_ci zcomp_stream_put(zram->comp); 13048c2ecf20Sopenharmony_ci } 13058c2ecf20Sopenharmony_ci zs_unmap_object(zram->mem_pool, handle); 13068c2ecf20Sopenharmony_ci zram_slot_unlock(zram, index); 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci /* Should NEVER happen. Return bio error if it does. */ 13098c2ecf20Sopenharmony_ci if (WARN_ON(ret)) 13108c2ecf20Sopenharmony_ci pr_err("Decompression failed! err=%d, page=%u\n", ret, index); 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci return ret; 13138c2ecf20Sopenharmony_ci} 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_cistatic int zram_bvec_read(struct zram *zram, struct bio_vec *bvec, 13168c2ecf20Sopenharmony_ci u32 index, int offset, struct bio *bio) 13178c2ecf20Sopenharmony_ci{ 13188c2ecf20Sopenharmony_ci int ret; 13198c2ecf20Sopenharmony_ci struct page *page; 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci page = bvec->bv_page; 13228c2ecf20Sopenharmony_ci if (is_partial_io(bvec)) { 13238c2ecf20Sopenharmony_ci /* Use a temporary buffer to decompress the page */ 13248c2ecf20Sopenharmony_ci page = alloc_page(GFP_NOIO|__GFP_HIGHMEM); 13258c2ecf20Sopenharmony_ci if (!page) 13268c2ecf20Sopenharmony_ci return -ENOMEM; 13278c2ecf20Sopenharmony_ci } 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci ret = __zram_bvec_read(zram, page, index, bio, is_partial_io(bvec)); 13308c2ecf20Sopenharmony_ci if (unlikely(ret)) 13318c2ecf20Sopenharmony_ci goto out; 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci if (is_partial_io(bvec)) { 13348c2ecf20Sopenharmony_ci void *dst = kmap_atomic(bvec->bv_page); 13358c2ecf20Sopenharmony_ci void *src = kmap_atomic(page); 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci memcpy(dst + bvec->bv_offset, src + offset, bvec->bv_len); 13388c2ecf20Sopenharmony_ci kunmap_atomic(src); 13398c2ecf20Sopenharmony_ci kunmap_atomic(dst); 13408c2ecf20Sopenharmony_ci } 13418c2ecf20Sopenharmony_ciout: 13428c2ecf20Sopenharmony_ci if (is_partial_io(bvec)) 13438c2ecf20Sopenharmony_ci __free_page(page); 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci return ret; 13468c2ecf20Sopenharmony_ci} 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_cistatic int __zram_bvec_write(struct zram *zram, struct bio_vec *bvec, 13498c2ecf20Sopenharmony_ci u32 index, struct bio *bio) 13508c2ecf20Sopenharmony_ci{ 13518c2ecf20Sopenharmony_ci int ret = 0; 13528c2ecf20Sopenharmony_ci unsigned long alloced_pages; 13538c2ecf20Sopenharmony_ci unsigned long handle = 0; 13548c2ecf20Sopenharmony_ci unsigned int comp_len = 0; 13558c2ecf20Sopenharmony_ci void *src, *dst, *mem; 13568c2ecf20Sopenharmony_ci struct zcomp_strm *zstrm; 13578c2ecf20Sopenharmony_ci struct page *page = bvec->bv_page; 13588c2ecf20Sopenharmony_ci unsigned long element = 0; 13598c2ecf20Sopenharmony_ci enum zram_pageflags flags = 0; 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci mem = kmap_atomic(page); 13628c2ecf20Sopenharmony_ci if (page_same_filled(mem, &element)) { 13638c2ecf20Sopenharmony_ci kunmap_atomic(mem); 13648c2ecf20Sopenharmony_ci /* Free memory associated with this sector now. */ 13658c2ecf20Sopenharmony_ci flags = ZRAM_SAME; 13668c2ecf20Sopenharmony_ci atomic64_inc(&zram->stats.same_pages); 13678c2ecf20Sopenharmony_ci goto out; 13688c2ecf20Sopenharmony_ci } 13698c2ecf20Sopenharmony_ci kunmap_atomic(mem); 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_cicompress_again: 13728c2ecf20Sopenharmony_ci zstrm = zcomp_stream_get(zram->comp); 13738c2ecf20Sopenharmony_ci src = kmap_atomic(page); 13748c2ecf20Sopenharmony_ci ret = zcomp_compress(zstrm, src, &comp_len); 13758c2ecf20Sopenharmony_ci kunmap_atomic(src); 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci if (unlikely(ret)) { 13788c2ecf20Sopenharmony_ci zcomp_stream_put(zram->comp); 13798c2ecf20Sopenharmony_ci pr_err("Compression failed! err=%d\n", ret); 13808c2ecf20Sopenharmony_ci zs_free(zram->mem_pool, handle); 13818c2ecf20Sopenharmony_ci return ret; 13828c2ecf20Sopenharmony_ci } 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci if (comp_len >= huge_class_size) 13858c2ecf20Sopenharmony_ci comp_len = PAGE_SIZE; 13868c2ecf20Sopenharmony_ci /* 13878c2ecf20Sopenharmony_ci * handle allocation has 2 paths: 13888c2ecf20Sopenharmony_ci * a) fast path is executed with preemption disabled (for 13898c2ecf20Sopenharmony_ci * per-cpu streams) and has __GFP_DIRECT_RECLAIM bit clear, 13908c2ecf20Sopenharmony_ci * since we can't sleep; 13918c2ecf20Sopenharmony_ci * b) slow path enables preemption and attempts to allocate 13928c2ecf20Sopenharmony_ci * the page with __GFP_DIRECT_RECLAIM bit set. we have to 13938c2ecf20Sopenharmony_ci * put per-cpu compression stream and, thus, to re-do 13948c2ecf20Sopenharmony_ci * the compression once handle is allocated. 13958c2ecf20Sopenharmony_ci * 13968c2ecf20Sopenharmony_ci * if we have a 'non-null' handle here then we are coming 13978c2ecf20Sopenharmony_ci * from the slow path and handle has already been allocated. 13988c2ecf20Sopenharmony_ci */ 13998c2ecf20Sopenharmony_ci if (!handle) 14008c2ecf20Sopenharmony_ci handle = zs_malloc(zram->mem_pool, comp_len, 14018c2ecf20Sopenharmony_ci __GFP_KSWAPD_RECLAIM | 14028c2ecf20Sopenharmony_ci __GFP_NOWARN | 14038c2ecf20Sopenharmony_ci __GFP_HIGHMEM | 14048c2ecf20Sopenharmony_ci __GFP_MOVABLE); 14058c2ecf20Sopenharmony_ci if (!handle) { 14068c2ecf20Sopenharmony_ci zcomp_stream_put(zram->comp); 14078c2ecf20Sopenharmony_ci atomic64_inc(&zram->stats.writestall); 14088c2ecf20Sopenharmony_ci handle = zs_malloc(zram->mem_pool, comp_len, 14098c2ecf20Sopenharmony_ci GFP_NOIO | __GFP_HIGHMEM | 14108c2ecf20Sopenharmony_ci __GFP_MOVABLE); 14118c2ecf20Sopenharmony_ci if (handle) 14128c2ecf20Sopenharmony_ci goto compress_again; 14138c2ecf20Sopenharmony_ci return -ENOMEM; 14148c2ecf20Sopenharmony_ci } 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci alloced_pages = zs_get_total_pages(zram->mem_pool); 14178c2ecf20Sopenharmony_ci update_used_max(zram, alloced_pages); 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci if (zram->limit_pages && alloced_pages > zram->limit_pages) { 14208c2ecf20Sopenharmony_ci zcomp_stream_put(zram->comp); 14218c2ecf20Sopenharmony_ci zs_free(zram->mem_pool, handle); 14228c2ecf20Sopenharmony_ci return -ENOMEM; 14238c2ecf20Sopenharmony_ci } 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci dst = zs_map_object(zram->mem_pool, handle, ZS_MM_WO); 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci src = zstrm->buffer; 14288c2ecf20Sopenharmony_ci if (comp_len == PAGE_SIZE) 14298c2ecf20Sopenharmony_ci src = kmap_atomic(page); 14308c2ecf20Sopenharmony_ci memcpy(dst, src, comp_len); 14318c2ecf20Sopenharmony_ci if (comp_len == PAGE_SIZE) 14328c2ecf20Sopenharmony_ci kunmap_atomic(src); 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci zcomp_stream_put(zram->comp); 14358c2ecf20Sopenharmony_ci zs_unmap_object(zram->mem_pool, handle); 14368c2ecf20Sopenharmony_ci atomic64_add(comp_len, &zram->stats.compr_data_size); 14378c2ecf20Sopenharmony_ciout: 14388c2ecf20Sopenharmony_ci /* 14398c2ecf20Sopenharmony_ci * Free memory associated with this sector 14408c2ecf20Sopenharmony_ci * before overwriting unused sectors. 14418c2ecf20Sopenharmony_ci */ 14428c2ecf20Sopenharmony_ci zram_slot_lock(zram, index); 14438c2ecf20Sopenharmony_ci zram_free_page(zram, index); 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ci if (comp_len == PAGE_SIZE) { 14468c2ecf20Sopenharmony_ci zram_set_flag(zram, index, ZRAM_HUGE); 14478c2ecf20Sopenharmony_ci atomic64_inc(&zram->stats.huge_pages); 14488c2ecf20Sopenharmony_ci } 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci if (flags) { 14518c2ecf20Sopenharmony_ci zram_set_flag(zram, index, flags); 14528c2ecf20Sopenharmony_ci zram_set_element(zram, index, element); 14538c2ecf20Sopenharmony_ci } else { 14548c2ecf20Sopenharmony_ci zram_set_handle(zram, index, handle); 14558c2ecf20Sopenharmony_ci zram_set_obj_size(zram, index, comp_len); 14568c2ecf20Sopenharmony_ci } 14578c2ecf20Sopenharmony_ci#ifdef CONFIG_ZRAM_GROUP 14588c2ecf20Sopenharmony_ci zram_group_track_obj(zram, index, page->mem_cgroup); 14598c2ecf20Sopenharmony_ci#endif 14608c2ecf20Sopenharmony_ci zram_slot_unlock(zram, index); 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci /* Update stats */ 14638c2ecf20Sopenharmony_ci atomic64_inc(&zram->stats.pages_stored); 14648c2ecf20Sopenharmony_ci return ret; 14658c2ecf20Sopenharmony_ci} 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_cistatic int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, 14688c2ecf20Sopenharmony_ci u32 index, int offset, struct bio *bio) 14698c2ecf20Sopenharmony_ci{ 14708c2ecf20Sopenharmony_ci int ret; 14718c2ecf20Sopenharmony_ci struct page *page = NULL; 14728c2ecf20Sopenharmony_ci void *src; 14738c2ecf20Sopenharmony_ci struct bio_vec vec; 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci vec = *bvec; 14768c2ecf20Sopenharmony_ci if (is_partial_io(bvec)) { 14778c2ecf20Sopenharmony_ci void *dst; 14788c2ecf20Sopenharmony_ci /* 14798c2ecf20Sopenharmony_ci * This is a partial IO. We need to read the full page 14808c2ecf20Sopenharmony_ci * before to write the changes. 14818c2ecf20Sopenharmony_ci */ 14828c2ecf20Sopenharmony_ci page = alloc_page(GFP_NOIO|__GFP_HIGHMEM); 14838c2ecf20Sopenharmony_ci if (!page) 14848c2ecf20Sopenharmony_ci return -ENOMEM; 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci ret = __zram_bvec_read(zram, page, index, bio, true); 14878c2ecf20Sopenharmony_ci if (ret) 14888c2ecf20Sopenharmony_ci goto out; 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci src = kmap_atomic(bvec->bv_page); 14918c2ecf20Sopenharmony_ci dst = kmap_atomic(page); 14928c2ecf20Sopenharmony_ci memcpy(dst + offset, src + bvec->bv_offset, bvec->bv_len); 14938c2ecf20Sopenharmony_ci kunmap_atomic(dst); 14948c2ecf20Sopenharmony_ci kunmap_atomic(src); 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci vec.bv_page = page; 14978c2ecf20Sopenharmony_ci vec.bv_len = PAGE_SIZE; 14988c2ecf20Sopenharmony_ci vec.bv_offset = 0; 14998c2ecf20Sopenharmony_ci } 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci ret = __zram_bvec_write(zram, &vec, index, bio); 15028c2ecf20Sopenharmony_ciout: 15038c2ecf20Sopenharmony_ci if (is_partial_io(bvec)) 15048c2ecf20Sopenharmony_ci __free_page(page); 15058c2ecf20Sopenharmony_ci return ret; 15068c2ecf20Sopenharmony_ci} 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci/* 15098c2ecf20Sopenharmony_ci * zram_bio_discard - handler on discard request 15108c2ecf20Sopenharmony_ci * @index: physical block index in PAGE_SIZE units 15118c2ecf20Sopenharmony_ci * @offset: byte offset within physical block 15128c2ecf20Sopenharmony_ci */ 15138c2ecf20Sopenharmony_cistatic void zram_bio_discard(struct zram *zram, u32 index, 15148c2ecf20Sopenharmony_ci int offset, struct bio *bio) 15158c2ecf20Sopenharmony_ci{ 15168c2ecf20Sopenharmony_ci size_t n = bio->bi_iter.bi_size; 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci /* 15198c2ecf20Sopenharmony_ci * zram manages data in physical block size units. Because logical block 15208c2ecf20Sopenharmony_ci * size isn't identical with physical block size on some arch, we 15218c2ecf20Sopenharmony_ci * could get a discard request pointing to a specific offset within a 15228c2ecf20Sopenharmony_ci * certain physical block. Although we can handle this request by 15238c2ecf20Sopenharmony_ci * reading that physiclal block and decompressing and partially zeroing 15248c2ecf20Sopenharmony_ci * and re-compressing and then re-storing it, this isn't reasonable 15258c2ecf20Sopenharmony_ci * because our intent with a discard request is to save memory. So 15268c2ecf20Sopenharmony_ci * skipping this logical block is appropriate here. 15278c2ecf20Sopenharmony_ci */ 15288c2ecf20Sopenharmony_ci if (offset) { 15298c2ecf20Sopenharmony_ci if (n <= (PAGE_SIZE - offset)) 15308c2ecf20Sopenharmony_ci return; 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci n -= (PAGE_SIZE - offset); 15338c2ecf20Sopenharmony_ci index++; 15348c2ecf20Sopenharmony_ci } 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci while (n >= PAGE_SIZE) { 15378c2ecf20Sopenharmony_ci zram_slot_lock(zram, index); 15388c2ecf20Sopenharmony_ci zram_free_page(zram, index); 15398c2ecf20Sopenharmony_ci zram_slot_unlock(zram, index); 15408c2ecf20Sopenharmony_ci atomic64_inc(&zram->stats.notify_free); 15418c2ecf20Sopenharmony_ci index++; 15428c2ecf20Sopenharmony_ci n -= PAGE_SIZE; 15438c2ecf20Sopenharmony_ci } 15448c2ecf20Sopenharmony_ci} 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci/* 15478c2ecf20Sopenharmony_ci * Returns errno if it has some problem. Otherwise return 0 or 1. 15488c2ecf20Sopenharmony_ci * Returns 0 if IO request was done synchronously 15498c2ecf20Sopenharmony_ci * Returns 1 if IO request was successfully submitted. 15508c2ecf20Sopenharmony_ci */ 15518c2ecf20Sopenharmony_cistatic int zram_bvec_rw(struct zram *zram, struct bio_vec *bvec, u32 index, 15528c2ecf20Sopenharmony_ci int offset, unsigned int op, struct bio *bio) 15538c2ecf20Sopenharmony_ci{ 15548c2ecf20Sopenharmony_ci int ret; 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci if (!op_is_write(op)) { 15578c2ecf20Sopenharmony_ci atomic64_inc(&zram->stats.num_reads); 15588c2ecf20Sopenharmony_ci ret = zram_bvec_read(zram, bvec, index, offset, bio); 15598c2ecf20Sopenharmony_ci flush_dcache_page(bvec->bv_page); 15608c2ecf20Sopenharmony_ci } else { 15618c2ecf20Sopenharmony_ci atomic64_inc(&zram->stats.num_writes); 15628c2ecf20Sopenharmony_ci ret = zram_bvec_write(zram, bvec, index, offset, bio); 15638c2ecf20Sopenharmony_ci } 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci zram_slot_lock(zram, index); 15668c2ecf20Sopenharmony_ci zram_accessed(zram, index); 15678c2ecf20Sopenharmony_ci zram_slot_unlock(zram, index); 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci if (unlikely(ret < 0)) { 15708c2ecf20Sopenharmony_ci if (!op_is_write(op)) 15718c2ecf20Sopenharmony_ci atomic64_inc(&zram->stats.failed_reads); 15728c2ecf20Sopenharmony_ci else 15738c2ecf20Sopenharmony_ci atomic64_inc(&zram->stats.failed_writes); 15748c2ecf20Sopenharmony_ci } 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_ci return ret; 15778c2ecf20Sopenharmony_ci} 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_cistatic void __zram_make_request(struct zram *zram, struct bio *bio) 15808c2ecf20Sopenharmony_ci{ 15818c2ecf20Sopenharmony_ci int offset; 15828c2ecf20Sopenharmony_ci u32 index; 15838c2ecf20Sopenharmony_ci struct bio_vec bvec; 15848c2ecf20Sopenharmony_ci struct bvec_iter iter; 15858c2ecf20Sopenharmony_ci unsigned long start_time; 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci index = bio->bi_iter.bi_sector >> SECTORS_PER_PAGE_SHIFT; 15888c2ecf20Sopenharmony_ci offset = (bio->bi_iter.bi_sector & 15898c2ecf20Sopenharmony_ci (SECTORS_PER_PAGE - 1)) << SECTOR_SHIFT; 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_ci switch (bio_op(bio)) { 15928c2ecf20Sopenharmony_ci case REQ_OP_DISCARD: 15938c2ecf20Sopenharmony_ci case REQ_OP_WRITE_ZEROES: 15948c2ecf20Sopenharmony_ci zram_bio_discard(zram, index, offset, bio); 15958c2ecf20Sopenharmony_ci bio_endio(bio); 15968c2ecf20Sopenharmony_ci return; 15978c2ecf20Sopenharmony_ci default: 15988c2ecf20Sopenharmony_ci break; 15998c2ecf20Sopenharmony_ci } 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci start_time = bio_start_io_acct(bio); 16028c2ecf20Sopenharmony_ci bio_for_each_segment(bvec, bio, iter) { 16038c2ecf20Sopenharmony_ci struct bio_vec bv = bvec; 16048c2ecf20Sopenharmony_ci unsigned int unwritten = bvec.bv_len; 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci do { 16078c2ecf20Sopenharmony_ci bv.bv_len = min_t(unsigned int, PAGE_SIZE - offset, 16088c2ecf20Sopenharmony_ci unwritten); 16098c2ecf20Sopenharmony_ci if (zram_bvec_rw(zram, &bv, index, offset, 16108c2ecf20Sopenharmony_ci bio_op(bio), bio) < 0) { 16118c2ecf20Sopenharmony_ci bio->bi_status = BLK_STS_IOERR; 16128c2ecf20Sopenharmony_ci break; 16138c2ecf20Sopenharmony_ci } 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci bv.bv_offset += bv.bv_len; 16168c2ecf20Sopenharmony_ci unwritten -= bv.bv_len; 16178c2ecf20Sopenharmony_ci 16188c2ecf20Sopenharmony_ci update_position(&index, &offset, &bv); 16198c2ecf20Sopenharmony_ci } while (unwritten); 16208c2ecf20Sopenharmony_ci } 16218c2ecf20Sopenharmony_ci bio_end_io_acct(bio, start_time); 16228c2ecf20Sopenharmony_ci bio_endio(bio); 16238c2ecf20Sopenharmony_ci} 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_ci/* 16268c2ecf20Sopenharmony_ci * Handler function for all zram I/O requests. 16278c2ecf20Sopenharmony_ci */ 16288c2ecf20Sopenharmony_cistatic blk_qc_t zram_submit_bio(struct bio *bio) 16298c2ecf20Sopenharmony_ci{ 16308c2ecf20Sopenharmony_ci struct zram *zram = bio->bi_disk->private_data; 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci if (!valid_io_request(zram, bio->bi_iter.bi_sector, 16338c2ecf20Sopenharmony_ci bio->bi_iter.bi_size)) { 16348c2ecf20Sopenharmony_ci atomic64_inc(&zram->stats.invalid_io); 16358c2ecf20Sopenharmony_ci goto error; 16368c2ecf20Sopenharmony_ci } 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci __zram_make_request(zram, bio); 16398c2ecf20Sopenharmony_ci return BLK_QC_T_NONE; 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_cierror: 16428c2ecf20Sopenharmony_ci bio_io_error(bio); 16438c2ecf20Sopenharmony_ci return BLK_QC_T_NONE; 16448c2ecf20Sopenharmony_ci} 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_cistatic void zram_slot_free_notify(struct block_device *bdev, 16478c2ecf20Sopenharmony_ci unsigned long index) 16488c2ecf20Sopenharmony_ci{ 16498c2ecf20Sopenharmony_ci struct zram *zram; 16508c2ecf20Sopenharmony_ci 16518c2ecf20Sopenharmony_ci zram = bdev->bd_disk->private_data; 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci atomic64_inc(&zram->stats.notify_free); 16548c2ecf20Sopenharmony_ci if (!zram_slot_trylock(zram, index)) { 16558c2ecf20Sopenharmony_ci atomic64_inc(&zram->stats.miss_free); 16568c2ecf20Sopenharmony_ci return; 16578c2ecf20Sopenharmony_ci } 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_ci zram_free_page(zram, index); 16608c2ecf20Sopenharmony_ci zram_slot_unlock(zram, index); 16618c2ecf20Sopenharmony_ci} 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_cistatic int zram_rw_page(struct block_device *bdev, sector_t sector, 16648c2ecf20Sopenharmony_ci struct page *page, unsigned int op) 16658c2ecf20Sopenharmony_ci{ 16668c2ecf20Sopenharmony_ci int offset, ret; 16678c2ecf20Sopenharmony_ci u32 index; 16688c2ecf20Sopenharmony_ci struct zram *zram; 16698c2ecf20Sopenharmony_ci struct bio_vec bv; 16708c2ecf20Sopenharmony_ci unsigned long start_time; 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci if (PageTransHuge(page)) 16738c2ecf20Sopenharmony_ci return -ENOTSUPP; 16748c2ecf20Sopenharmony_ci zram = bdev->bd_disk->private_data; 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ci if (!valid_io_request(zram, sector, PAGE_SIZE)) { 16778c2ecf20Sopenharmony_ci atomic64_inc(&zram->stats.invalid_io); 16788c2ecf20Sopenharmony_ci ret = -EINVAL; 16798c2ecf20Sopenharmony_ci goto out; 16808c2ecf20Sopenharmony_ci } 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_ci index = sector >> SECTORS_PER_PAGE_SHIFT; 16838c2ecf20Sopenharmony_ci offset = (sector & (SECTORS_PER_PAGE - 1)) << SECTOR_SHIFT; 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci bv.bv_page = page; 16868c2ecf20Sopenharmony_ci bv.bv_len = PAGE_SIZE; 16878c2ecf20Sopenharmony_ci bv.bv_offset = 0; 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_ci start_time = disk_start_io_acct(bdev->bd_disk, SECTORS_PER_PAGE, op); 16908c2ecf20Sopenharmony_ci ret = zram_bvec_rw(zram, &bv, index, offset, op, NULL); 16918c2ecf20Sopenharmony_ci disk_end_io_acct(bdev->bd_disk, op, start_time); 16928c2ecf20Sopenharmony_ciout: 16938c2ecf20Sopenharmony_ci /* 16948c2ecf20Sopenharmony_ci * If I/O fails, just return error(ie, non-zero) without 16958c2ecf20Sopenharmony_ci * calling page_endio. 16968c2ecf20Sopenharmony_ci * It causes resubmit the I/O with bio request by upper functions 16978c2ecf20Sopenharmony_ci * of rw_page(e.g., swap_readpage, __swap_writepage) and 16988c2ecf20Sopenharmony_ci * bio->bi_end_io does things to handle the error 16998c2ecf20Sopenharmony_ci * (e.g., SetPageError, set_page_dirty and extra works). 17008c2ecf20Sopenharmony_ci */ 17018c2ecf20Sopenharmony_ci if (unlikely(ret < 0)) 17028c2ecf20Sopenharmony_ci return ret; 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_ci switch (ret) { 17058c2ecf20Sopenharmony_ci case 0: 17068c2ecf20Sopenharmony_ci page_endio(page, op_is_write(op), 0); 17078c2ecf20Sopenharmony_ci break; 17088c2ecf20Sopenharmony_ci case 1: 17098c2ecf20Sopenharmony_ci ret = 0; 17108c2ecf20Sopenharmony_ci break; 17118c2ecf20Sopenharmony_ci default: 17128c2ecf20Sopenharmony_ci WARN_ON(1); 17138c2ecf20Sopenharmony_ci } 17148c2ecf20Sopenharmony_ci return ret; 17158c2ecf20Sopenharmony_ci} 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_cistatic void zram_reset_device(struct zram *zram) 17188c2ecf20Sopenharmony_ci{ 17198c2ecf20Sopenharmony_ci struct zcomp *comp; 17208c2ecf20Sopenharmony_ci u64 disksize; 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_ci down_write(&zram->init_lock); 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci zram->limit_pages = 0; 17258c2ecf20Sopenharmony_ci 17268c2ecf20Sopenharmony_ci if (!init_done(zram)) { 17278c2ecf20Sopenharmony_ci up_write(&zram->init_lock); 17288c2ecf20Sopenharmony_ci return; 17298c2ecf20Sopenharmony_ci } 17308c2ecf20Sopenharmony_ci 17318c2ecf20Sopenharmony_ci comp = zram->comp; 17328c2ecf20Sopenharmony_ci disksize = zram->disksize; 17338c2ecf20Sopenharmony_ci zram->disksize = 0; 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_ci set_capacity(zram->disk, 0); 17368c2ecf20Sopenharmony_ci part_stat_set_all(&zram->disk->part0, 0); 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_ci up_write(&zram->init_lock); 17398c2ecf20Sopenharmony_ci /* I/O operation under all of CPU are done so let's free */ 17408c2ecf20Sopenharmony_ci zram_meta_free(zram, disksize); 17418c2ecf20Sopenharmony_ci memset(&zram->stats, 0, sizeof(zram->stats)); 17428c2ecf20Sopenharmony_ci zcomp_destroy(comp); 17438c2ecf20Sopenharmony_ci reset_bdev(zram); 17448c2ecf20Sopenharmony_ci} 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_cistatic ssize_t disksize_store(struct device *dev, 17478c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t len) 17488c2ecf20Sopenharmony_ci{ 17498c2ecf20Sopenharmony_ci u64 disksize; 17508c2ecf20Sopenharmony_ci struct zcomp *comp; 17518c2ecf20Sopenharmony_ci struct zram *zram = dev_to_zram(dev); 17528c2ecf20Sopenharmony_ci int err; 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_ci disksize = memparse(buf, NULL); 17558c2ecf20Sopenharmony_ci if (!disksize) 17568c2ecf20Sopenharmony_ci return -EINVAL; 17578c2ecf20Sopenharmony_ci 17588c2ecf20Sopenharmony_ci down_write(&zram->init_lock); 17598c2ecf20Sopenharmony_ci if (init_done(zram)) { 17608c2ecf20Sopenharmony_ci pr_info("Cannot change disksize for initialized device\n"); 17618c2ecf20Sopenharmony_ci err = -EBUSY; 17628c2ecf20Sopenharmony_ci goto out_unlock; 17638c2ecf20Sopenharmony_ci } 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_ci disksize = PAGE_ALIGN(disksize); 17668c2ecf20Sopenharmony_ci if (!zram_meta_alloc(zram, disksize)) { 17678c2ecf20Sopenharmony_ci err = -ENOMEM; 17688c2ecf20Sopenharmony_ci goto out_unlock; 17698c2ecf20Sopenharmony_ci } 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_ci comp = zcomp_create(zram->compressor); 17728c2ecf20Sopenharmony_ci if (IS_ERR(comp)) { 17738c2ecf20Sopenharmony_ci pr_err("Cannot initialise %s compressing backend\n", 17748c2ecf20Sopenharmony_ci zram->compressor); 17758c2ecf20Sopenharmony_ci err = PTR_ERR(comp); 17768c2ecf20Sopenharmony_ci goto out_free_meta; 17778c2ecf20Sopenharmony_ci } 17788c2ecf20Sopenharmony_ci 17798c2ecf20Sopenharmony_ci zram->comp = comp; 17808c2ecf20Sopenharmony_ci zram->disksize = disksize; 17818c2ecf20Sopenharmony_ci set_capacity(zram->disk, zram->disksize >> SECTOR_SHIFT); 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_ci revalidate_disk_size(zram->disk, true); 17848c2ecf20Sopenharmony_ci up_write(&zram->init_lock); 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_ci return len; 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_ciout_free_meta: 17898c2ecf20Sopenharmony_ci zram_meta_free(zram, disksize); 17908c2ecf20Sopenharmony_ciout_unlock: 17918c2ecf20Sopenharmony_ci up_write(&zram->init_lock); 17928c2ecf20Sopenharmony_ci return err; 17938c2ecf20Sopenharmony_ci} 17948c2ecf20Sopenharmony_ci 17958c2ecf20Sopenharmony_cistatic ssize_t reset_store(struct device *dev, 17968c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t len) 17978c2ecf20Sopenharmony_ci{ 17988c2ecf20Sopenharmony_ci int ret; 17998c2ecf20Sopenharmony_ci unsigned short do_reset; 18008c2ecf20Sopenharmony_ci struct zram *zram; 18018c2ecf20Sopenharmony_ci struct block_device *bdev; 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_ci ret = kstrtou16(buf, 10, &do_reset); 18048c2ecf20Sopenharmony_ci if (ret) 18058c2ecf20Sopenharmony_ci return ret; 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci if (!do_reset) 18088c2ecf20Sopenharmony_ci return -EINVAL; 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_ci zram = dev_to_zram(dev); 18118c2ecf20Sopenharmony_ci bdev = bdget_disk(zram->disk, 0); 18128c2ecf20Sopenharmony_ci if (!bdev) 18138c2ecf20Sopenharmony_ci return -ENOMEM; 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci mutex_lock(&bdev->bd_mutex); 18168c2ecf20Sopenharmony_ci /* Do not reset an active device or claimed device */ 18178c2ecf20Sopenharmony_ci if (bdev->bd_openers || zram->claim) { 18188c2ecf20Sopenharmony_ci mutex_unlock(&bdev->bd_mutex); 18198c2ecf20Sopenharmony_ci bdput(bdev); 18208c2ecf20Sopenharmony_ci return -EBUSY; 18218c2ecf20Sopenharmony_ci } 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_ci /* From now on, anyone can't open /dev/zram[0-9] */ 18248c2ecf20Sopenharmony_ci zram->claim = true; 18258c2ecf20Sopenharmony_ci mutex_unlock(&bdev->bd_mutex); 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ci /* Make sure all the pending I/O are finished */ 18288c2ecf20Sopenharmony_ci fsync_bdev(bdev); 18298c2ecf20Sopenharmony_ci zram_reset_device(zram); 18308c2ecf20Sopenharmony_ci revalidate_disk_size(zram->disk, true); 18318c2ecf20Sopenharmony_ci bdput(bdev); 18328c2ecf20Sopenharmony_ci 18338c2ecf20Sopenharmony_ci mutex_lock(&bdev->bd_mutex); 18348c2ecf20Sopenharmony_ci zram->claim = false; 18358c2ecf20Sopenharmony_ci mutex_unlock(&bdev->bd_mutex); 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_ci return len; 18388c2ecf20Sopenharmony_ci} 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_cistatic int zram_open(struct block_device *bdev, fmode_t mode) 18418c2ecf20Sopenharmony_ci{ 18428c2ecf20Sopenharmony_ci int ret = 0; 18438c2ecf20Sopenharmony_ci struct zram *zram; 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_ci WARN_ON(!mutex_is_locked(&bdev->bd_mutex)); 18468c2ecf20Sopenharmony_ci 18478c2ecf20Sopenharmony_ci zram = bdev->bd_disk->private_data; 18488c2ecf20Sopenharmony_ci /* zram was claimed to reset so open request fails */ 18498c2ecf20Sopenharmony_ci if (zram->claim) 18508c2ecf20Sopenharmony_ci ret = -EBUSY; 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_ci return ret; 18538c2ecf20Sopenharmony_ci} 18548c2ecf20Sopenharmony_ci 18558c2ecf20Sopenharmony_cistatic const struct block_device_operations zram_devops = { 18568c2ecf20Sopenharmony_ci .open = zram_open, 18578c2ecf20Sopenharmony_ci .submit_bio = zram_submit_bio, 18588c2ecf20Sopenharmony_ci .swap_slot_free_notify = zram_slot_free_notify, 18598c2ecf20Sopenharmony_ci .rw_page = zram_rw_page, 18608c2ecf20Sopenharmony_ci .owner = THIS_MODULE 18618c2ecf20Sopenharmony_ci}; 18628c2ecf20Sopenharmony_ci 18638c2ecf20Sopenharmony_cistatic const struct block_device_operations zram_wb_devops = { 18648c2ecf20Sopenharmony_ci .open = zram_open, 18658c2ecf20Sopenharmony_ci .submit_bio = zram_submit_bio, 18668c2ecf20Sopenharmony_ci .swap_slot_free_notify = zram_slot_free_notify, 18678c2ecf20Sopenharmony_ci .owner = THIS_MODULE 18688c2ecf20Sopenharmony_ci}; 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_cistatic DEVICE_ATTR_WO(compact); 18718c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(disksize); 18728c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(initstate); 18738c2ecf20Sopenharmony_cistatic DEVICE_ATTR_WO(reset); 18748c2ecf20Sopenharmony_cistatic DEVICE_ATTR_WO(mem_limit); 18758c2ecf20Sopenharmony_cistatic DEVICE_ATTR_WO(mem_used_max); 18768c2ecf20Sopenharmony_cistatic DEVICE_ATTR_WO(idle); 18778c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(max_comp_streams); 18788c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(comp_algorithm); 18798c2ecf20Sopenharmony_ci#ifdef CONFIG_ZRAM_WRITEBACK 18808c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(backing_dev); 18818c2ecf20Sopenharmony_cistatic DEVICE_ATTR_WO(writeback); 18828c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(writeback_limit); 18838c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(writeback_limit_enable); 18848c2ecf20Sopenharmony_ci#endif 18858c2ecf20Sopenharmony_ci#ifdef CONFIG_ZRAM_GROUP 18868c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(group); 18878c2ecf20Sopenharmony_ci#endif 18888c2ecf20Sopenharmony_ci 18898c2ecf20Sopenharmony_cistatic struct attribute *zram_disk_attrs[] = { 18908c2ecf20Sopenharmony_ci &dev_attr_disksize.attr, 18918c2ecf20Sopenharmony_ci &dev_attr_initstate.attr, 18928c2ecf20Sopenharmony_ci &dev_attr_reset.attr, 18938c2ecf20Sopenharmony_ci &dev_attr_compact.attr, 18948c2ecf20Sopenharmony_ci &dev_attr_mem_limit.attr, 18958c2ecf20Sopenharmony_ci &dev_attr_mem_used_max.attr, 18968c2ecf20Sopenharmony_ci &dev_attr_idle.attr, 18978c2ecf20Sopenharmony_ci &dev_attr_max_comp_streams.attr, 18988c2ecf20Sopenharmony_ci &dev_attr_comp_algorithm.attr, 18998c2ecf20Sopenharmony_ci#ifdef CONFIG_ZRAM_WRITEBACK 19008c2ecf20Sopenharmony_ci &dev_attr_backing_dev.attr, 19018c2ecf20Sopenharmony_ci &dev_attr_writeback.attr, 19028c2ecf20Sopenharmony_ci &dev_attr_writeback_limit.attr, 19038c2ecf20Sopenharmony_ci &dev_attr_writeback_limit_enable.attr, 19048c2ecf20Sopenharmony_ci#endif 19058c2ecf20Sopenharmony_ci &dev_attr_io_stat.attr, 19068c2ecf20Sopenharmony_ci &dev_attr_mm_stat.attr, 19078c2ecf20Sopenharmony_ci#ifdef CONFIG_ZRAM_WRITEBACK 19088c2ecf20Sopenharmony_ci &dev_attr_bd_stat.attr, 19098c2ecf20Sopenharmony_ci#endif 19108c2ecf20Sopenharmony_ci &dev_attr_debug_stat.attr, 19118c2ecf20Sopenharmony_ci#ifdef CONFIG_ZRAM_GROUP 19128c2ecf20Sopenharmony_ci &dev_attr_group.attr, 19138c2ecf20Sopenharmony_ci#endif 19148c2ecf20Sopenharmony_ci NULL, 19158c2ecf20Sopenharmony_ci}; 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_cistatic const struct attribute_group zram_disk_attr_group = { 19188c2ecf20Sopenharmony_ci .attrs = zram_disk_attrs, 19198c2ecf20Sopenharmony_ci}; 19208c2ecf20Sopenharmony_ci 19218c2ecf20Sopenharmony_cistatic const struct attribute_group *zram_disk_attr_groups[] = { 19228c2ecf20Sopenharmony_ci &zram_disk_attr_group, 19238c2ecf20Sopenharmony_ci NULL, 19248c2ecf20Sopenharmony_ci}; 19258c2ecf20Sopenharmony_ci 19268c2ecf20Sopenharmony_ci/* 19278c2ecf20Sopenharmony_ci * Allocate and initialize new zram device. the function returns 19288c2ecf20Sopenharmony_ci * '>= 0' device_id upon success, and negative value otherwise. 19298c2ecf20Sopenharmony_ci */ 19308c2ecf20Sopenharmony_cistatic int zram_add(void) 19318c2ecf20Sopenharmony_ci{ 19328c2ecf20Sopenharmony_ci struct zram *zram; 19338c2ecf20Sopenharmony_ci struct request_queue *queue; 19348c2ecf20Sopenharmony_ci int ret, device_id; 19358c2ecf20Sopenharmony_ci 19368c2ecf20Sopenharmony_ci zram = kzalloc(sizeof(struct zram), GFP_KERNEL); 19378c2ecf20Sopenharmony_ci if (!zram) 19388c2ecf20Sopenharmony_ci return -ENOMEM; 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_ci ret = idr_alloc(&zram_index_idr, zram, 0, 0, GFP_KERNEL); 19418c2ecf20Sopenharmony_ci if (ret < 0) 19428c2ecf20Sopenharmony_ci goto out_free_dev; 19438c2ecf20Sopenharmony_ci device_id = ret; 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ci init_rwsem(&zram->init_lock); 19468c2ecf20Sopenharmony_ci#ifdef CONFIG_ZRAM_WRITEBACK 19478c2ecf20Sopenharmony_ci spin_lock_init(&zram->wb_limit_lock); 19488c2ecf20Sopenharmony_ci#endif 19498c2ecf20Sopenharmony_ci queue = blk_alloc_queue(NUMA_NO_NODE); 19508c2ecf20Sopenharmony_ci if (!queue) { 19518c2ecf20Sopenharmony_ci pr_err("Error allocating disk queue for device %d\n", 19528c2ecf20Sopenharmony_ci device_id); 19538c2ecf20Sopenharmony_ci ret = -ENOMEM; 19548c2ecf20Sopenharmony_ci goto out_free_idr; 19558c2ecf20Sopenharmony_ci } 19568c2ecf20Sopenharmony_ci 19578c2ecf20Sopenharmony_ci /* gendisk structure */ 19588c2ecf20Sopenharmony_ci zram->disk = alloc_disk(1); 19598c2ecf20Sopenharmony_ci if (!zram->disk) { 19608c2ecf20Sopenharmony_ci pr_err("Error allocating disk structure for device %d\n", 19618c2ecf20Sopenharmony_ci device_id); 19628c2ecf20Sopenharmony_ci ret = -ENOMEM; 19638c2ecf20Sopenharmony_ci goto out_free_queue; 19648c2ecf20Sopenharmony_ci } 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_ci zram->disk->major = zram_major; 19678c2ecf20Sopenharmony_ci zram->disk->first_minor = device_id; 19688c2ecf20Sopenharmony_ci zram->disk->fops = &zram_devops; 19698c2ecf20Sopenharmony_ci zram->disk->queue = queue; 19708c2ecf20Sopenharmony_ci zram->disk->private_data = zram; 19718c2ecf20Sopenharmony_ci snprintf(zram->disk->disk_name, 16, "zram%d", device_id); 19728c2ecf20Sopenharmony_ci 19738c2ecf20Sopenharmony_ci /* Actual capacity set using syfs (/sys/block/zram<id>/disksize */ 19748c2ecf20Sopenharmony_ci set_capacity(zram->disk, 0); 19758c2ecf20Sopenharmony_ci /* zram devices sort of resembles non-rotational disks */ 19768c2ecf20Sopenharmony_ci blk_queue_flag_set(QUEUE_FLAG_NONROT, zram->disk->queue); 19778c2ecf20Sopenharmony_ci blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, zram->disk->queue); 19788c2ecf20Sopenharmony_ci 19798c2ecf20Sopenharmony_ci /* 19808c2ecf20Sopenharmony_ci * To ensure that we always get PAGE_SIZE aligned 19818c2ecf20Sopenharmony_ci * and n*PAGE_SIZED sized I/O requests. 19828c2ecf20Sopenharmony_ci */ 19838c2ecf20Sopenharmony_ci blk_queue_physical_block_size(zram->disk->queue, PAGE_SIZE); 19848c2ecf20Sopenharmony_ci blk_queue_logical_block_size(zram->disk->queue, 19858c2ecf20Sopenharmony_ci ZRAM_LOGICAL_BLOCK_SIZE); 19868c2ecf20Sopenharmony_ci blk_queue_io_min(zram->disk->queue, PAGE_SIZE); 19878c2ecf20Sopenharmony_ci blk_queue_io_opt(zram->disk->queue, PAGE_SIZE); 19888c2ecf20Sopenharmony_ci zram->disk->queue->limits.discard_granularity = PAGE_SIZE; 19898c2ecf20Sopenharmony_ci blk_queue_max_discard_sectors(zram->disk->queue, UINT_MAX); 19908c2ecf20Sopenharmony_ci blk_queue_flag_set(QUEUE_FLAG_DISCARD, zram->disk->queue); 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_ci /* 19938c2ecf20Sopenharmony_ci * zram_bio_discard() will clear all logical blocks if logical block 19948c2ecf20Sopenharmony_ci * size is identical with physical block size(PAGE_SIZE). But if it is 19958c2ecf20Sopenharmony_ci * different, we will skip discarding some parts of logical blocks in 19968c2ecf20Sopenharmony_ci * the part of the request range which isn't aligned to physical block 19978c2ecf20Sopenharmony_ci * size. So we can't ensure that all discarded logical blocks are 19988c2ecf20Sopenharmony_ci * zeroed. 19998c2ecf20Sopenharmony_ci */ 20008c2ecf20Sopenharmony_ci if (ZRAM_LOGICAL_BLOCK_SIZE == PAGE_SIZE) 20018c2ecf20Sopenharmony_ci blk_queue_max_write_zeroes_sectors(zram->disk->queue, UINT_MAX); 20028c2ecf20Sopenharmony_ci 20038c2ecf20Sopenharmony_ci blk_queue_flag_set(QUEUE_FLAG_STABLE_WRITES, zram->disk->queue); 20048c2ecf20Sopenharmony_ci device_add_disk(NULL, zram->disk, zram_disk_attr_groups); 20058c2ecf20Sopenharmony_ci 20068c2ecf20Sopenharmony_ci strlcpy(zram->compressor, default_compressor, sizeof(zram->compressor)); 20078c2ecf20Sopenharmony_ci 20088c2ecf20Sopenharmony_ci zram_debugfs_register(zram); 20098c2ecf20Sopenharmony_ci pr_info("Added device: %s\n", zram->disk->disk_name); 20108c2ecf20Sopenharmony_ci return device_id; 20118c2ecf20Sopenharmony_ci 20128c2ecf20Sopenharmony_ciout_free_queue: 20138c2ecf20Sopenharmony_ci blk_cleanup_queue(queue); 20148c2ecf20Sopenharmony_ciout_free_idr: 20158c2ecf20Sopenharmony_ci idr_remove(&zram_index_idr, device_id); 20168c2ecf20Sopenharmony_ciout_free_dev: 20178c2ecf20Sopenharmony_ci kfree(zram); 20188c2ecf20Sopenharmony_ci return ret; 20198c2ecf20Sopenharmony_ci} 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_cistatic int zram_remove(struct zram *zram) 20228c2ecf20Sopenharmony_ci{ 20238c2ecf20Sopenharmony_ci struct block_device *bdev; 20248c2ecf20Sopenharmony_ci 20258c2ecf20Sopenharmony_ci bdev = bdget_disk(zram->disk, 0); 20268c2ecf20Sopenharmony_ci if (!bdev) 20278c2ecf20Sopenharmony_ci return -ENOMEM; 20288c2ecf20Sopenharmony_ci 20298c2ecf20Sopenharmony_ci mutex_lock(&bdev->bd_mutex); 20308c2ecf20Sopenharmony_ci if (bdev->bd_openers || zram->claim) { 20318c2ecf20Sopenharmony_ci mutex_unlock(&bdev->bd_mutex); 20328c2ecf20Sopenharmony_ci bdput(bdev); 20338c2ecf20Sopenharmony_ci return -EBUSY; 20348c2ecf20Sopenharmony_ci } 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_ci zram->claim = true; 20378c2ecf20Sopenharmony_ci mutex_unlock(&bdev->bd_mutex); 20388c2ecf20Sopenharmony_ci 20398c2ecf20Sopenharmony_ci zram_debugfs_unregister(zram); 20408c2ecf20Sopenharmony_ci 20418c2ecf20Sopenharmony_ci /* Make sure all the pending I/O are finished */ 20428c2ecf20Sopenharmony_ci fsync_bdev(bdev); 20438c2ecf20Sopenharmony_ci zram_reset_device(zram); 20448c2ecf20Sopenharmony_ci bdput(bdev); 20458c2ecf20Sopenharmony_ci 20468c2ecf20Sopenharmony_ci pr_info("Removed device: %s\n", zram->disk->disk_name); 20478c2ecf20Sopenharmony_ci 20488c2ecf20Sopenharmony_ci del_gendisk(zram->disk); 20498c2ecf20Sopenharmony_ci blk_cleanup_queue(zram->disk->queue); 20508c2ecf20Sopenharmony_ci put_disk(zram->disk); 20518c2ecf20Sopenharmony_ci kfree(zram); 20528c2ecf20Sopenharmony_ci return 0; 20538c2ecf20Sopenharmony_ci} 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci/* zram-control sysfs attributes */ 20568c2ecf20Sopenharmony_ci 20578c2ecf20Sopenharmony_ci/* 20588c2ecf20Sopenharmony_ci * NOTE: hot_add attribute is not the usual read-only sysfs attribute. In a 20598c2ecf20Sopenharmony_ci * sense that reading from this file does alter the state of your system -- it 20608c2ecf20Sopenharmony_ci * creates a new un-initialized zram device and returns back this device's 20618c2ecf20Sopenharmony_ci * device_id (or an error code if it fails to create a new device). 20628c2ecf20Sopenharmony_ci */ 20638c2ecf20Sopenharmony_cistatic ssize_t hot_add_show(struct class *class, 20648c2ecf20Sopenharmony_ci struct class_attribute *attr, 20658c2ecf20Sopenharmony_ci char *buf) 20668c2ecf20Sopenharmony_ci{ 20678c2ecf20Sopenharmony_ci int ret; 20688c2ecf20Sopenharmony_ci 20698c2ecf20Sopenharmony_ci mutex_lock(&zram_index_mutex); 20708c2ecf20Sopenharmony_ci ret = zram_add(); 20718c2ecf20Sopenharmony_ci mutex_unlock(&zram_index_mutex); 20728c2ecf20Sopenharmony_ci 20738c2ecf20Sopenharmony_ci if (ret < 0) 20748c2ecf20Sopenharmony_ci return ret; 20758c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%d\n", ret); 20768c2ecf20Sopenharmony_ci} 20778c2ecf20Sopenharmony_cistatic struct class_attribute class_attr_hot_add = 20788c2ecf20Sopenharmony_ci __ATTR(hot_add, 0400, hot_add_show, NULL); 20798c2ecf20Sopenharmony_ci 20808c2ecf20Sopenharmony_cistatic ssize_t hot_remove_store(struct class *class, 20818c2ecf20Sopenharmony_ci struct class_attribute *attr, 20828c2ecf20Sopenharmony_ci const char *buf, 20838c2ecf20Sopenharmony_ci size_t count) 20848c2ecf20Sopenharmony_ci{ 20858c2ecf20Sopenharmony_ci struct zram *zram; 20868c2ecf20Sopenharmony_ci int ret, dev_id; 20878c2ecf20Sopenharmony_ci 20888c2ecf20Sopenharmony_ci /* dev_id is gendisk->first_minor, which is `int' */ 20898c2ecf20Sopenharmony_ci ret = kstrtoint(buf, 10, &dev_id); 20908c2ecf20Sopenharmony_ci if (ret) 20918c2ecf20Sopenharmony_ci return ret; 20928c2ecf20Sopenharmony_ci if (dev_id < 0) 20938c2ecf20Sopenharmony_ci return -EINVAL; 20948c2ecf20Sopenharmony_ci 20958c2ecf20Sopenharmony_ci mutex_lock(&zram_index_mutex); 20968c2ecf20Sopenharmony_ci 20978c2ecf20Sopenharmony_ci zram = idr_find(&zram_index_idr, dev_id); 20988c2ecf20Sopenharmony_ci if (zram) { 20998c2ecf20Sopenharmony_ci ret = zram_remove(zram); 21008c2ecf20Sopenharmony_ci if (!ret) 21018c2ecf20Sopenharmony_ci idr_remove(&zram_index_idr, dev_id); 21028c2ecf20Sopenharmony_ci } else { 21038c2ecf20Sopenharmony_ci ret = -ENODEV; 21048c2ecf20Sopenharmony_ci } 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_ci mutex_unlock(&zram_index_mutex); 21078c2ecf20Sopenharmony_ci return ret ? ret : count; 21088c2ecf20Sopenharmony_ci} 21098c2ecf20Sopenharmony_cistatic CLASS_ATTR_WO(hot_remove); 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_cistatic struct attribute *zram_control_class_attrs[] = { 21128c2ecf20Sopenharmony_ci &class_attr_hot_add.attr, 21138c2ecf20Sopenharmony_ci &class_attr_hot_remove.attr, 21148c2ecf20Sopenharmony_ci NULL, 21158c2ecf20Sopenharmony_ci}; 21168c2ecf20Sopenharmony_ciATTRIBUTE_GROUPS(zram_control_class); 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_cistatic struct class zram_control_class = { 21198c2ecf20Sopenharmony_ci .name = "zram-control", 21208c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 21218c2ecf20Sopenharmony_ci .class_groups = zram_control_class_groups, 21228c2ecf20Sopenharmony_ci}; 21238c2ecf20Sopenharmony_ci 21248c2ecf20Sopenharmony_cistatic int zram_remove_cb(int id, void *ptr, void *data) 21258c2ecf20Sopenharmony_ci{ 21268c2ecf20Sopenharmony_ci zram_remove(ptr); 21278c2ecf20Sopenharmony_ci return 0; 21288c2ecf20Sopenharmony_ci} 21298c2ecf20Sopenharmony_ci 21308c2ecf20Sopenharmony_cistatic void destroy_devices(void) 21318c2ecf20Sopenharmony_ci{ 21328c2ecf20Sopenharmony_ci class_unregister(&zram_control_class); 21338c2ecf20Sopenharmony_ci idr_for_each(&zram_index_idr, &zram_remove_cb, NULL); 21348c2ecf20Sopenharmony_ci zram_debugfs_destroy(); 21358c2ecf20Sopenharmony_ci idr_destroy(&zram_index_idr); 21368c2ecf20Sopenharmony_ci unregister_blkdev(zram_major, "zram"); 21378c2ecf20Sopenharmony_ci cpuhp_remove_multi_state(CPUHP_ZCOMP_PREPARE); 21388c2ecf20Sopenharmony_ci} 21398c2ecf20Sopenharmony_ci 21408c2ecf20Sopenharmony_cistatic int __init zram_init(void) 21418c2ecf20Sopenharmony_ci{ 21428c2ecf20Sopenharmony_ci int ret; 21438c2ecf20Sopenharmony_ci 21448c2ecf20Sopenharmony_ci ret = cpuhp_setup_state_multi(CPUHP_ZCOMP_PREPARE, "block/zram:prepare", 21458c2ecf20Sopenharmony_ci zcomp_cpu_up_prepare, zcomp_cpu_dead); 21468c2ecf20Sopenharmony_ci if (ret < 0) 21478c2ecf20Sopenharmony_ci return ret; 21488c2ecf20Sopenharmony_ci 21498c2ecf20Sopenharmony_ci ret = class_register(&zram_control_class); 21508c2ecf20Sopenharmony_ci if (ret) { 21518c2ecf20Sopenharmony_ci pr_err("Unable to register zram-control class\n"); 21528c2ecf20Sopenharmony_ci cpuhp_remove_multi_state(CPUHP_ZCOMP_PREPARE); 21538c2ecf20Sopenharmony_ci return ret; 21548c2ecf20Sopenharmony_ci } 21558c2ecf20Sopenharmony_ci 21568c2ecf20Sopenharmony_ci zram_debugfs_create(); 21578c2ecf20Sopenharmony_ci zram_major = register_blkdev(0, "zram"); 21588c2ecf20Sopenharmony_ci if (zram_major <= 0) { 21598c2ecf20Sopenharmony_ci pr_err("Unable to get major number\n"); 21608c2ecf20Sopenharmony_ci class_unregister(&zram_control_class); 21618c2ecf20Sopenharmony_ci cpuhp_remove_multi_state(CPUHP_ZCOMP_PREPARE); 21628c2ecf20Sopenharmony_ci return -EBUSY; 21638c2ecf20Sopenharmony_ci } 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_ci while (num_devices != 0) { 21668c2ecf20Sopenharmony_ci mutex_lock(&zram_index_mutex); 21678c2ecf20Sopenharmony_ci ret = zram_add(); 21688c2ecf20Sopenharmony_ci mutex_unlock(&zram_index_mutex); 21698c2ecf20Sopenharmony_ci if (ret < 0) 21708c2ecf20Sopenharmony_ci goto out_error; 21718c2ecf20Sopenharmony_ci num_devices--; 21728c2ecf20Sopenharmony_ci } 21738c2ecf20Sopenharmony_ci 21748c2ecf20Sopenharmony_ci return 0; 21758c2ecf20Sopenharmony_ci 21768c2ecf20Sopenharmony_ciout_error: 21778c2ecf20Sopenharmony_ci destroy_devices(); 21788c2ecf20Sopenharmony_ci return ret; 21798c2ecf20Sopenharmony_ci} 21808c2ecf20Sopenharmony_ci 21818c2ecf20Sopenharmony_cistatic void __exit zram_exit(void) 21828c2ecf20Sopenharmony_ci{ 21838c2ecf20Sopenharmony_ci destroy_devices(); 21848c2ecf20Sopenharmony_ci} 21858c2ecf20Sopenharmony_ci 21868c2ecf20Sopenharmony_cimodule_init(zram_init); 21878c2ecf20Sopenharmony_cimodule_exit(zram_exit); 21888c2ecf20Sopenharmony_ci 21898c2ecf20Sopenharmony_cimodule_param(num_devices, uint, 0); 21908c2ecf20Sopenharmony_ciMODULE_PARM_DESC(num_devices, "Number of pre-created zram devices"); 21918c2ecf20Sopenharmony_ci 21928c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 21938c2ecf20Sopenharmony_ciMODULE_AUTHOR("Nitin Gupta <ngupta@vflare.org>"); 21948c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Compressed RAM Block Device"); 2195