Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1572946 > unrolled thread
| Started by | <zhouxianrong@huawei.com> |
|---|---|
| First post | 2017-02-03 09:50 +0100 |
| Last post | 2017-02-07 06:00 +0100 |
| Articles | 11 — 4 participants |
Back to article view | Back to linux.kernel
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
[PATCH] mm: extend zero pages to same element pages for zram <zhouxianrong@huawei.com> - 2017-02-03 09:50 +0100
Re: [PATCH] mm: extend zero pages to same element pages for zram Matthew Wilcox <willy@infradead.org> - 2017-02-03 16:50 +0100
Re: [PATCH] mm: extend zero pages to same element pages for zram zhouxianrong <zhouxianrong@huawei.com> - 2017-02-04 04:40 +0100
Re: [PATCH] mm: extend zero pages to same element pages for zram Minchan Kim <minchan@kernel.org> - 2017-02-05 15:30 +0100
Re: [PATCH] mm: extend zero pages to same element pages for zram zhouxianrong <zhouxianrong@huawei.com> - 2017-02-06 02:40 +0100
Re: [PATCH] mm: extend zero pages to same element pages for zram Matthew Wilcox <willy@infradead.org> - 2017-02-06 15:20 +0100
Re: [PATCH] mm: extend zero pages to same element pages for zram Minchan Kim <minchan@kernel.org> - 2017-02-07 00:50 +0100
Re: [PATCH] mm: extend zero pages to same element pages for zram zhouxianrong <zhouxianrong@huawei.com> - 2017-02-07 03:30 +0100
Re: [PATCH] mm: extend zero pages to same element pages for zram Minchan Kim <minchan@kernel.org> - 2017-02-07 04:00 +0100
Re: [PATCH] mm: extend zero pages to same element pages for zram zhouxianrong <zhouxianrong@huawei.com> - 2017-02-07 04:30 +0100
Re: [PATCH] mm: extend zero pages to same element pages for zram Minchan Kim <minchan@kernel.org> - 2017-02-07 06:00 +0100
| From | <zhouxianrong@huawei.com> |
|---|---|
| Date | 2017-02-03 09:50 +0100 |
| Subject | [PATCH] mm: extend zero pages to same element pages for zram |
| Message-ID | <t6HJ7-7Js-3@gated-at.bofh.it> |
From: zhouxianrong <zhouxianrong@huawei.com>
test result as listed below:
zero pattern_char pattern_short pattern_int pattern_long total (unit)
162989 14454 3534 23516 2769 3294399 (page)
statistics for the result:
zero pattern_char pattern_short pattern_int pattern_long
AVERAGE 0.745696298 0.085937175 0.015957701 0.131874915 0.020533911
STDEV 0.035623777 0.016892402 0.004454534 0.021657123 0.019420072
MAX 0.973813421 0.222222222 0.021409518 0.211812245 0.176512625
MIN 0.645431905 0.004634398 0 0 0
Signed-off-by: zhouxianrong <zhouxianrong@huawei.com>
---
drivers/block/zram/zram_drv.c | 124 +++++++++++++++++++++++++++++++----------
drivers/block/zram/zram_drv.h | 11 ++--
2 files changed, 103 insertions(+), 32 deletions(-)
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index e5ab7d9..6a8c9c5 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -95,6 +95,17 @@ static void zram_clear_flag(struct zram_meta *meta, u32 index,
meta->table[index].value &= ~BIT(flag);
}
+static inline void zram_set_element(struct zram_meta *meta, u32 index,
+ unsigned long element)
+{
+ meta->table[index].element = element;
+}
+
+static inline void zram_clear_element(struct zram_meta *meta, u32 index)
+{
+ meta->table[index].element = 0;
+}
+
static size_t zram_get_obj_size(struct zram_meta *meta, u32 index)
{
return meta->table[index].value & (BIT(ZRAM_FLAG_SHIFT) - 1);
@@ -167,31 +178,78 @@ static inline void update_used_max(struct zram *zram,
} while (old_max != cur_max);
}
-static bool page_zero_filled(void *ptr)
+static inline void zram_fill_page(char *ptr, unsigned long value)
+{
+ int i;
+ unsigned long *page = (unsigned long *)ptr;
+
+ if (likely(value == 0)) {
+ clear_page(ptr);
+ } else {
+ for (i = 0; i < PAGE_SIZE / sizeof(*page); i++)
+ page[i] = value;
+ }
+}
+
+static inline void zram_fill_page_partial(char *ptr, unsigned int size,
+ unsigned long value)
+{
+ int i;
+ unsigned long *page;
+
+ if (likely(value == 0)) {
+ memset(ptr, 0, size);
+ return;
+ }
+
+ i = ((unsigned long)ptr) % sizeof(*page);
+ if (i) {
+ while (i < sizeof(*page)) {
+ *ptr++ = (value >> (i * 8)) & 0xff;
+ --size;
+ ++i;
+ }
+ }
+
+ for (i = size / sizeof(*page); i > 0; --i) {
+ page = (unsigned long *)ptr;
+ *page = value;
+ ptr += sizeof(*page);
+ size -= sizeof(*page);
+ }
+
+ for (i = 0; i < size; ++i)
+ *ptr++ = (value >> (i * 8)) & 0xff;
+}
+
+static bool page_same_filled(void *ptr, unsigned long *element)
{
unsigned int pos;
unsigned long *page;
page = (unsigned long *)ptr;
- for (pos = 0; pos != PAGE_SIZE / sizeof(*page); pos++) {
- if (page[pos])
+ for (pos = 0; pos < PAGE_SIZE / sizeof(*page) - 1; pos++) {
+ if (page[pos] != page[pos + 1])
return false;
}
+ *element = page[pos];
+
return true;
}
-static void handle_zero_page(struct bio_vec *bvec)
+static void handle_same_page(struct bio_vec *bvec, unsigned long element)
{
struct page *page = bvec->bv_page;
void *user_mem;
user_mem = kmap_atomic(page);
if (is_partial_io(bvec))
- memset(user_mem + bvec->bv_offset, 0, bvec->bv_len);
+ zram_fill_page_partial(user_mem + bvec->bv_offset, bvec->bv_len,
+ element);
else
- clear_page(user_mem);
+ zram_fill_page(user_mem, element);
kunmap_atomic(user_mem);
flush_dcache_page(page);
@@ -440,7 +498,7 @@ static ssize_t mm_stat_show(struct device *dev,
mem_used << PAGE_SHIFT,
zram->limit_pages << PAGE_SHIFT,
max_used << PAGE_SHIFT,
- (u64)atomic64_read(&zram->stats.zero_pages),
+ (u64)atomic64_read(&zram->stats.same_pages),
pool_stats.pages_compacted);
up_read(&zram->init_lock);
@@ -473,7 +531,7 @@ static ssize_t debug_stat_show(struct device *dev,
ZRAM_ATTR_RO(failed_writes);
ZRAM_ATTR_RO(invalid_io);
ZRAM_ATTR_RO(notify_free);
-ZRAM_ATTR_RO(zero_pages);
+ZRAM_ATTR_RO(same_pages);
ZRAM_ATTR_RO(compr_data_size);
static inline bool zram_meta_get(struct zram *zram)
@@ -495,11 +553,17 @@ static void zram_meta_free(struct zram_meta *meta, u64 disksize)
/* Free all pages that are still in this zram device */
for (index = 0; index < num_pages; index++) {
- unsigned long handle = meta->table[index].handle;
+ unsigned long handle;
+
+ bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value);
+ handle = meta->table[index].handle;
- if (!handle)
+ if (!handle || zram_test_flag(meta, index, ZRAM_SAME)) {
+ bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
continue;
+ }
+ bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
zs_free(meta->mem_pool, handle);
}
@@ -511,7 +575,7 @@ static void zram_meta_free(struct zram_meta *meta, u64 disksize)
static struct zram_meta *zram_meta_alloc(char *pool_name, u64 disksize)
{
size_t num_pages;
- struct zram_meta *meta = kmalloc(sizeof(*meta), GFP_KERNEL);
+ struct zram_meta *meta = kzalloc(sizeof(*meta), GFP_KERNEL);
if (!meta)
return NULL;
@@ -547,18 +611,20 @@ static void zram_free_page(struct zram *zram, size_t index)
struct zram_meta *meta = zram->meta;
unsigned long handle = meta->table[index].handle;
- if (unlikely(!handle)) {
- /*
- * No memory is allocated for zero filled pages.
- * Simply clear zero page flag.
- */
- if (zram_test_flag(meta, index, ZRAM_ZERO)) {
- zram_clear_flag(meta, index, ZRAM_ZERO);
- atomic64_dec(&zram->stats.zero_pages);
- }
+ /*
+ * No memory is allocated for same element filled pages.
+ * Simply clear same page flag.
+ */
+ if (zram_test_flag(meta, index, ZRAM_SAME)) {
+ zram_clear_flag(meta, index, ZRAM_SAME);
+ zram_clear_element(meta, index);
+ atomic64_dec(&zram->stats.same_pages);
return;
}
+ if (unlikely(!handle))
+ return;
+
zs_free(meta->mem_pool, handle);
atomic64_sub(zram_get_obj_size(meta, index),
@@ -581,9 +647,9 @@ static int zram_decompress_page(struct zram *zram, char *mem, u32 index)
handle = meta->table[index].handle;
size = zram_get_obj_size(meta, index);
- if (!handle || zram_test_flag(meta, index, ZRAM_ZERO)) {
+ if (!handle || zram_test_flag(meta, index, ZRAM_SAME)) {
bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
- clear_page(mem);
+ zram_fill_page(mem, meta->table[index].element);
return 0;
}
@@ -619,9 +685,9 @@ static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec,
bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value);
if (unlikely(!meta->table[index].handle) ||
- zram_test_flag(meta, index, ZRAM_ZERO)) {
+ zram_test_flag(meta, index, ZRAM_SAME)) {
bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
- handle_zero_page(bvec);
+ handle_same_page(bvec, meta->table[index].element);
return 0;
}
bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
@@ -669,6 +735,7 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
struct zram_meta *meta = zram->meta;
struct zcomp_strm *zstrm = NULL;
unsigned long alloced_pages;
+ unsigned long element;
page = bvec->bv_page;
if (is_partial_io(bvec)) {
@@ -697,16 +764,17 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
uncmem = user_mem;
}
- if (page_zero_filled(uncmem)) {
+ if (page_same_filled(uncmem, &element)) {
if (user_mem)
kunmap_atomic(user_mem);
/* Free memory associated with this sector now. */
bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value);
zram_free_page(zram, index);
- zram_set_flag(meta, index, ZRAM_ZERO);
+ zram_set_flag(meta, index, ZRAM_SAME);
+ zram_set_element(meta, index, element);
bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
- atomic64_inc(&zram->stats.zero_pages);
+ atomic64_inc(&zram->stats.same_pages);
ret = 0;
goto out;
}
@@ -1206,7 +1274,7 @@ static int zram_open(struct block_device *bdev, fmode_t mode)
&dev_attr_compact.attr,
&dev_attr_invalid_io.attr,
&dev_attr_notify_free.attr,
- &dev_attr_zero_pages.attr,
+ &dev_attr_same_pages.attr,
&dev_attr_orig_data_size.attr,
&dev_attr_compr_data_size.attr,
&dev_attr_mem_used_total.attr,
diff --git a/drivers/block/zram/zram_drv.h b/drivers/block/zram/zram_drv.h
index 74fcf10..4bb92e1 100644
--- a/drivers/block/zram/zram_drv.h
+++ b/drivers/block/zram/zram_drv.h
@@ -60,8 +60,8 @@
/* Flags for zram pages (table[page_no].value) */
enum zram_pageflags {
- /* Page consists entirely of zeros */
- ZRAM_ZERO = ZRAM_FLAG_SHIFT,
+ /* Page consists entirely of same elements */
+ ZRAM_SAME = ZRAM_FLAG_SHIFT,
ZRAM_ACCESS, /* page is now accessed */
__NR_ZRAM_PAGEFLAGS,
@@ -71,7 +71,10 @@ enum zram_pageflags {
/* Allocated for each disk page */
struct zram_table_entry {
- unsigned long handle;
+ union {
+ unsigned long handle;
+ unsigned long element;
+ };
unsigned long value;
};
@@ -83,7 +86,7 @@ struct zram_stats {
atomic64_t failed_writes; /* can happen when memory is too low */
atomic64_t invalid_io; /* non-page-aligned I/O requests */
atomic64_t notify_free; /* no. of swap slot free notifications */
- atomic64_t zero_pages; /* no. of zero filled pages */
+ atomic64_t same_pages; /* no. of same element filled pages */
atomic64_t pages_stored; /* no. of pages currently stored */
atomic_long_t max_used_pages; /* no. of maximum pages stored */
atomic64_t writestall; /* no. of write slow paths */
--
1.7.9.5
[toc] | [next] | [standalone]
| From | Matthew Wilcox <willy@infradead.org> |
|---|---|
| Date | 2017-02-03 16:50 +0100 |
| Message-ID | <t6Ohz-3Ax-7@gated-at.bofh.it> |
| In reply to | #1572946 |
On Fri, Feb 03, 2017 at 04:42:27PM +0800, zhouxianrong@huawei.com wrote:
> +static inline void zram_fill_page_partial(char *ptr, unsigned int size,
> + unsigned long value)
> +{
> + int i;
> + unsigned long *page;
> +
> + if (likely(value == 0)) {
> + memset(ptr, 0, size);
> + return;
> + }
> +
> + i = ((unsigned long)ptr) % sizeof(*page);
> + if (i) {
> + while (i < sizeof(*page)) {
> + *ptr++ = (value >> (i * 8)) & 0xff;
> + --size;
> + ++i;
> + }
> + }
> +
> + for (i = size / sizeof(*page); i > 0; --i) {
> + page = (unsigned long *)ptr;
> + *page = value;
> + ptr += sizeof(*page);
> + size -= sizeof(*page);
> + }
> +
> + for (i = 0; i < size; ++i)
> + *ptr++ = (value >> (i * 8)) & 0xff;
> +}
You're assuming little-endian here. I think you need to do a
cpu_to_le() here, but I don't think we have a cpu_to_leul, only
cpu_to_le64/cpu_to_le32. So you may have some work to do ...
[toc] | [prev] | [next] | [standalone]
| From | zhouxianrong <zhouxianrong@huawei.com> |
|---|---|
| Date | 2017-02-04 04:40 +0100 |
| Message-ID | <t6ZmG-32o-15@gated-at.bofh.it> |
| In reply to | #1573184 |
right, thanks.
On 2017/2/3 23:33, Matthew Wilcox wrote:
> On Fri, Feb 03, 2017 at 04:42:27PM +0800, zhouxianrong@huawei.com wrote:
>> +static inline void zram_fill_page_partial(char *ptr, unsigned int size,
>> + unsigned long value)
>> +{
>> + int i;
>> + unsigned long *page;
>> +
>> + if (likely(value == 0)) {
>> + memset(ptr, 0, size);
>> + return;
>> + }
>> +
>> + i = ((unsigned long)ptr) % sizeof(*page);
>> + if (i) {
>> + while (i < sizeof(*page)) {
>> + *ptr++ = (value >> (i * 8)) & 0xff;
>> + --size;
>> + ++i;
>> + }
>> + }
>> +
>> + for (i = size / sizeof(*page); i > 0; --i) {
>> + page = (unsigned long *)ptr;
>> + *page = value;
>> + ptr += sizeof(*page);
>> + size -= sizeof(*page);
>> + }
>> +
>> + for (i = 0; i < size; ++i)
>> + *ptr++ = (value >> (i * 8)) & 0xff;
>> +}
>
> You're assuming little-endian here. I think you need to do a
> cpu_to_le() here, but I don't think we have a cpu_to_leul, only
> cpu_to_le64/cpu_to_le32. So you may have some work to do ...
>
>
> .
>
[toc] | [prev] | [next] | [standalone]
| From | Minchan Kim <minchan@kernel.org> |
|---|---|
| Date | 2017-02-05 15:30 +0100 |
| Message-ID | <t7vZf-8vP-5@gated-at.bofh.it> |
| In reply to | #1572946 |
Hi zhouxianrong,
On Fri, Feb 03, 2017 at 04:42:27PM +0800, zhouxianrong@huawei.com wrote:
> From: zhouxianrong <zhouxianrong@huawei.com>
>
> test result as listed below:
>
> zero pattern_char pattern_short pattern_int pattern_long total (unit)
> 162989 14454 3534 23516 2769 3294399 (page)
>
> statistics for the result:
>
> zero pattern_char pattern_short pattern_int pattern_long
> AVERAGE 0.745696298 0.085937175 0.015957701 0.131874915 0.020533911
> STDEV 0.035623777 0.016892402 0.004454534 0.021657123 0.019420072
> MAX 0.973813421 0.222222222 0.021409518 0.211812245 0.176512625
> MIN 0.645431905 0.004634398 0 0 0
The description in old version was better for justifying same page merging
feature.
>
> Signed-off-by: zhouxianrong <zhouxianrong@huawei.com>
> ---
> drivers/block/zram/zram_drv.c | 124 +++++++++++++++++++++++++++++++----------
> drivers/block/zram/zram_drv.h | 11 ++--
> 2 files changed, 103 insertions(+), 32 deletions(-)
>
> diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
> index e5ab7d9..6a8c9c5 100644
> --- a/drivers/block/zram/zram_drv.c
> +++ b/drivers/block/zram/zram_drv.c
> @@ -95,6 +95,17 @@ static void zram_clear_flag(struct zram_meta *meta, u32 index,
> meta->table[index].value &= ~BIT(flag);
> }
>
> +static inline void zram_set_element(struct zram_meta *meta, u32 index,
> + unsigned long element)
> +{
> + meta->table[index].element = element;
> +}
> +
> +static inline void zram_clear_element(struct zram_meta *meta, u32 index)
> +{
> + meta->table[index].element = 0;
> +}
> +
> static size_t zram_get_obj_size(struct zram_meta *meta, u32 index)
> {
> return meta->table[index].value & (BIT(ZRAM_FLAG_SHIFT) - 1);
> @@ -167,31 +178,78 @@ static inline void update_used_max(struct zram *zram,
> } while (old_max != cur_max);
> }
>
> -static bool page_zero_filled(void *ptr)
> +static inline void zram_fill_page(char *ptr, unsigned long value)
> +{
> + int i;
> + unsigned long *page = (unsigned long *)ptr;
> +
> + if (likely(value == 0)) {
> + clear_page(ptr);
> + } else {
> + for (i = 0; i < PAGE_SIZE / sizeof(*page); i++)
> + page[i] = value;
> + }
> +}
> +
> +static inline void zram_fill_page_partial(char *ptr, unsigned int size,
> + unsigned long value)
> +{
> + int i;
> + unsigned long *page;
> +
> + if (likely(value == 0)) {
> + memset(ptr, 0, size);
> + return;
> + }
> +
> + i = ((unsigned long)ptr) % sizeof(*page);
> + if (i) {
> + while (i < sizeof(*page)) {
> + *ptr++ = (value >> (i * 8)) & 0xff;
> + --size;
> + ++i;
> + }
> + }
> +
I don't think we need this part because block layer works with sector
size or multiple times of it so it must be aligned unsigned long.
[toc] | [prev] | [next] | [standalone]
| From | zhouxianrong <zhouxianrong@huawei.com> |
|---|---|
| Date | 2017-02-06 02:40 +0100 |
| Message-ID | <t7GrD-6Dt-1@gated-at.bofh.it> |
| In reply to | #1573881 |
On 2017/2/5 22:21, Minchan Kim wrote:
> Hi zhouxianrong,
>
> On Fri, Feb 03, 2017 at 04:42:27PM +0800, zhouxianrong@huawei.com wrote:
>> From: zhouxianrong <zhouxianrong@huawei.com>
>>
>> test result as listed below:
>>
>> zero pattern_char pattern_short pattern_int pattern_long total (unit)
>> 162989 14454 3534 23516 2769 3294399 (page)
>>
>> statistics for the result:
>>
>> zero pattern_char pattern_short pattern_int pattern_long
>> AVERAGE 0.745696298 0.085937175 0.015957701 0.131874915 0.020533911
>> STDEV 0.035623777 0.016892402 0.004454534 0.021657123 0.019420072
>> MAX 0.973813421 0.222222222 0.021409518 0.211812245 0.176512625
>> MIN 0.645431905 0.004634398 0 0 0
>
> The description in old version was better for justifying same page merging
> feature.
>
>>
>> Signed-off-by: zhouxianrong <zhouxianrong@huawei.com>
>> ---
>> drivers/block/zram/zram_drv.c | 124 +++++++++++++++++++++++++++++++----------
>> drivers/block/zram/zram_drv.h | 11 ++--
>> 2 files changed, 103 insertions(+), 32 deletions(-)
>>
>> diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
>> index e5ab7d9..6a8c9c5 100644
>> --- a/drivers/block/zram/zram_drv.c
>> +++ b/drivers/block/zram/zram_drv.c
>> @@ -95,6 +95,17 @@ static void zram_clear_flag(struct zram_meta *meta, u32 index,
>> meta->table[index].value &= ~BIT(flag);
>> }
>>
>> +static inline void zram_set_element(struct zram_meta *meta, u32 index,
>> + unsigned long element)
>> +{
>> + meta->table[index].element = element;
>> +}
>> +
>> +static inline void zram_clear_element(struct zram_meta *meta, u32 index)
>> +{
>> + meta->table[index].element = 0;
>> +}
>> +
>> static size_t zram_get_obj_size(struct zram_meta *meta, u32 index)
>> {
>> return meta->table[index].value & (BIT(ZRAM_FLAG_SHIFT) - 1);
>> @@ -167,31 +178,78 @@ static inline void update_used_max(struct zram *zram,
>> } while (old_max != cur_max);
>> }
>>
>> -static bool page_zero_filled(void *ptr)
>> +static inline void zram_fill_page(char *ptr, unsigned long value)
>> +{
>> + int i;
>> + unsigned long *page = (unsigned long *)ptr;
>> +
>> + if (likely(value == 0)) {
>> + clear_page(ptr);
>> + } else {
>> + for (i = 0; i < PAGE_SIZE / sizeof(*page); i++)
>> + page[i] = value;
>> + }
>> +}
>> +
>> +static inline void zram_fill_page_partial(char *ptr, unsigned int size,
>> + unsigned long value)
>> +{
>> + int i;
>> + unsigned long *page;
>> +
>> + if (likely(value == 0)) {
>> + memset(ptr, 0, size);
>> + return;
>> + }
>> +
>> + i = ((unsigned long)ptr) % sizeof(*page);
>> + if (i) {
>> + while (i < sizeof(*page)) {
>> + *ptr++ = (value >> (i * 8)) & 0xff;
>> + --size;
>> + ++i;
>> + }
>> + }
>> +
>
> I don't think we need this part because block layer works with sector
> size or multiple times of it so it must be aligned unsigned long.
>
>
>
>
> .
>
Minchan and Matthew Wilcox:
1. right, but users could open /dev/block/zram0 file and do any read operations.
2. about endian operation for long, the modification is trivial and low efficient.
i have not better method. do you have any good idea for this?
3. the below should be modified.
static inline bool zram_meta_get(struct zram *zram)
@@ -495,11 +553,17 @@ static void zram_meta_free(struct zram_meta *meta, u64 disksize)
/* Free all pages that are still in this zram device */
for (index = 0; index < num_pages; index++) {
- unsigned long handle = meta->table[index].handle;
+ unsigned long handle;
+
+ bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value);
+ handle = meta->table[index].handle;
- if (!handle)
+ if (!handle || zram_test_flag(meta, index, ZRAM_SAME)) {
+ bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
continue;
+ }
+ bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
zs_free(meta->mem_pool, handle);
}
@@ -511,7 +575,7 @@ static void zram_meta_free(struct zram_meta *meta, u64 disksize)
static struct zram_meta *zram_meta_alloc(char *pool_name, u64 disksize)
{
size_t num_pages;
- struct zram_meta *meta = kmalloc(sizeof(*meta), GFP_KERNEL);
+ struct zram_meta *meta = kzalloc(sizeof(*meta), GFP_KERNEL);
[toc] | [prev] | [next] | [standalone]
| From | Matthew Wilcox <willy@infradead.org> |
|---|---|
| Date | 2017-02-06 15:20 +0100 |
| Message-ID | <t7Sj8-61m-23@gated-at.bofh.it> |
| In reply to | #1574318 |
On Mon, Feb 06, 2017 at 09:28:18AM +0800, zhouxianrong wrote:
> > > +static inline void zram_fill_page_partial(char *ptr, unsigned int size,
> > > + unsigned long value)
> > > +{
> > > + int i;
> > > + unsigned long *page;
> > > +
> > > + if (likely(value == 0)) {
> > > + memset(ptr, 0, size);
> > > + return;
> > > + }
> > > +
> > > + i = ((unsigned long)ptr) % sizeof(*page);
> > > + if (i) {
> > > + while (i < sizeof(*page)) {
> > > + *ptr++ = (value >> (i * 8)) & 0xff;
> > > + --size;
> > > + ++i;
> > > + }
> > > + }
> > > +
> >
> > I don't think we need this part because block layer works with sector
> > size or multiple times of it so it must be aligned unsigned long.
>
> Minchan and Matthew Wilcox:
>
> 1. right, but users could open /dev/block/zram0 file and do any read operations.
But any such read operation would go through the page cache, so will
be page aligned. Unless they do an O_DIRECT operation, in which case
it must be aligned to block size. Please, try it. I/Os which are not
aligned should be failed long before they reach your driver.
[toc] | [prev] | [next] | [standalone]
| From | Minchan Kim <minchan@kernel.org> |
|---|---|
| Date | 2017-02-07 00:50 +0100 |
| Message-ID | <t81cJ-3ij-7@gated-at.bofh.it> |
| In reply to | #1574318 |
Hi
On Mon, Feb 06, 2017 at 09:28:18AM +0800, zhouxianrong wrote:
>
>
> On 2017/2/5 22:21, Minchan Kim wrote:
> >Hi zhouxianrong,
> >
> >On Fri, Feb 03, 2017 at 04:42:27PM +0800, zhouxianrong@huawei.com wrote:
> >>From: zhouxianrong <zhouxianrong@huawei.com>
> >>
> >>test result as listed below:
> >>
> >>zero pattern_char pattern_short pattern_int pattern_long total (unit)
> >>162989 14454 3534 23516 2769 3294399 (page)
> >>
> >>statistics for the result:
> >>
> >> zero pattern_char pattern_short pattern_int pattern_long
> >>AVERAGE 0.745696298 0.085937175 0.015957701 0.131874915 0.020533911
> >>STDEV 0.035623777 0.016892402 0.004454534 0.021657123 0.019420072
> >>MAX 0.973813421 0.222222222 0.021409518 0.211812245 0.176512625
> >>MIN 0.645431905 0.004634398 0 0 0
> >
> >The description in old version was better for justifying same page merging
> >feature.
> >
> >>
> >>Signed-off-by: zhouxianrong <zhouxianrong@huawei.com>
> >>---
> >> drivers/block/zram/zram_drv.c | 124 +++++++++++++++++++++++++++++++----------
> >> drivers/block/zram/zram_drv.h | 11 ++--
> >> 2 files changed, 103 insertions(+), 32 deletions(-)
> >>
> >>diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
> >>index e5ab7d9..6a8c9c5 100644
> >>--- a/drivers/block/zram/zram_drv.c
> >>+++ b/drivers/block/zram/zram_drv.c
> >>@@ -95,6 +95,17 @@ static void zram_clear_flag(struct zram_meta *meta, u32 index,
> >> meta->table[index].value &= ~BIT(flag);
> >> }
> >>
> >>+static inline void zram_set_element(struct zram_meta *meta, u32 index,
> >>+ unsigned long element)
> >>+{
> >>+ meta->table[index].element = element;
> >>+}
> >>+
> >>+static inline void zram_clear_element(struct zram_meta *meta, u32 index)
> >>+{
> >>+ meta->table[index].element = 0;
> >>+}
> >>+
> >> static size_t zram_get_obj_size(struct zram_meta *meta, u32 index)
> >> {
> >> return meta->table[index].value & (BIT(ZRAM_FLAG_SHIFT) - 1);
> >>@@ -167,31 +178,78 @@ static inline void update_used_max(struct zram *zram,
> >> } while (old_max != cur_max);
> >> }
> >>
> >>-static bool page_zero_filled(void *ptr)
> >>+static inline void zram_fill_page(char *ptr, unsigned long value)
> >>+{
> >>+ int i;
> >>+ unsigned long *page = (unsigned long *)ptr;
> >>+
> >>+ if (likely(value == 0)) {
> >>+ clear_page(ptr);
> >>+ } else {
> >>+ for (i = 0; i < PAGE_SIZE / sizeof(*page); i++)
> >>+ page[i] = value;
> >>+ }
> >>+}
> >>+
> >>+static inline void zram_fill_page_partial(char *ptr, unsigned int size,
> >>+ unsigned long value)
> >>+{
> >>+ int i;
> >>+ unsigned long *page;
> >>+
> >>+ if (likely(value == 0)) {
> >>+ memset(ptr, 0, size);
> >>+ return;
> >>+ }
> >>+
> >>+ i = ((unsigned long)ptr) % sizeof(*page);
> >>+ if (i) {
> >>+ while (i < sizeof(*page)) {
> >>+ *ptr++ = (value >> (i * 8)) & 0xff;
> >>+ --size;
> >>+ ++i;
> >>+ }
> >>+ }
> >>+
> >
> >I don't think we need this part because block layer works with sector
> >size or multiple times of it so it must be aligned unsigned long.
> >
> >
> >
> >
> >.
> >
>
> Minchan and Matthew Wilcox:
>
> 1. right, but users could open /dev/block/zram0 file and do any read operations.
Could you make that happen?
I don't think it's possible as Matthew already pointed out, too.
>
> 2. about endian operation for long, the modification is trivial and low efficient.
> i have not better method. do you have any good idea for this?
So if assumption 1 is wrong, we don't need 2, either.
>
> 3. the below should be modified.
>
> static inline bool zram_meta_get(struct zram *zram)
> @@ -495,11 +553,17 @@ static void zram_meta_free(struct zram_meta *meta, u64 disksize)
>
> /* Free all pages that are still in this zram device */
> for (index = 0; index < num_pages; index++) {
> - unsigned long handle = meta->table[index].handle;
> + unsigned long handle;
> +
> + bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value);
> + handle = meta->table[index].handle;
>
> - if (!handle)
> + if (!handle || zram_test_flag(meta, index, ZRAM_SAME)) {
> + bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
> continue;
> + }
>
> + bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
> zs_free(meta->mem_pool, handle);
Could you explain why we need this modification?
> }
>
> @@ -511,7 +575,7 @@ static void zram_meta_free(struct zram_meta *meta, u64 disksize)
> static struct zram_meta *zram_meta_alloc(char *pool_name, u64 disksize)
> {
> size_t num_pages;
> - struct zram_meta *meta = kmalloc(sizeof(*meta), GFP_KERNEL);
> + struct zram_meta *meta = kzalloc(sizeof(*meta), GFP_KERNEL);
Ditto
>
>
[toc] | [prev] | [next] | [standalone]
| From | zhouxianrong <zhouxianrong@huawei.com> |
|---|---|
| Date | 2017-02-07 03:30 +0100 |
| Message-ID | <t83HA-4X1-9@gated-at.bofh.it> |
| In reply to | #1575253 |
On 2017/2/7 7:48, Minchan Kim wrote:
> Hi
>
> On Mon, Feb 06, 2017 at 09:28:18AM +0800, zhouxianrong wrote:
>>
>>
>> On 2017/2/5 22:21, Minchan Kim wrote:
>>> Hi zhouxianrong,
>>>
>>> On Fri, Feb 03, 2017 at 04:42:27PM +0800, zhouxianrong@huawei.com wrote:
>>>> From: zhouxianrong <zhouxianrong@huawei.com>
>>>>
>>>> test result as listed below:
>>>>
>>>> zero pattern_char pattern_short pattern_int pattern_long total (unit)
>>>> 162989 14454 3534 23516 2769 3294399 (page)
>>>>
>>>> statistics for the result:
>>>>
>>>> zero pattern_char pattern_short pattern_int pattern_long
>>>> AVERAGE 0.745696298 0.085937175 0.015957701 0.131874915 0.020533911
>>>> STDEV 0.035623777 0.016892402 0.004454534 0.021657123 0.019420072
>>>> MAX 0.973813421 0.222222222 0.021409518 0.211812245 0.176512625
>>>> MIN 0.645431905 0.004634398 0 0 0
>>>
>>> The description in old version was better for justifying same page merging
>>> feature.
>>>
>>>>
>>>> Signed-off-by: zhouxianrong <zhouxianrong@huawei.com>
>>>> ---
>>>> drivers/block/zram/zram_drv.c | 124 +++++++++++++++++++++++++++++++----------
>>>> drivers/block/zram/zram_drv.h | 11 ++--
>>>> 2 files changed, 103 insertions(+), 32 deletions(-)
>>>>
>>>> diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
>>>> index e5ab7d9..6a8c9c5 100644
>>>> --- a/drivers/block/zram/zram_drv.c
>>>> +++ b/drivers/block/zram/zram_drv.c
>>>> @@ -95,6 +95,17 @@ static void zram_clear_flag(struct zram_meta *meta, u32 index,
>>>> meta->table[index].value &= ~BIT(flag);
>>>> }
>>>>
>>>> +static inline void zram_set_element(struct zram_meta *meta, u32 index,
>>>> + unsigned long element)
>>>> +{
>>>> + meta->table[index].element = element;
>>>> +}
>>>> +
>>>> +static inline void zram_clear_element(struct zram_meta *meta, u32 index)
>>>> +{
>>>> + meta->table[index].element = 0;
>>>> +}
>>>> +
>>>> static size_t zram_get_obj_size(struct zram_meta *meta, u32 index)
>>>> {
>>>> return meta->table[index].value & (BIT(ZRAM_FLAG_SHIFT) - 1);
>>>> @@ -167,31 +178,78 @@ static inline void update_used_max(struct zram *zram,
>>>> } while (old_max != cur_max);
>>>> }
>>>>
>>>> -static bool page_zero_filled(void *ptr)
>>>> +static inline void zram_fill_page(char *ptr, unsigned long value)
>>>> +{
>>>> + int i;
>>>> + unsigned long *page = (unsigned long *)ptr;
>>>> +
>>>> + if (likely(value == 0)) {
>>>> + clear_page(ptr);
>>>> + } else {
>>>> + for (i = 0; i < PAGE_SIZE / sizeof(*page); i++)
>>>> + page[i] = value;
>>>> + }
>>>> +}
>>>> +
>>>> +static inline void zram_fill_page_partial(char *ptr, unsigned int size,
>>>> + unsigned long value)
>>>> +{
>>>> + int i;
>>>> + unsigned long *page;
>>>> +
>>>> + if (likely(value == 0)) {
>>>> + memset(ptr, 0, size);
>>>> + return;
>>>> + }
>>>> +
>>>> + i = ((unsigned long)ptr) % sizeof(*page);
>>>> + if (i) {
>>>> + while (i < sizeof(*page)) {
>>>> + *ptr++ = (value >> (i * 8)) & 0xff;
>>>> + --size;
>>>> + ++i;
>>>> + }
>>>> + }
>>>> +
>>>
>>> I don't think we need this part because block layer works with sector
>>> size or multiple times of it so it must be aligned unsigned long.
>>>
>>>
>>>
>>>
>>> .
>>>
>>
>> Minchan and Matthew Wilcox:
>>
>> 1. right, but users could open /dev/block/zram0 file and do any read operations.
>
> Could you make that happen?
> I don't think it's possible as Matthew already pointed out, too.
yes, Matthew is right, thanks
>
>>
>> 2. about endian operation for long, the modification is trivial and low efficient.
>> i have not better method. do you have any good idea for this?
>
> So if assumption 1 is wrong, we don't need 2, either.
yes
>
>>
>> 3. the below should be modified.
>>
>> static inline bool zram_meta_get(struct zram *zram)
>> @@ -495,11 +553,17 @@ static void zram_meta_free(struct zram_meta *meta, u64 disksize)
>>
>> /* Free all pages that are still in this zram device */
>> for (index = 0; index < num_pages; index++) {
>> - unsigned long handle = meta->table[index].handle;
>> + unsigned long handle;
>> +
>> + bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value);
>> + handle = meta->table[index].handle;
>>
>> - if (!handle)
>> + if (!handle || zram_test_flag(meta, index, ZRAM_SAME)) {
>> + bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
>> continue;
>> + }
>>
>> + bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
>> zs_free(meta->mem_pool, handle);
>
> Could you explain why we need this modification?
>
>> }
>>
>> @@ -511,7 +575,7 @@ static void zram_meta_free(struct zram_meta *meta, u64 disksize)
>> static struct zram_meta *zram_meta_alloc(char *pool_name, u64 disksize)
>> {
>> size_t num_pages;
>> - struct zram_meta *meta = kmalloc(sizeof(*meta), GFP_KERNEL);
>> + struct zram_meta *meta = kzalloc(sizeof(*meta), GFP_KERNEL);
>
> Ditto
>
>>
>>
>
> .
>
because of union of handle and element, i think a non-zero element (other than handle) is prevented from freeing.
if zram_meta_get was modified, zram_meta_alloc did so.
[toc] | [prev] | [next] | [standalone]
| From | Minchan Kim <minchan@kernel.org> |
|---|---|
| Date | 2017-02-07 04:00 +0100 |
| Message-ID | <t84aC-58r-15@gated-at.bofh.it> |
| In reply to | #1575326 |
On Tue, Feb 07, 2017 at 10:20:57AM +0800, zhouxianrong wrote:
< snip >
> >>3. the below should be modified.
> >>
> >>static inline bool zram_meta_get(struct zram *zram)
> >>@@ -495,11 +553,17 @@ static void zram_meta_free(struct zram_meta *meta, u64 disksize)
> >>
> >> /* Free all pages that are still in this zram device */
> >> for (index = 0; index < num_pages; index++) {
> >>- unsigned long handle = meta->table[index].handle;
> >>+ unsigned long handle;
> >>+
> >>+ bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value);
> >>+ handle = meta->table[index].handle;
> >>
> >>- if (!handle)
> >>+ if (!handle || zram_test_flag(meta, index, ZRAM_SAME)) {
> >>+ bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
> >> continue;
> >>+ }
> >>
> >>+ bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
> >> zs_free(meta->mem_pool, handle);
> >
> >Could you explain why we need this modification?
> >
> >> }
> >>
> >>@@ -511,7 +575,7 @@ static void zram_meta_free(struct zram_meta *meta, u64 disksize)
> >> static struct zram_meta *zram_meta_alloc(char *pool_name, u64 disksize)
> >> {
> >> size_t num_pages;
> >>- struct zram_meta *meta = kmalloc(sizeof(*meta), GFP_KERNEL);
> >>+ struct zram_meta *meta = kzalloc(sizeof(*meta), GFP_KERNEL);
> >
> >Ditto
> >
> >>
> >>
> >
> >.
> >
>
> because of union of handle and element, i think a non-zero element (other than handle) is prevented from freeing.
> if zram_meta_get was modified, zram_meta_alloc did so.
Right. Thanks but I don't see why we need the locking in there and modification of
zram_meta_alloc.
Isn't it enough with this?
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index c20b05a84f21..a25d34a8af19 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -425,8 +425,11 @@ static void zram_meta_free(struct zram_meta *meta, u64 disksize)
/* Free all pages that are still in this zram device */
for (index = 0; index < num_pages; index++) {
unsigned long handle = meta->table[index].handle;
-
- if (!handle)
+ /*
+ * No memory is allocated for same element filled pages.
+ * Simply clear same page flag.
+ */
+ if (!handle || zram_test_flag(meta, index, ZRAM_SAME))
continue;
zs_free(meta->mem_pool, handle);
[toc] | [prev] | [next] | [standalone]
| From | zhouxianrong <zhouxianrong@huawei.com> |
|---|---|
| Date | 2017-02-07 04:30 +0100 |
| Message-ID | <t84DE-5EP-3@gated-at.bofh.it> |
| In reply to | #1575342 |
On 2017/2/7 10:54, Minchan Kim wrote:
> On Tue, Feb 07, 2017 at 10:20:57AM +0800, zhouxianrong wrote:
>
> < snip >
>
>>>> 3. the below should be modified.
>>>>
>>>> static inline bool zram_meta_get(struct zram *zram)
>>>> @@ -495,11 +553,17 @@ static void zram_meta_free(struct zram_meta *meta, u64 disksize)
>>>>
>>>> /* Free all pages that are still in this zram device */
>>>> for (index = 0; index < num_pages; index++) {
>>>> - unsigned long handle = meta->table[index].handle;
>>>> + unsigned long handle;
>>>> +
>>>> + bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value);
>>>> + handle = meta->table[index].handle;
>>>>
>>>> - if (!handle)
>>>> + if (!handle || zram_test_flag(meta, index, ZRAM_SAME)) {
>>>> + bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
>>>> continue;
>>>> + }
>>>>
>>>> + bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
>>>> zs_free(meta->mem_pool, handle);
>>>
>>> Could you explain why we need this modification?
>>>
>>>> }
>>>>
>>>> @@ -511,7 +575,7 @@ static void zram_meta_free(struct zram_meta *meta, u64 disksize)
>>>> static struct zram_meta *zram_meta_alloc(char *pool_name, u64 disksize)
>>>> {
>>>> size_t num_pages;
>>>> - struct zram_meta *meta = kmalloc(sizeof(*meta), GFP_KERNEL);
>>>> + struct zram_meta *meta = kzalloc(sizeof(*meta), GFP_KERNEL);
>>>
>>> Ditto
>>>
>>>>
>>>>
>>>
>>> .
>>>
>>
>> because of union of handle and element, i think a non-zero element (other than handle) is prevented from freeing.
>> if zram_meta_get was modified, zram_meta_alloc did so.
>
> Right. Thanks but I don't see why we need the locking in there and modification of
> zram_meta_alloc.
>
> Isn't it enough with this?
i am afraid someone do reset_store, so did lock.
yes, i am wrong, zram_meta_alloc should not be modified here. because meta->table has already cleared
meta->table = vzalloc(num_pages * sizeof(*meta->table));
>
> diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
> index c20b05a84f21..a25d34a8af19 100644
> --- a/drivers/block/zram/zram_drv.c
> +++ b/drivers/block/zram/zram_drv.c
> @@ -425,8 +425,11 @@ static void zram_meta_free(struct zram_meta *meta, u64 disksize)
> /* Free all pages that are still in this zram device */
> for (index = 0; index < num_pages; index++) {
> unsigned long handle = meta->table[index].handle;
> -
> - if (!handle)
> + /*
> + * No memory is allocated for same element filled pages.
> + * Simply clear same page flag.
> + */
> + if (!handle || zram_test_flag(meta, index, ZRAM_SAME))
> continue;
>
> zs_free(meta->mem_pool, handle);
>
> .
>
[toc] | [prev] | [next] | [standalone]
| From | Minchan Kim <minchan@kernel.org> |
|---|---|
| Date | 2017-02-07 06:00 +0100 |
| Message-ID | <t862J-6rI-1@gated-at.bofh.it> |
| In reply to | #1575356 |
On Tue, Feb 07, 2017 at 11:24:40AM +0800, zhouxianrong wrote:
>
>
> On 2017/2/7 10:54, Minchan Kim wrote:
> >On Tue, Feb 07, 2017 at 10:20:57AM +0800, zhouxianrong wrote:
> >
> >< snip >
> >
> >>>>3. the below should be modified.
> >>>>
> >>>>static inline bool zram_meta_get(struct zram *zram)
> >>>>@@ -495,11 +553,17 @@ static void zram_meta_free(struct zram_meta *meta, u64 disksize)
> >>>>
> >>>> /* Free all pages that are still in this zram device */
> >>>> for (index = 0; index < num_pages; index++) {
> >>>>- unsigned long handle = meta->table[index].handle;
> >>>>+ unsigned long handle;
> >>>>+
> >>>>+ bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value);
> >>>>+ handle = meta->table[index].handle;
> >>>>
> >>>>- if (!handle)
> >>>>+ if (!handle || zram_test_flag(meta, index, ZRAM_SAME)) {
> >>>>+ bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
> >>>> continue;
> >>>>+ }
> >>>>
> >>>>+ bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
> >>>> zs_free(meta->mem_pool, handle);
> >>>
> >>>Could you explain why we need this modification?
> >>>
> >>>> }
> >>>>
> >>>>@@ -511,7 +575,7 @@ static void zram_meta_free(struct zram_meta *meta, u64 disksize)
> >>>>static struct zram_meta *zram_meta_alloc(char *pool_name, u64 disksize)
> >>>>{
> >>>> size_t num_pages;
> >>>>- struct zram_meta *meta = kmalloc(sizeof(*meta), GFP_KERNEL);
> >>>>+ struct zram_meta *meta = kzalloc(sizeof(*meta), GFP_KERNEL);
> >>>
> >>>Ditto
> >>>
> >>>>
> >>>>
> >>>
> >>>.
> >>>
> >>
> >>because of union of handle and element, i think a non-zero element (other than handle) is prevented from freeing.
> >>if zram_meta_get was modified, zram_meta_alloc did so.
> >
> >Right. Thanks but I don't see why we need the locking in there and modification of
> >zram_meta_alloc.
> >
> >Isn't it enough with this?
>
> i am afraid someone do reset_store, so did lock.
reset_store is protected by zram->claim and and init_done so I don't
think so.
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web