kexec.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
From: Anthony Yznaga <anthony.yznaga@oracle.com>
To: linux-mm@kvack.org, linux-kernel@vger.kernel.org
Cc: tglx@linutronix.de, mingo@redhat.com, bp@alien8.de,
	x86@kernel.org, hpa@zytor.com, dave.hansen@linux.intel.com,
	luto@kernel.org, peterz@infradead.org, rppt@kernel.org,
	akpm@linux-foundation.org, ebiederm@xmission.com,
	keescook@chromium.org, graf@amazon.com, jason.zeng@intel.com,
	lei.l.li@intel.com, steven.sistare@oracle.com,
	fam.zheng@bytedance.com, mgalaxy@akamai.com,
	kexec@lists.infradead.org
Subject: [RFC v3 05/21] mm: PKRAM: implement byte stream operations
Date: Wed, 26 Apr 2023 17:08:41 -0700	[thread overview]
Message-ID: <1682554137-13938-6-git-send-email-anthony.yznaga@oracle.com> (raw)
In-Reply-To: <1682554137-13938-1-git-send-email-anthony.yznaga@oracle.com>

This patch adds the ability to save an arbitrary byte streams to a
a PKRAM object using pkram_write() to be restored later using pkram_read().

Originally-by: Vladimir Davydov <vdavydov.dev@gmail.com>
Signed-off-by: Anthony Yznaga <anthony.yznaga@oracle.com>
---
 include/linux/pkram.h |  11 +++++
 mm/pkram.c            | 123 ++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 130 insertions(+), 4 deletions(-)

diff --git a/include/linux/pkram.h b/include/linux/pkram.h
index 130ab5c2d94a..b614e9059bba 100644
--- a/include/linux/pkram.h
+++ b/include/linux/pkram.h
@@ -14,10 +14,12 @@
  * enum pkram_data_flags - definition of data types contained in a pkram obj
  * @PKRAM_DATA_none: No data types configured
  * @PKRAM_DATA_folios: obj contains folio data
+ * @PKRAM_DATA_bytes: obj contains byte data
  */
 enum pkram_data_flags {
 	PKRAM_DATA_none		= 0x0,	/* No data types configured */
 	PKRAM_DATA_folios	= 0x1,	/* Contains folio data */
+	PKRAM_DATA_bytes	= 0x2,	/* Contains byte data */
 };
 
 struct pkram_data_stream {
@@ -36,18 +38,27 @@ struct pkram_stream {
 
 	__u64 *folios_head_link_pfnp;
 	__u64 *folios_tail_link_pfnp;
+
+	__u64 *bytes_head_link_pfnp;
+	__u64 *bytes_tail_link_pfnp;
 };
 
 struct pkram_folios_access {
 	unsigned long next_index;
 };
 
+struct pkram_bytes_access {
+	struct page *data_page;		/* current page */
+	unsigned int data_offset;	/* offset into current page */
+};
+
 struct pkram_access {
 	enum pkram_data_flags dtype;
 	struct pkram_stream *ps;
 	struct pkram_data_stream pds;
 
 	struct pkram_folios_access folios;
+	struct pkram_bytes_access bytes;
 };
 
 #define PKRAM_NAME_MAX		256	/* including nul */
diff --git a/mm/pkram.c b/mm/pkram.c
index 610ff7a88c98..eac8cf6b0cdf 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>
@@ -44,6 +45,9 @@ struct pkram_link {
 struct pkram_obj {
 	__u64	folios_head_link_pfn;	/* the first folios link of the object */
 	__u64	folios_tail_link_pfn;	/* the last folios link of the object */
+	__u64	bytes_head_link_pfn;	/* the first bytes link of the object */
+	__u64	bytes_tail_link_pfn;	/* the last bytes link of the object */
+	__u64	data_len;	/* byte data size */
 	__u64	obj_pfn;	/* points to the next object in the list */
 };
 
@@ -138,6 +142,11 @@ static void pkram_truncate_obj(struct pkram_obj *obj)
 	pkram_truncate_links(obj->folios_head_link_pfn);
 	obj->folios_head_link_pfn = 0;
 	obj->folios_tail_link_pfn = 0;
+
+	pkram_truncate_links(obj->bytes_head_link_pfn);
+	obj->bytes_head_link_pfn = 0;
+	obj->bytes_tail_link_pfn = 0;
+	obj->data_len = 0;
 }
 
 static void pkram_truncate_node(struct pkram_node *node)
@@ -310,7 +319,7 @@ int pkram_prepare_save_obj(struct pkram_stream *ps, enum pkram_data_flags flags)
 
 	BUG_ON((node->flags & PKRAM_ACCMODE_MASK) != PKRAM_SAVE);
 
-	if (flags & ~PKRAM_DATA_folios)
+	if (flags & ~(PKRAM_DATA_folios | PKRAM_DATA_bytes))
 		return -EINVAL;
 
 	page = pkram_alloc_page(ps->gfp_mask | __GFP_ZERO);
@@ -326,6 +335,10 @@ int pkram_prepare_save_obj(struct pkram_stream *ps, enum pkram_data_flags flags)
 		ps->folios_head_link_pfnp = &obj->folios_head_link_pfn;
 		ps->folios_tail_link_pfnp = &obj->folios_tail_link_pfn;
 	}
