Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f56c0b3e authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "zram: fix race condition while returning zram_entry refcount"

parents f2958cc4 16741735
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -137,3 +137,13 @@ Description:
		The writeback_limit file is read-write and specifies the maximum
		amount of writeback ZRAM can do. The limit could be changed
		in run time.

What:		/sys/block/zram<id>/use_dedup
Date:		March 2017
Contact:	Joonsoo Kim <iamjoonsoo.kim@lge.com>
Description:
		The use_dedup file is read-write and specifies deduplication
		feature is used or not. If enabled, duplicated data is
		managed by reference count and will not be stored in memory
		twice. Benefit of this feature largely depends on the workload
		so keep attention when use.
+1 −1
Original line number Diff line number Diff line
@@ -173,7 +173,7 @@ compact WO trigger memory compaction
debug_stat        	RO	this file is used for zram debugging purposes
backing_dev	  	RW	set up backend storage for zram to write out
idle		  	WO	mark allocated slot as idle

use_dedup		RW	show and set deduplication feature

User space is advised to use the following files to read the device statistics.

+14 −0
Original line number Diff line number Diff line
@@ -15,6 +15,20 @@ config ZRAM

	  See Documentation/blockdev/zram.txt for more information.

config ZRAM_DEDUP
	bool "Deduplication support for ZRAM data"
	depends on ZRAM
	default n
	help
	  Deduplicate ZRAM data to reduce amount of memory consumption.
	  Advantage largely depends on the workload. In some cases, this
          option reduces memory usage to the half. However, if there is no
	  duplicated data, the amount of memory consumption would be
	  increased due to additional metadata usage. And, there is
	  computation time trade-off. Please check the benefit before
	  enabling this option. Experiment shows the positive effect when
	  the zram is used as blockdev and is used to store build output.

config ZRAM_WRITEBACK
       bool "Write back incompressible or idle page to backing device"
       depends on ZRAM
+2 −1
Original line number Diff line number Diff line
zram-y	:=	zcomp.o zram_drv.o zram_dedup.o
zram-y				:=	zcomp.o zram_drv.o
zram-$(CONFIG_ZRAM_DEDUP)	+=	zram_dedup.o

obj-$(CONFIG_ZRAM)	+=	zram.o
+65 −14
Original line number Diff line number Diff line
@@ -41,6 +41,9 @@ void zram_dedup_insert(struct zram *zram, struct zram_entry *new,
	struct rb_node **rb_node, *parent = NULL;
	struct zram_entry *entry;

	if (!zram_dedup_enabled(zram))
		return;

	new->checksum = checksum;
	hash = &zram->hash[checksum % zram->hash_size];
	rb_root = &hash->rb_root;
@@ -89,13 +92,14 @@ static unsigned long zram_dedup_put(struct zram *zram,
{
	struct zram_hash *hash;
	u32 checksum;
	unsigned long val;

	checksum = entry->checksum;
	hash = &zram->hash[checksum % zram->hash_size];

	spin_lock(&hash->lock);

	entry->refcount--;
	val = --entry->refcount;
	if (!entry->refcount)
		rb_erase(&entry->rb_node, &hash->rb_root);
	else
@@ -103,35 +107,70 @@ static unsigned long zram_dedup_put(struct zram *zram,

	spin_unlock(&hash->lock);

	return entry->refcount;
	return val;
}

static struct zram_entry *zram_dedup_get(struct zram *zram,
				unsigned char *mem, u32 checksum)
static struct zram_entry *__zram_dedup_get(struct zram *zram,
				struct zram_hash *hash, unsigned char *mem,
				struct zram_entry *entry)
{
	struct zram_hash *hash;
	struct zram_entry *entry;
	struct zram_entry *tmp, *prev = NULL;
	struct rb_node *rb_node;

	hash = &zram->hash[checksum % zram->hash_size];
	/* find left-most entry with same checksum */
	while ((rb_node = rb_prev(&entry->rb_node))) {
		tmp = rb_entry(rb_node, struct zram_entry, rb_node);
		if (tmp->checksum != entry->checksum)
			break;

	spin_lock(&hash->lock);
	rb_node = hash->rb_root.rb_node;
	while (rb_node) {
		entry = rb_entry(rb_node, struct zram_entry, rb_node);
		if (checksum == entry->checksum) {
		entry = tmp;
	}

again:
	entry->refcount++;
	atomic64_add(entry->len, &zram->stats.dup_data_size);
	spin_unlock(&hash->lock);

	if (prev)
		zram_entry_free(zram, prev);

	if (zram_dedup_match(zram, entry, mem))
		return entry;

	spin_lock(&hash->lock);
	tmp = NULL;
	rb_node = rb_next(&entry->rb_node);
	if (rb_node)
		tmp = rb_entry(rb_node, struct zram_entry, rb_node);

	if (tmp && (tmp->checksum == entry->checksum)) {
		prev = entry;
		entry = tmp;
		goto again;
	}

	spin_unlock(&hash->lock);
	zram_entry_free(zram, entry);

	return NULL;
}

static struct zram_entry *zram_dedup_get(struct zram *zram,
				unsigned char *mem, u32 checksum)
{
	struct zram_hash *hash;
	struct zram_entry *entry;
	struct rb_node *rb_node;

	hash = &zram->hash[checksum % zram->hash_size];

	spin_lock(&hash->lock);
	rb_node = hash->rb_root.rb_node;
	while (rb_node) {
		entry = rb_entry(rb_node, struct zram_entry, rb_node);
		if (checksum == entry->checksum)
			return __zram_dedup_get(zram, hash, mem, entry);

		if (checksum < entry->checksum)
			rb_node = rb_node->rb_left;
		else
@@ -148,6 +187,9 @@ struct zram_entry *zram_dedup_find(struct zram *zram, struct page *page,
	void *mem;
	struct zram_entry *entry;

	if (!zram_dedup_enabled(zram))
		return NULL;

	mem = kmap_atomic(page);
	*checksum = zram_dedup_checksum(mem);

@@ -160,6 +202,9 @@ struct zram_entry *zram_dedup_find(struct zram *zram, struct page *page,
void zram_dedup_init_entry(struct zram *zram, struct zram_entry *entry,
				unsigned long handle, unsigned int len)
{
	if (!zram_dedup_enabled(zram))
		return;

	entry->handle = handle;
	entry->refcount = 1;
	entry->len = len;
@@ -167,6 +212,9 @@ void zram_dedup_init_entry(struct zram *zram, struct zram_entry *entry,

bool zram_dedup_put_entry(struct zram *zram, struct zram_entry *entry)
{
	if (!zram_dedup_enabled(zram))
		return true;

	if (zram_dedup_put(zram, entry))
		return false;

@@ -178,6 +226,9 @@ int zram_dedup_init(struct zram *zram, size_t num_pages)
	int i;
	struct zram_hash *hash;

	if (!zram_dedup_enabled(zram))
		return 0;

	zram->hash_size = num_pages >> ZRAM_HASH_SHIFT;
	zram->hash_size = min_t(size_t, ZRAM_HASH_SIZE_MAX, zram->hash_size);
	zram->hash_size = max_t(size_t, ZRAM_HASH_SIZE_MIN, zram->hash_size);
Loading