linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Al Viro <viro@ZenIV.linux.org.uk>
To: Linus Torvalds <torvalds@linux-foundation.org>
Cc: linux-arch@vger.kernel.org, linux-kernel@vger.kernel.org,
	David Miller <davem@davemloft.net>,
	Tony Luck <tony.luck@intel.com>, Will Deacon <will@kernel.org>
Subject: [PATCH 18/41] regset: new method and helpers for it
Date: Mon, 29 Jun 2020 19:26:05 +0100	[thread overview]
Message-ID: <20200629182628.529995-18-viro@ZenIV.linux.org.uk> (raw)
In-Reply-To: <20200629182628.529995-1-viro@ZenIV.linux.org.uk>

From: Al Viro <viro@zeniv.linux.org.uk>

->get2() takes task+regset+buffer, returns the amount of free space
left in the buffer on success and -E... on error.

buffer is represented as struct membuf - a pair of (kernel) pointer
and amount of space left

Primitives for writing to such:
	* membuf_write(buf, data, size)
	* membuf_zero(buf, size)
	* membuf_store(buf, value)

These are implemented as inlines (in case of membuf_store - a macro).
All writes are sequential; they become no-ops when there's no space
left.  Return value of all primitives is the amount of space left
after the operation, so they can be used as return values of ->get2().

Example of use:

// stores pt_regs of task + 64 bytes worth of zeroes + 32bit PID of task
int foo_get(struct task_struct *task, const struct regset *regset,
	    struct membuf to)
{
	membuf_write(&to, task_pt_regs(task), sizeof(struct pt_regs));
	membuf_zero(&to, 64);
	return membuf_store(&to, (u32)task_tgid_vnr(task));
}

regset_get()/regset_get_alloc() taught to use that thing if present.
By the end of the series all users of ->get() will be converted;
then ->get() and ->get_size() can go.

Note that unlike ->get() this thing always starts at offset 0 and,
since it only writes to kernel buffer, can't fail on copyout.
It can, of course, fail for other reasons, but those tend to
be less numerous.

The caller guarantees that the buffer size won't be bigger than
regset->n * regset->size.  That simplifies life for quite a few
instances.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 include/linux/regset.h | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++
 kernel/regset.c        | 12 +++++++++++-
 2 files changed, 62 insertions(+), 1 deletion(-)

diff --git a/include/linux/regset.h b/include/linux/regset.h
index af57c1db1924..567a4b63f469 100644
--- a/include/linux/regset.h
+++ b/include/linux/regset.h
@@ -17,6 +17,52 @@
 struct task_struct;
 struct user_regset;
 