+	if (flags & PKRAM_DATA_bytes) {
+		ps->bytes_head_link_pfnp = &obj->bytes_head_link_pfn;
+		ps->bytes_tail_link_pfnp = &obj->bytes_tail_link_pfn;
+	}
 	ps->obj = obj;
 	return 0;
 }
@@ -432,7 +445,7 @@ int pkram_prepare_load_obj(struct pkram_stream *ps)
 		return -ENODATA;
 
 	obj = pfn_to_kaddr(node->obj_pfn);
-	if (!obj->folios_head_link_pfn) {
+	if (!obj->folios_head_link_pfn && !obj->bytes_head_link_pfn) {
 		WARN_ON(1);
 		return -EINVAL;
 	}
@@ -443,6 +456,10 @@ int pkram_prepare_load_obj(struct pkram_stream *ps)
 		ps->folios_head_link_pfnp = &obj->folios_head_link_pfn;
 		ps->folios_tail_link_pfnp = &obj->folios_tail_link_pfn;
 	}
+	if (obj->bytes_head_link_pfn) {
+		ps->bytes_head_link_pfnp = &obj->bytes_head_link_pfn;
+		ps->bytes_tail_link_pfnp = &obj->bytes_tail_link_pfn;
+	}
 	ps->obj = obj;
 	return 0;
 }
@@ -493,6 +510,9 @@ void pkram_finish_access(struct pkram_access *pa, bool status_ok)
 
 	if (pa->pds.link)
 		pkram_truncate_link(pa->pds.link);
