kcm: Splice support

Implement kcm_splice_read. This is supported only for seqpacket.
Add kcm_seqpacket_ops and set splice read to kcm_splice_read.

Signed-off-by: Tom Herbert <tom@herbertland.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Tom Herbert 2016-03-07 14:11:08 -08:00 committed by David S. Miller
parent cd6e111bf5
commit 91687355b9
1 changed files with 96 additions and 2 deletions

View File

@ -1256,6 +1256,76 @@ out:
return copied ? : err;
}
static ssize_t kcm_sock_splice(struct sock *sk,
struct pipe_inode_info *pipe,
struct splice_pipe_desc *spd)
{
int ret;
release_sock(sk);
ret = splice_to_pipe(pipe, spd);
lock_sock(sk);
return ret;
}
static ssize_t kcm_splice_read(struct socket *sock, loff_t *ppos,
struct pipe_inode_info *pipe, size_t len,
unsigned int flags)
{
struct sock *sk = sock->sk;
struct kcm_sock *kcm = kcm_sk(sk);
long timeo;
struct kcm_rx_msg *rxm;
int err = 0;
size_t copied;
struct sk_buff *skb;
/* Only support splice for SOCKSEQPACKET */
timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
lock_sock(sk);
skb = kcm_wait_data(sk, flags, timeo, &err);
if (!skb)
goto err_out;
/* Okay, have a message on the receive queue */
rxm = kcm_rx_msg(skb);
if (len > rxm->full_len)
len = rxm->full_len;
copied = skb_splice_bits(skb, sk, rxm->offset, pipe, len, flags,
kcm_sock_splice);
if (copied < 0) {
err = copied;
goto err_out;
}
KCM_STATS_ADD(kcm->stats.rx_bytes, copied);
rxm->offset += copied;
rxm->full_len -= copied;
/* We have no way to return MSG_EOR. If all the bytes have been
* read we still leave the message in the receive socket buffer.
* A subsequent recvmsg needs to be done to return MSG_EOR and
* finish reading the message.
*/
release_sock(sk);
return copied;
err_out:
release_sock(sk);
return err;
}
/* kcm sock lock held */
static void kcm_recv_disable(struct kcm_sock *kcm)
{
@ -1907,7 +1977,7 @@ static int kcm_release(struct socket *sock)
return 0;
}
static const struct proto_ops kcm_ops = {
static const struct proto_ops kcm_dgram_ops = {
.family = PF_KCM,
.owner = THIS_MODULE,
.release = kcm_release,
@ -1928,6 +1998,28 @@ static const struct proto_ops kcm_ops = {
.sendpage = sock_no_sendpage,
};
static const struct proto_ops kcm_seqpacket_ops = {
.family = PF_KCM,
.owner = THIS_MODULE,
.release = kcm_release,
.bind = sock_no_bind,
.connect = sock_no_connect,
.socketpair = sock_no_socketpair,
.accept = sock_no_accept,
.getname = sock_no_getname,
.poll = datagram_poll,
.ioctl = kcm_ioctl,
.listen = sock_no_listen,
.shutdown = sock_no_shutdown,
.setsockopt = kcm_setsockopt,
.getsockopt = kcm_getsockopt,
.sendmsg = kcm_sendmsg,
.recvmsg = kcm_recvmsg,
.mmap = sock_no_mmap,
.sendpage = sock_no_sendpage,
.splice_read = kcm_splice_read,
};
/* Create proto operation for kcm sockets */
static int kcm_create(struct net *net, struct socket *sock,
int protocol, int kern)
@ -1938,8 +2030,10 @@ static int kcm_create(struct net *net, struct socket *sock,
switch (sock->type) {
case SOCK_DGRAM:
sock->ops = &kcm_dgram_ops;
break;
case SOCK_SEQPACKET:
sock->ops = &kcm_ops;
sock->ops = &kcm_seqpacket_ops;
break;
default:
return -ESOCKTNOSUPPORT;