+struct membuf {
+	void *p;
+	size_t left;
+};
+
+static inline int membuf_zero(struct membuf *s, size_t size)
+{
+	if (s->left) {
+		if (size > s->left)
+			size = s->left;
+		memset(s->p, 0, size);
+		s->p += size;
+		s->left -= size;
+	}
+	return s->left;
+}
+
+static inline int membuf_write(struct membuf *s, const void *v, size_t size)
+{
+	if (s->left) {
+		if (size > s->left)
+			size = s->left;
+		memcpy(s->p, v, size);
+		s->p += size;
+		s->left -= size;
+	}
+	return s->left;
+}
+
+/* current s->p must be aligned for v; v must be a scalar */
+#define membuf_store(s, v)				\
+({							\
+	struct membuf *__s = (s);			\
+        if (__s->left) {				\
+		typeof(v) __v = (v);			\
+		size_t __size = sizeof(__v);		\
+		if (unlikely(__size > __s->left)) {	\
+			__size = __s->left;		\
+			memcpy(__s->p, &__v, __size);	\
+		} else {				\
+			*(typeof(__v + 0) *)__s->p = __v;	\
+		}					\
+		__s->p += __size;			\
+		__s->left -= __size;			\
+	}						\
+	__s->left;})
 
 /**
  * user_regset_active_fn - type of @active function in &struct user_regset
@@ -57,6 +103,10 @@ typedef int user_regset_get_fn(struct task_struct *target,
 			       unsigned int pos, unsigned int count,
 			       void *kbuf, void __user *ubuf);
 
+typedef int user_regset_get2_fn(struct task_struct *target,
+			       const struct user_regset *regset,
+			       struct membuf to);
+
 /**
  * user_regset_set_fn - type of @set function in &struct user_regset
  * @target:	thread being examined
@@ -186,6 +236,7 @@ typedef unsigned int user_regset_get_size_fn(struct task_struct *target,
  */
 struct user_regset {
 	user_regset_get_fn		*get;
+	user_regset_get2_fn		*get2;
 	user_regset_set_fn		*set;
 	user_regset_active_fn		*active;
 	user_regset_writeback_fn	*writeback;
diff --git a/kernel/regset.c b/kernel/regset.c
index 0a610983ce43..c548fb9f0943 100644
--- a/kernel/regset.c
+++ b/kernel/regset.c
@@ -11,7 +11,7 @@ static int __regset_get(struct task_struct *target,
 	void *p = *data, *to_free = NULL;
 	int res;
 
-	if (!regset->get)
+	if (!regset->get && !regset->get2)
 		return -EOPNOTSUPP;
 	if (size > regset->n * regset->size)
 		size = regset->n * regset->size;
@@ -20,6 +20,16 @@ static int __regset_get(struct task_struct *target,
 		if (!p)
 			return -ENOMEM;
 	}
+	if (regset->get2) {
+		res = regset->get2(target, regset,
+				   (struct membuf){.p = p, .left = size});
+		if (res < 0) {
+			kfree(to_free);
+			return res;
+		}
+		*data = p;
+		return size - res;
+	}
 	res = regset->get(target, regset, 0, size, p, NULL);
 	if (unlikely(res < 0)) {
 		kfree(to_free);
-- 
2.11.0


  parent reply	other threads:[~2020-06-29 18:43 UTC|newest]

Thread overview: 51+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-06-29 18:23 [RFC][PATCHSET] regset ->get() rework Al Viro
2020-06-29 18:25 ` [PATCH 01/41] introduction of regset ->get() wrappers, switching ELF coredumps to those Al Viro
2020-06-29 18:25   ` [PATCH 02/41] x86: copy_fpstate_to_sigframe(): have fpregs_soft_get() use kernel buffer Al Viro
2020-06-29 18:25   ` [PATCH 03/41] x86: kill dump_fpu() Al Viro
2020-06-29 18:25   ` [PATCH 04/41] [ia64] sanitize elf_access_gpreg() Al Viro
2020-06-29 18:25   ` [PATCH 05/41] [ia64] teach elf_access_reg() to handle the missing range (r16..r31) Al Viro
2020-06-29 18:25   ` [PATCH 06/41] [ia64] regularize do_gpregs_[gs]et() Al Viro
2020-06-29 18:25   ` [PATCH 07/41] [ia64] access_uarea(): stop bothering with gpregs_[gs]et() Al Viro
2020-06-29 18:25   ` [PATCH 08/41] [ia64] access_uarea(): don't bother with fpregs_[gs]et() Al Viro
2020-06-29 18:25   ` [PATCH 09/41] sparc64: switch genregs32_get() to use of get_from_target() Al Viro
2020-06-29 18:25   ` [PATCH 10/41] sparc32: get rid of odd callers of copy_regset_to_user() Al Viro
2020-06-29 18:25   ` [PATCH 11/41] sparc64: " Al Viro
2020-06-29 18:25   ` [PATCH 12/41] sparc32: get rid of odd callers of copy_regset_from_user() Al Viro
2020-06-29 18:26   ` [PATCH 13/41] sparc64: " Al Viro
2020-06-29 18:26   ` [PATCH 14/41] arm64: take fetching compat reg out of pt_regs into a new helper Al Viro
2020-06-29 18:26   ` [PATCH 15/41] arm64: get rid of copy_regset_to_user() in compat_ptrace_read_user() Al Viro
2020-06-29 18:26   ` [PATCH 16/41] arm64: sanitize compat_ptrace_write_user() Al Viro
2020-06-29 18:26   ` [PATCH 17/41] copy_regset_to_user(): do all copyout at once Al Viro
2020-06-29 18:26   ` Al Viro [this message]
2020-06-29 19:23     ` [PATCH 18/41] regset: new method and helpers for it Linus Torvalds
2020-06-29 20:30       ` Al Viro
2020-06-30 13:25         ` Al Viro
2020-06-30 16:53           ` Linus Torvalds
2020-06-30 19:40             ` Al Viro
2020-06-29 18:26   ` [PATCH 19/41] x86: switch to ->get2() Al Viro
2020-06-29 18:26   ` [PATCH 20/41] powerpc: " Al Viro
2020-06-29 18:26   ` [PATCH 21/41] s390: " Al Viro
2020-06-29 18:26   ` [PATCH 22/41] sparc: " Al Viro
2020-06-30 13:16     ` Al Viro
2020-06-29 18:26   ` [PATCH 23/41] mips: " Al Viro
2020-06-29 18:26   ` [PATCH 24/41] arm64: " Al Viro
2020-06-29 18:26   ` [PATCH 25/41] sh: convert " Al Viro
2020-06-29 18:26   ` [PATCH 26/41] arm: switch " Al Viro
2020-06-29 18:26   ` [PATCH 27/41] arc: " Al Viro
2020-06-29 18:26   ` [PATCH 28/41] ia64: " Al Viro
2020-06-29 18:26   ` [PATCH 29/41] c6x: " Al Viro
2020-06-29 18:26   ` [PATCH 30/41] riscv: " Al Viro
2020-06-29 18:26   ` [PATCH 31/41] openrisc: " Al Viro
2020-06-29 18:26   ` [PATCH 32/41] h8300: " Al Viro
2020-06-29 18:26   ` [PATCH 33/41] hexagon: " Al Viro
2020-08-11 18:35     ` Brian Cain
2020-06-29 18:26   ` [PATCH 34/41] nios2: " Al Viro
2020-06-29 18:26   ` [PATCH 35/41] nds32: " Al Viro
2020-06-29 18:26   ` [PATCH 36/41] parisc: " Al Viro
2020-06-29 18:26   ` [PATCH 37/41] xtensa: " Al Viro
2020-06-29 18:26   ` [PATCH 38/41] csky: " Al Viro
2020-06-29 18:26   ` [PATCH 39/41] regset: kill ->get() Al Viro
2020-06-29 18:26   ` [PATCH 40/41] regset(): kill ->get_size() Al Viro
2020-06-29 18:26   ` [PATCH 41/41] regset: kill user_regset_copyout{,_zero}() Al Viro
2020-07-23  8:00 ` [RFC][PATCHSET] regset ->get() rework Christoph Hellwig
2020-07-23 17:27   ` Al Viro

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=20200629182628.529995-18-viro@ZenIV.linux.org.uk \
    --to=viro@zeniv.linux.org.uk \
    --cc=davem@davemloft.net \
    --cc=linux-arch@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=tony.luck@intel.com \
    --cc=torvalds@linux-foundation.org \
    --cc=will@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).