aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/scm.c
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2021-04-15 10:37:53 -0700
committerDavid S. Miller <davem@davemloft.net>2021-04-15 17:03:33 -0700
commit38ebcf5096a86762b82262e96b2c8b170fe79040 (patch)
treee374d75ffd37f3053bf687938f8596aea6988f69 /net/core/scm.c
parentenetc: convert to schedule_work() (diff)
downloadlinux-dev-38ebcf5096a86762b82262e96b2c8b170fe79040.tar.xz
linux-dev-38ebcf5096a86762b82262e96b2c8b170fe79040.zip
scm: optimize put_cmsg()
Calling two copy_to_user() for very small regions has very high overhead. Switch to inlined unsafe_put_user() to save one stac/clac sequence, and avoid copy_to_user(). Signed-off-by: Eric Dumazet <edumazet@google.com> Cc: Soheil Hassas Yeganeh <soheil@google.com> Acked-by: Soheil Hassas Yeganeh <soheil@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core/scm.c')
-rw-r--r--net/core/scm.c23
1 files changed, 15 insertions, 8 deletions
diff --git a/net/core/scm.c b/net/core/scm.c
index 8156d4fb8a39..bd96c922041d 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -228,14 +228,16 @@ int put_cmsg(struct msghdr * msg, int level, int type, int len, void *data)
if (msg->msg_control_is_user) {
struct cmsghdr __user *cm = msg->msg_control_user;
- struct cmsghdr cmhdr;
-
- cmhdr.cmsg_level = level;
- cmhdr.cmsg_type = type;
- cmhdr.cmsg_len = cmlen;
- if (copy_to_user(cm, &cmhdr, sizeof cmhdr) ||
- copy_to_user(CMSG_USER_DATA(cm), data, cmlen - sizeof(*cm)))
- return -EFAULT;
+
+ if (!user_write_access_begin(cm, cmlen))
+ goto efault;
+
+ unsafe_put_user(len, &cm->cmsg_len, efault_end);
+ unsafe_put_user(level, &cm->cmsg_level, efault_end);
+ unsafe_put_user(type, &cm->cmsg_type, efault_end);
+ unsafe_copy_to_user(CMSG_USER_DATA(cm), data,
+ cmlen - sizeof(*cm), efault_end);
+ user_write_access_end();
} else {
struct cmsghdr *cm = msg->msg_control;
@@ -249,6 +251,11 @@ int put_cmsg(struct msghdr * msg, int level, int type, int len, void *data)
msg->msg_control += cmlen;
msg->msg_controllen -= cmlen;
return 0;
+
+efault_end:
+ user_write_access_end();
+efault:
+ return -EFAULT;
}
EXPORT_SYMBOL(put_cmsg);