+
+	if ((pa->dtype == PKRAM_DATA_bytes) && (pa->bytes.data_page))
+		pkram_free_page(page_address(pa->bytes.data_page));
 }
 
 /*
@@ -547,6 +567,22 @@ int pkram_save_folio(struct pkram_access *pa, struct folio *folio)
 	return __pkram_save_page(pa, page, page->index);
 }
 
+static int __pkram_bytes_save_page(struct pkram_access *pa, struct page *page)
+{
+	struct pkram_data_stream *pds = &pa->pds;
+	struct pkram_link *link = pds->link;
+
+	if (!link || pds->entry_idx >= PKRAM_LINK_ENTRIES_MAX) {
+		link = pkram_new_link(pds, pa->ps->gfp_mask);
+		if (!link)
+			return -ENOMEM;
+	}
+
+	pkram_add_link_entry(pds, page);
+
+	return 0;
+}
+
 static struct page *__pkram_prep_load_page(pkram_entry_t p)
 {
 	struct page *page;
@@ -662,10 +698,53 @@ struct folio *pkram_load_folio(struct pkram_access *pa, unsigned long *index)
  *
  * 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_access *pa, const void *buf, size_t count)
 {
-	return -EINVAL;
+	struct pkram_node *node = pa->ps->node;
+	struct pkram_obj *obj = pa->ps->obj;
+	size_t copy_count, write_count = 0;
+	void *addr;
+
+	BUG_ON((node->flags & PKRAM_ACCMODE_MASK) != PKRAM_SAVE);
+
+	while (count > 0) {
+		if (!pa->bytes.data_page) {
+			gfp_t gfp_mask = pa->ps->gfp_mask;
+			struct page *page;
+			int err;
+
+			page = pkram_alloc_page((gfp_mask & GFP_RECLAIM_MASK) |
+					       __GFP_HIGHMEM | __GFP_ZERO);
+			if (!page)
+				return -ENOMEM;
+			err = __pkram_bytes_save_page(pa, page);
+			if (err) {
+				pkram_free_page(page_address(page));
+				return err;
+			}
+			pa->bytes.data_page = page;
+			pa->bytes.data_offset = 0;
+		}
+
+		copy_count = min_t(size_t, count, PAGE_SIZE - pa->bytes.data_offset);
+		addr = kmap_local_page(pa->bytes.data_page);
+		memcpy(addr + pa->bytes.data_offset, buf, copy_count);
+		kunmap_local(addr);
+
+		buf += copy_count;
+		obj->data_len += copy_count;
+		pa->bytes.data_offset += copy_count;
+		if (pa->bytes.data_offset >= PAGE_SIZE)
+			pa->bytes.data_page = NULL;
+
+		write_count += copy_count;
+		count -= copy_count;
+	}
+	return write_count;
 }
 
 /**
@@ -679,5 +758,41 @@ ssize_t pkram_write(struct pkram_access *pa, const void *buf, size_t count)
  */
 size_t pkram_read(struct pkram_access *pa, void *buf, size_t count)
 {
-	return 0;
+	struct pkram_node *node = pa->ps->node;
+	struct pkram_obj *obj = pa->ps->obj;
+	size_t copy_count, read_count = 0;
+	char *addr;
+
+	BUG_ON((node->flags & PKRAM_ACCMODE_MASK) != PKRAM_LOAD);
+
+	while (count > 0 && obj->data_len > 0) {
+		if (!pa->bytes.data_page) {
+			struct page *page;
+
+			page = __pkram_load_page(pa, NULL);
+			if (IS_ERR_OR_NULL(page))
+				break;
+			pa->bytes.data_page = page;
+			pa->bytes.data_offset = 0;
+		}
+
+		copy_count = min_t(size_t, count, PAGE_SIZE - pa->bytes.data_offset);
+		if (copy_count > obj->data_len)
+			copy_count = obj->data_len;
+		addr = kmap_local_page(pa->bytes.data_page);
+		memcpy(buf, addr + pa->bytes.data_offset, copy_count);
+		kunmap_local(addr);
+
+		buf += copy_count;
+		obj->data_len -= copy_count;
+		pa->bytes.data_offset += copy_count;
+		if (pa->bytes.data_offset >= PAGE_SIZE || !obj->data_len) {
+			put_page(pa->bytes.data_page);
+			pa->bytes.data_page = NULL;
+		}
+
+		read_count += copy_count;
+		count -= copy_count;
+	}
+	return read_count;
 }
