aboutsummaryrefslogtreecommitdiff
path: root/net/rds/recv.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/rds/recv.c')
-rw-r--r--net/rds/recv.c23
1 files changed, 16 insertions, 7 deletions
diff --git a/net/rds/recv.c b/net/rds/recv.c
index d50747725221..de50e2126e40 100644
--- a/net/rds/recv.c
+++ b/net/rds/recv.c
@@ -579,9 +579,10 @@ out:
static bool rds_recvmsg_zcookie(struct rds_sock *rs, struct msghdr *msg)
{
- struct sk_buff *skb;
- struct sk_buff_head *q = &rs->rs_zcookie_queue;
+ struct rds_msg_zcopy_queue *q = &rs->rs_zcookie_queue;
+ struct rds_msg_zcopy_info *info = NULL;
struct rds_zcopy_cookies *done;
+ unsigned long flags;
if (!msg->msg_control)
return false;
@@ -590,16 +591,24 @@ static bool rds_recvmsg_zcookie(struct rds_sock *rs, struct msghdr *msg)
msg->msg_controllen < CMSG_SPACE(sizeof(*done)))
return false;
- skb = skb_dequeue(q);
- if (!skb)
+ spin_lock_irqsave(&q->lock, flags);
+ if (!list_empty(&q->zcookie_head)) {
+ info = list_entry(q->zcookie_head.next,
+ struct rds_msg_zcopy_info, rs_zcookie_next);
+ list_del(&info->rs_zcookie_next);
+ }
+ spin_unlock_irqrestore(&q->lock, flags);
+ if (!info)
return false;
- done = (struct rds_zcopy_cookies *)skb->cb;
+ done = &info->zcookies;
if (put_cmsg(msg, SOL_RDS, RDS_CMSG_ZCOPY_COMPLETION, sizeof(*done),
done)) {
- skb_queue_head(q, skb);
+ spin_lock_irqsave(&q->lock, flags);
+ list_add(&info->rs_zcookie_next, &q->zcookie_head);
+ spin_unlock_irqrestore(&q->lock, flags);
return false;
}
- consume_skb(skb);
+ kfree(info);
return true;
}