From: Vladimir Davydov <vdavydov@parallels.com>
To: linux-kernel@vger.kernel.org
Cc: linux-mm@kvack.org, criu@openvz.org, devel@openvz.org,
xemul@parallels.com, khorenko@parallels.com
Subject: [PATCH RFC 04/13] mm: PRAM: implement byte stream operations
Date: Mon, 1 Jul 2013 15:57:39 +0400 [thread overview]
Message-ID: <65bcf77aad13e514e805dd3e26a479ad42ce93c7.1372582755.git.vdavydov@parallels.com> (raw)
In-Reply-To: <cover.1372582754.git.vdavydov@parallels.com>
This patch adds ability to save arbitrary byte strings to PRAM using
pram_write() to be restored later using pram_read(). These two
operations are implemented on top of pram_save_page() and
pram_load_page() respectively.
---
include/linux/pram.h | 4 +++
mm/pram.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 88 insertions(+), 2 deletions(-)
diff --git a/include/linux/pram.h b/include/linux/pram.h
index dd17316..61c536c 100644
--- a/include/linux/pram.h
+++ b/include/linux/pram.h
@@ -13,6 +13,10 @@ struct pram_stream {
struct pram_node *node;
struct pram_link *link; /* current link */
unsigned int page_index; /* next page index in link */
+
+ /* byte-stream specific */
+ struct page *data_page;
+ unsigned int data_offset;
};
#define PRAM_NAME_MAX 256 /* including nul */
diff --git a/mm/pram.c b/mm/pram.c
index a443eb0..f7eebe1 100644
--- a/mm/pram.c
+++ b/mm/pram.c
@@ -1,5 +1,6 @@
#include <linux/err.h>
#include <linux/gfp.h>
+#include <linux/highmem.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/mm.h>
@@ -46,6 +47,7 @@ struct pram_link {
struct pram_node {
__u32 flags; /* see PRAM_* flags below */
__u32 type; /* data type, see enum pram_stream_type */
+ __u64 data_len; /* data size, only for byte streams */
__u64 link_pfn; /* points to the first link of the node */
__u8 name[PRAM_NAME_MAX];
@@ -284,6 +286,9 @@ void pram_finish_load(struct pram_stream *ps)
BUG_ON((node->flags & PRAM_ACCMODE_MASK) != PRAM_LOAD);
+ if (ps->data_page)
+ put_page(ps->data_page);
+
pram_truncate_node(node);
pram_free_page(node);
}
@@ -422,10 +427,51 @@ struct page *pram_load_page(struct pram_stream *ps, int *flags)
*
* 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 pram_write(struct pram_stream *ps, const void *buf, size_t count)
{
- return -ENOSYS;
+ void *addr;
+ size_t copy_count, write_count = 0;
+ struct pram_node *node = ps->node;
+
+ BUG_ON(node->type != PRAM_BYTE_STREAM);
+ BUG_ON((node->flags & PRAM_ACCMODE_MASK) != PRAM_SAVE);
+
+ while (count > 0) {
+ if (!ps->data_page) {
+ struct page *page;
+ int err;
+
+ page = pram_alloc_page((ps->gfp_mask & GFP_RECLAIM_MASK) |
+ __GFP_HIGHMEM | __GFP_ZERO);
+ if (!page)
+ return -ENOMEM;
+ err = __pram_save_page(ps, page, 0);
+ put_page(page);
+ if (err)
+ return err;
+ ps->data_page = page;
+ ps->data_offset = 0;
+ }
+
+ copy_count = min_t(size_t, count, PAGE_SIZE - ps->data_offset);
+ addr = kmap_atomic(ps->data_page);
+ memcpy(addr + ps->data_offset, buf, copy_count);
+ kunmap_atomic(addr);
+
+ buf += copy_count;
+ node->data_len += copy_count;
+ ps->data_offset += copy_count;
+ if (ps->data_offset >= PAGE_SIZE)
+ ps->data_page = NULL;
+
+ write_count += copy_count;
+ count -= copy_count;
+ }
+ return write_count;
}
/**
@@ -437,5 +483,41 @@ ssize_t pram_write(struct pram_stream *ps, const void *buf, size_t count)
*/
size_t pram_read(struct pram_stream *ps, void *buf, size_t count)
{
- return 0;
+ char *addr;
+ size_t copy_count, read_count = 0;
+ struct pram_node *node = ps->node;
+
+ BUG_ON(node->type != PRAM_BYTE_STREAM);
+ BUG_ON((node->flags & PRAM_ACCMODE_MASK) != PRAM_LOAD);
+
+ while (count > 0 && node->data_len > 0) {
+ if (!ps->data_page) {
+ struct page *page;
+
+ page = __pram_load_page(ps, NULL);
+ if (!page)
+ break;
+ ps->data_page = page;
+ ps->data_offset = 0;
+ }
+
+ copy_count = min_t(size_t, count, PAGE_SIZE - ps->data_offset);
+ if (copy_count > node->data_len)
+ copy_count = node->data_len;
+ addr = kmap_atomic(ps->data_page);
+ memcpy(buf, addr + ps->data_offset, copy_count);
+ kunmap_atomic(addr);
+
+ buf += copy_count;
+ node->data_len -= copy_count;
+ ps->data_offset += copy_count;
+ if (ps->data_offset >= PAGE_SIZE || !node->data_len) {
+ put_page(ps->data_page);
+ ps->data_page = NULL;
+ }
+
+ read_count += copy_count;
+ count -= copy_count;
+ }
+ return read_count;
}
--
1.7.10.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
next prev parent reply other threads:[~2013-07-01 11:58 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-07-01 11:57 [PATCH RFC 00/13] PRAM: Persistent over-kexec memory storage Vladimir Davydov
2013-07-01 11:57 ` [PATCH RFC 01/13] mm: add PRAM API stubs and Kconfig Vladimir Davydov
2013-07-01 11:57 ` [PATCH RFC 02/13] mm: PRAM: implement node load and save functions Vladimir Davydov
2013-07-01 11:57 ` [PATCH RFC 03/13] mm: PRAM: implement page stream operations Vladimir Davydov
2013-07-01 11:57 ` Vladimir Davydov [this message]
2013-07-01 11:57 ` [PATCH RFC 05/13] mm: PRAM: link nodes by pfn before reboot Vladimir Davydov
2013-07-01 11:57 ` [PATCH RFC 06/13] mm: PRAM: introduce super block Vladimir Davydov
2013-07-01 11:57 ` [PATCH RFC 07/13] mm: PRAM: preserve persistent memory at boot Vladimir Davydov
2013-07-01 11:57 ` [PATCH RFC 08/13] mm: PRAM: checksum saved data Vladimir Davydov
2013-07-01 11:57 ` [PATCH RFC 09/13] mm: PRAM: ban pages that have been reserved at boot time Vladimir Davydov
2013-07-01 11:57 ` [PATCH RFC 10/13] mm: PRAM: allow to ban arbitrary memory ranges Vladimir Davydov
2013-07-01 11:57 ` [PATCH RFC 11/13] mm: PRAM: allow to free persistent memory from userspace Vladimir Davydov
2013-07-01 11:57 ` [PATCH RFC 12/13] mm: shmem: introduce shmem_insert_page Vladimir Davydov
2013-07-01 11:57 ` [PATCH RFC 13/13] mm: shmem: enable saving to PRAM Vladimir Davydov
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=65bcf77aad13e514e805dd3e26a479ad42ce93c7.1372582755.git.vdavydov@parallels.com \
--to=vdavydov@parallels.com \
--cc=criu@openvz.org \
--cc=devel@openvz.org \
--cc=khorenko@parallels.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=xemul@parallels.com \
/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