-- 
1.9.4


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

  parent reply	other threads:[~2023-04-27  0:10 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-04-27  0:08 [RFC v3 00/21] Preserved-over-Kexec RAM Anthony Yznaga
2023-04-27  0:08 ` [RFC v3 01/21] mm: add PKRAM API stubs and Kconfig Anthony Yznaga
2023-04-27  0:08 ` [RFC v3 02/21] mm: PKRAM: implement node load and save functions Anthony Yznaga
2023-04-27  0:08 ` [RFC v3 03/21] mm: PKRAM: implement object " Anthony Yznaga
2023-04-27  0:08 ` [RFC v3 04/21] mm: PKRAM: implement folio stream operations Anthony Yznaga
2023-04-27  0:08 ` Anthony Yznaga [this message]
2023-04-27  0:08 ` [RFC v3 06/21] mm: PKRAM: link nodes by pfn before reboot Anthony Yznaga
2023-04-27  0:08 ` [RFC v3 07/21] mm: PKRAM: introduce super block Anthony Yznaga
2023-06-05  2:40   ` Coiby Xu
2023-06-06  2:01     ` Anthony Yznaga
2023-06-06  2:55       ` Coiby Xu
2023-06-06  3:12         ` Anthony Yznaga
2023-04-27  0:08 ` [RFC v3 08/21] PKRAM: track preserved pages in a physical mapping pagetable Anthony Yznaga
2023-04-27  0:08 ` [RFC v3 09/21] PKRAM: pass a list of preserved ranges to the next kernel Anthony Yznaga
2023-04-27  0:08 ` [RFC v3 10/21] PKRAM: prepare for adding preserved ranges to memblock reserved Anthony Yznaga
2023-04-27  0:08 ` [RFC v3 11/21] mm: PKRAM: reserve preserved memory at boot Anthony Yznaga
2023-04-27  0:08 ` [RFC v3 12/21] PKRAM: free the preserved ranges list Anthony Yznaga
2023-04-27  0:08 ` [RFC v3 13/21] PKRAM: prevent inadvertent use of a stale superblock Anthony Yznaga
2023-04-27  0:08 ` [RFC v3 14/21] PKRAM: provide a way to ban pages from use by PKRAM Anthony Yznaga
2023-04-27  0:08 ` [RFC v3 15/21] kexec: PKRAM: prevent kexec clobbering preserved pages in some cases Anthony Yznaga
2023-04-27  0:08 ` [RFC v3 16/21] PKRAM: provide a way to check if a memory range has preserved pages Anthony Yznaga
2023-04-27  0:08 ` [RFC v3 17/21] kexec: PKRAM: avoid clobbering already " Anthony Yznaga
2023-04-27  0:08 ` [RFC v3 18/21] mm: PKRAM: allow preserved memory to be freed from userspace Anthony Yznaga
2023-04-27  0:08 ` [RFC v3 19/21] PKRAM: disable feature when running the kdump kernel Anthony Yznaga
2023-04-27  0:08 ` [RFC v3 20/21] x86/KASLR: PKRAM: support physical kaslr Anthony Yznaga
2023-04-27  0:08 ` [RFC v3 21/21] x86/boot/compressed/64: use 1GB pages for mappings Anthony Yznaga
2023-04-27 18:40   ` H. Peter Anvin
2023-04-27 22:38     ` Anthony Yznaga
2023-05-26 13:57 ` [RFC v3 00/21] Preserved-over-Kexec RAM Gowans, James
2023-05-31 23:14   ` Anthony Yznaga
2023-06-01  2:15 ` Baoquan He
2023-06-01 23:58   ` Anthony Yznaga

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1682554137-13938-6-git-send-email-anthony.yznaga@oracle.com \
    --to=anthony.yznaga@oracle.com \
    --cc=akpm@linux-foundation.org \
    --cc=bp@alien8.de \
    --cc=dave.hansen@linux.intel.com \
    --cc=ebiederm@xmission.com \
    --cc=fam.zheng@bytedance.com \
    --cc=graf@amazon.com \
    --cc=hpa@zytor.com \
    --cc=jason.zeng@intel.com \
    --cc=keescook@chromium.org \
    --cc=kexec@lists.infradead.org \
    --cc=lei.l.li@intel.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=luto@kernel.org \
    --cc=mgalaxy@akamai.com \
    --cc=mingo@redhat.com \
    --cc=peterz@infradead.org \
    --cc=rppt@kernel.org \
    --cc=steven.sistare@oracle.com \
    --cc=tglx@linutronix.de \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).