[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1588812129-8596-7-git-send-email-anthony.yznaga@oracle.com>
Date: Wed, 6 May 2020 17:41:32 -0700
From: Anthony Yznaga <anthony.yznaga@...cle.com>
To: linux-mm@...ck.org, linux-kernel@...r.kernel.org
Cc: willy@...radead.org, corbet@....net, tglx@...utronix.de,
mingo@...hat.com, bp@...en8.de, x86@...nel.org, hpa@...or.com,
dave.hansen@...ux.intel.com, luto@...nel.org, peterz@...radead.org,
rppt@...ux.ibm.com, akpm@...ux-foundation.org, hughd@...gle.com,
ebiederm@...ssion.com, masahiroy@...nel.org, ardb@...nel.org,
ndesaulniers@...gle.com, dima@...ovin.in, daniel.kiper@...cle.com,
nivedita@...m.mit.edu, rafael.j.wysocki@...el.com,
dan.j.williams@...el.com, zhenzhong.duan@...cle.com,
jroedel@...e.de, bhe@...hat.com, guro@...com,
Thomas.Lendacky@....com, andriy.shevchenko@...ux.intel.com,
keescook@...omium.org, hannes@...xchg.org, minchan@...nel.org,
mhocko@...nel.org, ying.huang@...el.com,
yang.shi@...ux.alibaba.com, gustavo@...eddedor.com,
ziqian.lzq@...fin.com, vdavydov.dev@...il.com,
jason.zeng@...el.com, kevin.tian@...el.com, zhiyuan.lv@...el.com,
lei.l.li@...el.com, paul.c.lai@...el.com, ashok.raj@...el.com,
linux-fsdevel@...r.kernel.org, linux-doc@...r.kernel.org,
kexec@...ts.infradead.org
Subject: [RFC 06/43] mm: PKRAM: implement byte stream operations
This patch adds the ability to save arbitrary byte streams up to a
total length of one page to a PKRAM object using pkram_write() to be
restored later using pkram_read().
Originally-by: Vladimir Davydov <vdavydov.dev@...il.com>
Signed-off-by: Anthony Yznaga <anthony.yznaga@...cle.com>
---
include/linux/pkram.h | 4 +++
mm/pkram.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 86 insertions(+), 2 deletions(-)
diff --git a/include/linux/pkram.h b/include/linux/pkram.h
index 584cadb662b4..a58dd2ea835a 100644
--- a/include/linux/pkram.h
+++ b/include/linux/pkram.h
@@ -17,6 +17,10 @@ struct pkram_stream {
unsigned int entry_idx; /* next entry in link */
unsigned long next_index;
+
+ /* byte data */
+ struct page *data_page;
+ unsigned int data_offset;
};
#define PKRAM_NAME_MAX 256 /* including nul */
diff --git a/mm/pkram.c b/mm/pkram.c
index 9164060e36f5..06b471eea0b0 100644
--- a/mm/pkram.c
+++ b/mm/pkram.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/err.h>
#include <linux/gfp.h>
+#include <linux/highmem.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/list.h>
@@ -42,6 +43,8 @@ struct pkram_link {
((PAGE_SIZE-sizeof(struct pkram_link))/sizeof(pkram_entry_t))
struct pkram_obj {
+ __u64 data_pfn; /* points to the byte data */
+ __u64 data_len; /* byte data size */
__u64 link_pfn; /* points to the first link of the object */
__u64 obj_pfn; /* points to the next object in the list */
};
@@ -407,6 +410,9 @@ void pkram_finish_load_obj(struct pkram_stream *ps)
}
}
+ if (ps->data_page)
+ pkram_free_page(page_address(ps->data_page));
+
pkram_truncate_obj(obj);
pkram_free_page(obj);
}
@@ -422,6 +428,9 @@ void pkram_finish_load(struct pkram_stream *ps)
BUG_ON((node->flags & PKRAM_ACCMODE_MASK) != PKRAM_LOAD);
+ if (ps->data_page)
+ put_page(ps->data_page);
+
pkram_truncate_node(node);
pkram_free_page(node);
}
@@ -581,10 +590,41 @@ struct page *pkram_load_page(struct pkram_stream *ps, unsigned long *index, shor
*
* On success, returns the number of bytes written, which is always equal to
* @count. On failure, -errno is returned.
+ *
+ * Error values:
+ * %ENOMEM: insufficient amount of memory available
*/
ssize_t pkram_write(struct pkram_stream *ps, const void *buf, size_t count)
{
- return -ENOSYS;
+ struct pkram_node *node = ps->node;
+ struct pkram_obj *obj = ps->obj;
+ void *addr;
+
+ BUG_ON((node->flags & PKRAM_ACCMODE_MASK) != PKRAM_SAVE);
+
+ if (!ps->data_page) {
+ struct page *page;
+
+ page = pkram_alloc_page((ps->gfp_mask & GFP_RECLAIM_MASK) |
+ __GFP_HIGHMEM | __GFP_ZERO);
+ if (!page)
+ return -ENOMEM;
+
+ ps->data_page = page;
+ ps->data_offset = 0;
+ obj->data_pfn = page_to_pfn(page);
+ }
+
+ BUG_ON(count > PAGE_SIZE - ps->data_offset);
+
+ addr = kmap_atomic(ps->data_page);
+ memcpy(addr + ps->data_offset, buf, count);
+ kunmap_atomic(addr);
+
+ obj->data_len += count;
+ ps->data_offset += count;
+
+ return count;
}
/**
@@ -597,5 +637,45 @@ ssize_t pkram_write(struct pkram_stream *ps, const void *buf, size_t count)
*/
size_t pkram_read(struct pkram_stream *ps, void *buf, size_t count)
{
- return 0;
+ struct pkram_node *node = ps->node;
+ struct pkram_obj *obj = ps->obj;
+ size_t copy_count;
+ char *addr;
+
+ BUG_ON((node->flags & PKRAM_ACCMODE_MASK) != PKRAM_LOAD);
+
+ if (!count || !obj->data_len)
+ return 0;
+
+ if (!ps->data_page) {
+ struct page *page;
+
+ page = pfn_to_page(obj->data_pfn);
+ if (!page)
+ return 0;
+
+ ps->data_page = page;
+ ps->data_offset = 0;
+ obj->data_pfn = 0;
+ }
+
+ BUG_ON(count > PAGE_SIZE - ps->data_offset);
+
+ copy_count = min_t(size_t, count, PAGE_SIZE - ps->data_offset);
+ if (copy_count > obj->data_len)
+ copy_count = obj->data_len;
+
+ addr = kmap_atomic(ps->data_page);
+ memcpy(buf, addr + ps->data_offset, copy_count);
+ kunmap_atomic(addr);
+
+ obj->data_len -= copy_count;
+ ps->data_offset += copy_count;
+
+ if (!obj->data_len) {
+ pkram_free_page(page_address(ps->data_page));
+ ps->data_page = NULL;
+ }
+
+ return copy_count;
}
--
2.13.3
Powered by blists - more mailing lists