Commit f55bb7f9 authored by Pavel Emelyanov's avatar Pavel Emelyanov Committed by David S. Miller

unix: Support peeking offset for datagram and seqpacket sockets

The sk_peek_off manipulations are protected with the unix_sk->readlock mutex.
This mutex is enough since all we need is to syncronize setting the offset
vs reading the queue head. The latter is fully covered with the mentioned lock.

The recently added __skb_recv_datagram's offset is used to pick the skb to
read the data from.
Signed-off-by: default avatarPavel Emelyanov <xemul@parallels.com>
Acked-by: default avatarEric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ef64a54f
...@@ -530,6 +530,16 @@ static int unix_seqpacket_sendmsg(struct kiocb *, struct socket *, ...@@ -530,6 +530,16 @@ static int unix_seqpacket_sendmsg(struct kiocb *, struct socket *,
static int unix_seqpacket_recvmsg(struct kiocb *, struct socket *, static int unix_seqpacket_recvmsg(struct kiocb *, struct socket *,
struct msghdr *, size_t, int); struct msghdr *, size_t, int);
static void unix_set_peek_off(struct sock *sk, int val)
{
struct unix_sock *u = unix_sk(sk);
mutex_lock(&u->readlock);
sk->sk_peek_off = val;
mutex_unlock(&u->readlock);
}
static const struct proto_ops unix_stream_ops = { static const struct proto_ops unix_stream_ops = {
.family = PF_UNIX, .family = PF_UNIX,
.owner = THIS_MODULE, .owner = THIS_MODULE,
...@@ -570,6 +580,7 @@ static const struct proto_ops unix_dgram_ops = { ...@@ -570,6 +580,7 @@ static const struct proto_ops unix_dgram_ops = {
.recvmsg = unix_dgram_recvmsg, .recvmsg = unix_dgram_recvmsg,
.mmap = sock_no_mmap, .mmap = sock_no_mmap,
.sendpage = sock_no_sendpage, .sendpage = sock_no_sendpage,
.set_peek_off = unix_set_peek_off,
}; };
static const struct proto_ops unix_seqpacket_ops = { static const struct proto_ops unix_seqpacket_ops = {
...@@ -591,6 +602,7 @@ static const struct proto_ops unix_seqpacket_ops = { ...@@ -591,6 +602,7 @@ static const struct proto_ops unix_seqpacket_ops = {
.recvmsg = unix_seqpacket_recvmsg, .recvmsg = unix_seqpacket_recvmsg,
.mmap = sock_no_mmap, .mmap = sock_no_mmap,
.sendpage = sock_no_sendpage, .sendpage = sock_no_sendpage,
.set_peek_off = unix_set_peek_off,
}; };
static struct proto unix_proto = { static struct proto unix_proto = {
...@@ -1756,6 +1768,7 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock, ...@@ -1756,6 +1768,7 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
int noblock = flags & MSG_DONTWAIT; int noblock = flags & MSG_DONTWAIT;
struct sk_buff *skb; struct sk_buff *skb;
int err; int err;
int peeked, skip;
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
if (flags&MSG_OOB) if (flags&MSG_OOB)
...@@ -1769,7 +1782,9 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock, ...@@ -1769,7 +1782,9 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
goto out; goto out;
} }
skb = skb_recv_datagram(sk, flags, noblock, &err); skip = sk_peek_offset(sk, flags);
skb = __skb_recv_datagram(sk, flags, &peeked, &skip, &err);
if (!skb) { if (!skb) {
unix_state_lock(sk); unix_state_lock(sk);
/* Signal EOF on disconnected non-blocking SEQPACKET socket. */ /* Signal EOF on disconnected non-blocking SEQPACKET socket. */
...@@ -1786,12 +1801,12 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock, ...@@ -1786,12 +1801,12 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
if (msg->msg_name) if (msg->msg_name)
unix_copy_addr(msg, skb->sk); unix_copy_addr(msg, skb->sk);
if (size > skb->len) if (size > skb->len - skip)
size = skb->len; size = skb->len - skip;
else if (size < skb->len) else if (size < skb->len - skip)
msg->msg_flags |= MSG_TRUNC; msg->msg_flags |= MSG_TRUNC;
err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, size); err = skb_copy_datagram_iovec(skb, skip, msg->msg_iov, size);
if (err) if (err)
goto out_free; goto out_free;
...@@ -1808,6 +1823,8 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock, ...@@ -1808,6 +1823,8 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
if (!(flags & MSG_PEEK)) { if (!(flags & MSG_PEEK)) {
if (UNIXCB(skb).fp) if (UNIXCB(skb).fp)
unix_detach_fds(siocb->scm, skb); unix_detach_fds(siocb->scm, skb);
sk_peek_offset_bwd(sk, skb->len);
} else { } else {
/* It is questionable: on PEEK we could: /* It is questionable: on PEEK we could:
- do not return fds - good, but too simple 8) - do not return fds - good, but too simple 8)
...@@ -1821,6 +1838,9 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock, ...@@ -1821,6 +1838,9 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
clearly however! clearly however!
*/ */
sk_peek_offset_fwd(sk, size);
if (UNIXCB(skb).fp) if (UNIXCB(skb).fp)
siocb->scm->fp = scm_fp_dup(UNIXCB(skb).fp); siocb->scm->fp = scm_fp_dup(UNIXCB(skb).fp);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment