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