tipc: Allow receiving into iovec containing multiple entries

Enhances TIPC's socket receive routines to support iovec structures
containing more than a single entry. This change leverages existing
sk_buff routines to do most of the work; the only significant change
to TIPC itself is that an sk_buff now records how much data has been
already consumed as an numeric offset, rather than as a pointer to
the first unread data byte.

Signed-off-by: Allan Stephens <Allan.Stephens@windriver.com>
Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
This commit is contained in:
Allan Stephens 2011-02-21 09:45:40 -05:00 коммит произвёл Paul Gortmaker
Родитель bef55aebd5
Коммит 0232fd0ac4
1 изменённых файлов: 15 добавлений и 23 удалений

Просмотреть файл

@ -289,7 +289,7 @@ static int release(struct socket *sock)
if (buf == NULL) if (buf == NULL)
break; break;
atomic_dec(&tipc_queue_size); atomic_dec(&tipc_queue_size);
if (TIPC_SKB_CB(buf)->handle != msg_data(buf_msg(buf))) if (TIPC_SKB_CB(buf)->handle != 0)
buf_discard(buf); buf_discard(buf);
else { else {
if ((sock->state == SS_CONNECTING) || if ((sock->state == SS_CONNECTING) ||
@ -917,9 +917,6 @@ static int recv_msg(struct kiocb *iocb, struct socket *sock,
/* Catch invalid receive requests */ /* Catch invalid receive requests */
if (m->msg_iovlen != 1)
return -EOPNOTSUPP; /* Don't do multiple iovec entries yet */
if (unlikely(!buf_len)) if (unlikely(!buf_len))
return -EINVAL; return -EINVAL;
@ -991,11 +988,10 @@ restart:
sz = buf_len; sz = buf_len;
m->msg_flags |= MSG_TRUNC; m->msg_flags |= MSG_TRUNC;
} }
if (unlikely(copy_to_user(m->msg_iov->iov_base, msg_data(msg), res = skb_copy_datagram_iovec(buf, msg_hdr_sz(msg),
sz))) { m->msg_iov, sz);
res = -EFAULT; if (res)
goto exit; goto exit;
}
res = sz; res = sz;
} else { } else {
if ((sock->state == SS_READY) || if ((sock->state == SS_READY) ||
@ -1041,16 +1037,11 @@ static int recv_stream(struct kiocb *iocb, struct socket *sock,
unsigned int sz; unsigned int sz;
int sz_to_copy, target, needed; int sz_to_copy, target, needed;
int sz_copied = 0; int sz_copied = 0;
char __user *crs = m->msg_iov->iov_base;
unsigned char *buf_crs;
u32 err; u32 err;
int res = 0; int res = 0;
/* Catch invalid receive attempts */ /* Catch invalid receive attempts */
if (m->msg_iovlen != 1)
return -EOPNOTSUPP; /* Don't do multiple iovec entries yet */
if (unlikely(!buf_len)) if (unlikely(!buf_len))
return -EINVAL; return -EINVAL;
@ -1112,24 +1103,25 @@ restart:
/* Capture message data (if valid) & compute return value (always) */ /* Capture message data (if valid) & compute return value (always) */
if (!err) { if (!err) {
buf_crs = (unsigned char *)(TIPC_SKB_CB(buf)->handle); u32 offset = (u32)(unsigned long)(TIPC_SKB_CB(buf)->handle);
sz = (unsigned char *)msg + msg_size(msg) - buf_crs;
sz -= offset;
needed = (buf_len - sz_copied); needed = (buf_len - sz_copied);
sz_to_copy = (sz <= needed) ? sz : needed; sz_to_copy = (sz <= needed) ? sz : needed;
if (unlikely(copy_to_user(crs, buf_crs, sz_to_copy))) {
res = -EFAULT; res = skb_copy_datagram_iovec(buf, msg_hdr_sz(msg) + offset,
m->msg_iov, sz_to_copy);
if (res)
goto exit; goto exit;
}
sz_copied += sz_to_copy; sz_copied += sz_to_copy;
if (sz_to_copy < sz) { if (sz_to_copy < sz) {
if (!(flags & MSG_PEEK)) if (!(flags & MSG_PEEK))
TIPC_SKB_CB(buf)->handle = buf_crs + sz_to_copy; TIPC_SKB_CB(buf)->handle =
(void *)(unsigned long)(offset + sz_to_copy);
goto exit; goto exit;
} }
crs += sz_to_copy;
} else { } else {
if (sz_copied != 0) if (sz_copied != 0)
goto exit; /* can't add error msg to valid data */ goto exit; /* can't add error msg to valid data */
@ -1256,7 +1248,7 @@ static u32 filter_rcv(struct sock *sk, struct sk_buff *buf)
/* Enqueue message (finally!) */ /* Enqueue message (finally!) */
TIPC_SKB_CB(buf)->handle = msg_data(msg); TIPC_SKB_CB(buf)->handle = 0;
atomic_inc(&tipc_queue_size); atomic_inc(&tipc_queue_size);
__skb_queue_tail(&sk->sk_receive_queue, buf); __skb_queue_tail(&sk->sk_receive_queue, buf);
@ -1608,7 +1600,7 @@ restart:
buf = __skb_dequeue(&sk->sk_receive_queue); buf = __skb_dequeue(&sk->sk_receive_queue);
if (buf) { if (buf) {
atomic_dec(&tipc_queue_size); atomic_dec(&tipc_queue_size);
if (TIPC_SKB_CB(buf)->handle != msg_data(buf_msg(buf))) { if (TIPC_SKB_CB(buf)->handle != 0) {
buf_discard(buf); buf_discard(buf);
goto restart; goto restart;
} }