[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <4ea86b6d9f4e3ba0126f9961b98407549d7f0294.1597233555.git.christophe.leroy@csgroup.eu>
Date: Wed, 12 Aug 2020 12:06:10 +0000 (UTC)
From: Christophe Leroy <christophe.leroy@...roup.eu>
To: Benjamin Herrenschmidt <benh@...nel.crashing.org>,
Paul Mackerras <paulus@...ba.org>,
Michael Ellerman <mpe@...erman.id.au>, ldv@...linux.org,
viro@...iv.linux.org.uk
Cc: linux-kernel@...r.kernel.org, linuxppc-dev@...ts.ozlabs.org
Subject: [RFC PATCH v1 18/19] powerpc/signal32: Add and use
unsafe_put_sigset_t()
put_sigset_t() calls copy_to_user() for copying two words.
Because INLINE_COPY_TO_USER is not defined on powerpc,
copy_to_user() doesn't get optimised and falls back to
copy_tofrom_user() with the relevant glue. This is terribly
inefficient for copying two words.
By switching to unsafe_put_user(), we end up with something as
simple as:
3cc: 81 3d 00 00 lwz r9,0(r29)
3d0: 91 26 00 b4 stw r9,180(r6)
3d4: 81 3d 00 04 lwz r9,4(r29)
3d8: 91 26 00 b8 stw r9,184(r6)
Signed-off-by: Christophe Leroy <christophe.leroy@...roup.eu>
---
arch/powerpc/kernel/signal_32.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index d03ba3d8eb68..6cbff0293ff4 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -87,6 +87,8 @@ static inline int put_sigset_t(compat_sigset_t __user *uset, sigset_t *set)
return put_compat_sigset(uset, set, sizeof(*uset));
}
+#define unsafe_put_sigset_t unsafe_put_compat_sigset
+
static inline int get_sigset_t(sigset_t *set,
const compat_sigset_t __user *uset)
{
@@ -143,6 +145,13 @@ static inline int put_sigset_t(sigset_t __user *uset, sigset_t *set)
return copy_to_user(uset, set, sizeof(*uset));
}
+#define unsafe_put_sigset_t(uset, set, label) do { \
+ sigset_t __user *__us = uset ; \
+ const sigset_t *__s = set; \
+ \
+ unsafe_copy_to_user(__us, __s, sizeof(*__us), label); \
+} while (0)
+
static inline int get_sigset_t(sigset_t *set, const sigset_t __user *uset)
{
return copy_from_user(set, uset, sizeof(*uset));
@@ -820,10 +829,11 @@ int handle_rt_signal32(struct ksignal *ksig, sigset_t *oldset,
{
unsafe_put_user(0, &rt_sf->uc.uc_link, failed);
}
+
+ unsafe_put_sigset_t(&rt_sf->uc.uc_sigmask, oldset, failed);
+
user_write_access_end();
- if (put_sigset_t(&rt_sf->uc.uc_sigmask, oldset))
- goto badframe;
if (copy_siginfo_to_user(&rt_sf->info, &ksig->info))
goto badframe;
--
2.25.0
Powered by blists - more mailing lists