Commit 38ebcf50 authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller
Browse files

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: default avatarEric Dumazet <edumazet@google.com>
Cc: Soheil Hassas Yeganeh <soheil@google.com>
Acked-by: default avatarSoheil Hassas Yeganeh <soheil@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b6faf160
Loading
Loading
Loading
Loading
+15 −8
Original line number Diff line number Diff line
@@ -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);