proto_ops: Add locked held versions of sendmsg and sendpage
Add new proto_ops sendmsg_locked and sendpage_locked that can be called when the socket lock is already held. Correspondingly, add kernel_sendmsg_locked and kernel_sendpage_locked as front end functions. These functions will be used in zero proxy so that we can take the socket lock in a ULP sendmsg/sendpage and then directly call the backend transport proto_ops functions. Signed-off-by: Tom Herbert <tom@quantonium.net> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
29fda25a2d
commit
306b13eb3c
|
@ -190,8 +190,16 @@ struct proto_ops {
|
||||||
struct pipe_inode_info *pipe, size_t len, unsigned int flags);
|
struct pipe_inode_info *pipe, size_t len, unsigned int flags);
|
||||||
int (*set_peek_off)(struct sock *sk, int val);
|
int (*set_peek_off)(struct sock *sk, int val);
|
||||||
int (*peek_len)(struct socket *sock);
|
int (*peek_len)(struct socket *sock);
|
||||||
|
|
||||||
|
/* The following functions are called internally by kernel with
|
||||||
|
* sock lock already held.
|
||||||
|
*/
|
||||||
int (*read_sock)(struct sock *sk, read_descriptor_t *desc,
|
int (*read_sock)(struct sock *sk, read_descriptor_t *desc,
|
||||||
sk_read_actor_t recv_actor);
|
sk_read_actor_t recv_actor);
|
||||||
|
int (*sendpage_locked)(struct sock *sk, struct page *page,
|
||||||
|
int offset, size_t size, int flags);
|
||||||
|
int (*sendmsg_locked)(struct sock *sk, struct msghdr *msg,
|
||||||
|
size_t size);
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DECLARE_SOCKADDR(type, dst, src) \
|
#define DECLARE_SOCKADDR(type, dst, src) \
|
||||||
|
@ -279,6 +287,8 @@ do { \
|
||||||
|
|
||||||
int kernel_sendmsg(struct socket *sock, struct msghdr *msg, struct kvec *vec,
|
int kernel_sendmsg(struct socket *sock, struct msghdr *msg, struct kvec *vec,
|
||||||
size_t num, size_t len);
|
size_t num, size_t len);
|
||||||
|
int kernel_sendmsg_locked(struct sock *sk, struct msghdr *msg,
|
||||||
|
struct kvec *vec, size_t num, size_t len);
|
||||||
int kernel_recvmsg(struct socket *sock, struct msghdr *msg, struct kvec *vec,
|
int kernel_recvmsg(struct socket *sock, struct msghdr *msg, struct kvec *vec,
|
||||||
size_t num, size_t len, int flags);
|
size_t num, size_t len, int flags);
|
||||||
|
|
||||||
|
@ -297,6 +307,8 @@ int kernel_setsockopt(struct socket *sock, int level, int optname, char *optval,
|
||||||
unsigned int optlen);
|
unsigned int optlen);
|
||||||
int kernel_sendpage(struct socket *sock, struct page *page, int offset,
|
int kernel_sendpage(struct socket *sock, struct page *page, int offset,
|
||||||
size_t size, int flags);
|
size_t size, int flags);
|
||||||
|
int kernel_sendpage_locked(struct sock *sk, struct page *page, int offset,
|
||||||
|
size_t size, int flags);
|
||||||
int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg);
|
int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg);
|
||||||
int kernel_sock_shutdown(struct socket *sock, enum sock_shutdown_cmd how);
|
int kernel_sock_shutdown(struct socket *sock, enum sock_shutdown_cmd how);
|
||||||
|
|
||||||
|
|
|
@ -1582,11 +1582,14 @@ int sock_no_shutdown(struct socket *, int);
|
||||||
int sock_no_getsockopt(struct socket *, int , int, char __user *, int __user *);
|
int sock_no_getsockopt(struct socket *, int , int, char __user *, int __user *);
|
||||||
int sock_no_setsockopt(struct socket *, int, int, char __user *, unsigned int);
|
int sock_no_setsockopt(struct socket *, int, int, char __user *, unsigned int);
|
||||||
int sock_no_sendmsg(struct socket *, struct msghdr *, size_t);
|
int sock_no_sendmsg(struct socket *, struct msghdr *, size_t);
|
||||||
|
int sock_no_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t len);
|
||||||
int sock_no_recvmsg(struct socket *, struct msghdr *, size_t, int);
|
int sock_no_recvmsg(struct socket *, struct msghdr *, size_t, int);
|
||||||
int sock_no_mmap(struct file *file, struct socket *sock,
|
int sock_no_mmap(struct file *file, struct socket *sock,
|
||||||
struct vm_area_struct *vma);
|
struct vm_area_struct *vma);
|
||||||
ssize_t sock_no_sendpage(struct socket *sock, struct page *page, int offset,
|
ssize_t sock_no_sendpage(struct socket *sock, struct page *page, int offset,
|
||||||
size_t size, int flags);
|
size_t size, int flags);
|
||||||
|
ssize_t sock_no_sendpage_locked(struct sock *sk, struct page *page,
|
||||||
|
int offset, size_t size, int flags);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Functions to fill in entries in struct proto_ops when a protocol
|
* Functions to fill in entries in struct proto_ops when a protocol
|
||||||
|
|
|
@ -350,8 +350,11 @@ int tcp_v4_rcv(struct sk_buff *skb);
|
||||||
|
|
||||||
int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw);
|
int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw);
|
||||||
int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size);
|
int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size);
|
||||||
|
int tcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t size);
|
||||||
int tcp_sendpage(struct sock *sk, struct page *page, int offset, size_t size,
|
int tcp_sendpage(struct sock *sk, struct page *page, int offset, size_t size,
|
||||||
int flags);
|
int flags);
|
||||||
|
int tcp_sendpage_locked(struct sock *sk, struct page *page, int offset,
|
||||||
|
size_t size, int flags);
|
||||||
ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset,
|
ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset,
|
||||||
size_t size, int flags);
|
size_t size, int flags);
|
||||||
void tcp_release_cb(struct sock *sk);
|
void tcp_release_cb(struct sock *sk);
|
||||||
|
|
|
@ -2500,6 +2500,12 @@ int sock_no_sendmsg(struct socket *sock, struct msghdr *m, size_t len)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(sock_no_sendmsg);
|
EXPORT_SYMBOL(sock_no_sendmsg);
|
||||||
|
|
||||||
|
int sock_no_sendmsg_locked(struct sock *sk, struct msghdr *m, size_t len)
|
||||||
|
{
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(sock_no_sendmsg_locked);
|
||||||
|
|
||||||
int sock_no_recvmsg(struct socket *sock, struct msghdr *m, size_t len,
|
int sock_no_recvmsg(struct socket *sock, struct msghdr *m, size_t len,
|
||||||
int flags)
|
int flags)
|
||||||
{
|
{
|
||||||
|
@ -2528,6 +2534,22 @@ ssize_t sock_no_sendpage(struct socket *sock, struct page *page, int offset, siz
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(sock_no_sendpage);
|
EXPORT_SYMBOL(sock_no_sendpage);
|
||||||
|
|
||||||
|
ssize_t sock_no_sendpage_locked(struct sock *sk, struct page *page,
|
||||||
|
int offset, size_t size, int flags)
|
||||||
|
{
|
||||||
|
ssize_t res;
|
||||||
|
struct msghdr msg = {.msg_flags = flags};
|
||||||
|
struct kvec iov;
|
||||||
|
char *kaddr = kmap(page);
|
||||||
|
|
||||||
|
iov.iov_base = kaddr + offset;
|
||||||
|
iov.iov_len = size;
|
||||||
|
res = kernel_sendmsg_locked(sk, &msg, &iov, 1, size);
|
||||||
|
kunmap(page);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(sock_no_sendpage_locked);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Default Socket Callbacks
|
* Default Socket Callbacks
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -944,6 +944,8 @@ const struct proto_ops inet_stream_ops = {
|
||||||
.sendpage = inet_sendpage,
|
.sendpage = inet_sendpage,
|
||||||
.splice_read = tcp_splice_read,
|
.splice_read = tcp_splice_read,
|
||||||
.read_sock = tcp_read_sock,
|
.read_sock = tcp_read_sock,
|
||||||
|
.sendmsg_locked = tcp_sendmsg_locked,
|
||||||
|
.sendpage_locked = tcp_sendpage_locked,
|
||||||
.peek_len = tcp_peek_len,
|
.peek_len = tcp_peek_len,
|
||||||
#ifdef CONFIG_COMPAT
|
#ifdef CONFIG_COMPAT
|
||||||
.compat_setsockopt = compat_sock_common_setsockopt,
|
.compat_setsockopt = compat_sock_common_setsockopt,
|
||||||
|
|
|
@ -1046,23 +1046,29 @@ out_err:
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(do_tcp_sendpages);
|
EXPORT_SYMBOL_GPL(do_tcp_sendpages);
|
||||||
|
|
||||||
int tcp_sendpage(struct sock *sk, struct page *page, int offset,
|
int tcp_sendpage_locked(struct sock *sk, struct page *page, int offset,
|
||||||
size_t size, int flags)
|
size_t size, int flags)
|
||||||
{
|
{
|
||||||
ssize_t res;
|
|
||||||
|
|
||||||
if (!(sk->sk_route_caps & NETIF_F_SG) ||
|
if (!(sk->sk_route_caps & NETIF_F_SG) ||
|
||||||
!sk_check_csum_caps(sk))
|
!sk_check_csum_caps(sk))
|
||||||
return sock_no_sendpage(sk->sk_socket, page, offset, size,
|
return sock_no_sendpage(sk->sk_socket, page, offset, size,
|
||||||
flags);
|
flags);
|
||||||
|
|
||||||
lock_sock(sk);
|
|
||||||
|
|
||||||
tcp_rate_check_app_limited(sk); /* is sending application-limited? */
|
tcp_rate_check_app_limited(sk); /* is sending application-limited? */
|
||||||
|
|
||||||
res = do_tcp_sendpages(sk, page, offset, size, flags);
|
return do_tcp_sendpages(sk, page, offset, size, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
int tcp_sendpage(struct sock *sk, struct page *page, int offset,
|
||||||
|
size_t size, int flags)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
lock_sock(sk);
|
||||||
|
ret = tcp_sendpage_locked(sk, page, offset, size, flags);
|
||||||
release_sock(sk);
|
release_sock(sk);
|
||||||
return res;
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(tcp_sendpage);
|
EXPORT_SYMBOL(tcp_sendpage);
|
||||||
|
|
||||||
|
@ -1156,7 +1162,7 @@ static int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg,
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
|
int tcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t size)
|
||||||
{
|
{
|
||||||
struct tcp_sock *tp = tcp_sk(sk);
|
struct tcp_sock *tp = tcp_sk(sk);
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
|
@ -1167,8 +1173,6 @@ int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
|
||||||
bool sg;
|
bool sg;
|
||||||
long timeo;
|
long timeo;
|
||||||
|
|
||||||
lock_sock(sk);
|
|
||||||
|
|
||||||
flags = msg->msg_flags;
|
flags = msg->msg_flags;
|
||||||
if (unlikely(flags & MSG_FASTOPEN || inet_sk(sk)->defer_connect)) {
|
if (unlikely(flags & MSG_FASTOPEN || inet_sk(sk)->defer_connect)) {
|
||||||
err = tcp_sendmsg_fastopen(sk, msg, &copied_syn, size);
|
err = tcp_sendmsg_fastopen(sk, msg, &copied_syn, size);
|
||||||
|
@ -1377,7 +1381,6 @@ out:
|
||||||
tcp_push(sk, flags, mss_now, tp->nonagle, size_goal);
|
tcp_push(sk, flags, mss_now, tp->nonagle, size_goal);
|
||||||
}
|
}
|
||||||
out_nopush:
|
out_nopush:
|
||||||
release_sock(sk);
|
|
||||||
return copied + copied_syn;
|
return copied + copied_syn;
|
||||||
|
|
||||||
do_fault:
|
do_fault:
|
||||||
|
@ -1401,9 +1404,19 @@ out_err:
|
||||||
sk->sk_write_space(sk);
|
sk->sk_write_space(sk);
|
||||||
tcp_chrono_stop(sk, TCP_CHRONO_SNDBUF_LIMITED);
|
tcp_chrono_stop(sk, TCP_CHRONO_SNDBUF_LIMITED);
|
||||||
}
|
}
|
||||||
release_sock(sk);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
lock_sock(sk);
|
||||||
|
ret = tcp_sendmsg_locked(sk, msg, size);
|
||||||
|
release_sock(sk);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
EXPORT_SYMBOL(tcp_sendmsg);
|
EXPORT_SYMBOL(tcp_sendmsg);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
27
net/socket.c
27
net/socket.c
|
@ -652,6 +652,20 @@ int kernel_sendmsg(struct socket *sock, struct msghdr *msg,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(kernel_sendmsg);
|
EXPORT_SYMBOL(kernel_sendmsg);
|
||||||
|
|
||||||
|
int kernel_sendmsg_locked(struct sock *sk, struct msghdr *msg,
|
||||||
|
struct kvec *vec, size_t num, size_t size)
|
||||||
|
{
|
||||||
|
struct socket *sock = sk->sk_socket;
|
||||||
|
|
||||||
|
if (!sock->ops->sendmsg_locked)
|
||||||
|
sock_no_sendmsg_locked(sk, msg, size);
|
||||||
|
|
||||||
|
iov_iter_kvec(&msg->msg_iter, WRITE | ITER_KVEC, vec, num, size);
|
||||||
|
|
||||||
|
return sock->ops->sendmsg_locked(sk, msg, msg_data_left(msg));
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(kernel_sendmsg_locked);
|
||||||
|
|
||||||
static bool skb_is_err_queue(const struct sk_buff *skb)
|
static bool skb_is_err_queue(const struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
/* pkt_type of skbs enqueued on the error queue are set to
|
/* pkt_type of skbs enqueued on the error queue are set to
|
||||||
|
@ -3376,6 +3390,19 @@ int kernel_sendpage(struct socket *sock, struct page *page, int offset,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(kernel_sendpage);
|
EXPORT_SYMBOL(kernel_sendpage);
|
||||||
|
|
||||||
|
int kernel_sendpage_locked(struct sock *sk, struct page *page, int offset,
|
||||||
|
size_t size, int flags)
|
||||||
|
{
|
||||||
|
struct socket *sock = sk->sk_socket;
|
||||||
|
|
||||||
|
if (sock->ops->sendpage_locked)
|
||||||
|
return sock->ops->sendpage_locked(sk, page, offset, size,
|
||||||
|
flags);
|
||||||
|
|
||||||
|
return sock_no_sendpage_locked(sk, page, offset, size, flags);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(kernel_sendpage_locked);
|
||||||
|
|
||||||
int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg)
|
int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg)
|
||||||
{
|
{
|
||||||
mm_segment_t oldfs = get_fs();
|
mm_segment_t oldfs = get_fs();
|
||||||
|
|
Loading…
Reference in New Issue