|
@@ -48,7 +48,6 @@ static unsigned int rds_exthdr_size[__RDS_EXTHDR_MAX] = {
|
|
|
[RDS_EXTHDR_GEN_NUM] = sizeof(u32),
|
|
|
};
|
|
|
|
|
|
-
|
|
|
void rds_message_addref(struct rds_message *rm)
|
|
|
{
|
|
|
rdsdebug("addref rm %p ref %d\n", rm, refcount_read(&rm->m_refcount));
|
|
@@ -56,9 +55,9 @@ void rds_message_addref(struct rds_message *rm)
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(rds_message_addref);
|
|
|
|
|
|
-static inline bool skb_zcookie_add(struct sk_buff *skb, u32 cookie)
|
|
|
+static inline bool rds_zcookie_add(struct rds_msg_zcopy_info *info, u32 cookie)
|
|
|
{
|
|
|
- struct rds_zcopy_cookies *ck = (struct rds_zcopy_cookies *)skb->cb;
|
|
|
+ struct rds_zcopy_cookies *ck = &info->zcookies;
|
|
|
int ncookies = ck->num;
|
|
|
|
|
|
if (ncookies == RDS_MAX_ZCOOKIES)
|
|
@@ -68,38 +67,61 @@ static inline bool skb_zcookie_add(struct sk_buff *skb, u32 cookie)
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+struct rds_msg_zcopy_info *rds_info_from_znotifier(struct rds_znotifier *znotif)
|
|
|
+{
|
|
|
+ return container_of(znotif, struct rds_msg_zcopy_info, znotif);
|
|
|
+}
|
|
|
+
|
|
|
+void rds_notify_msg_zcopy_purge(struct rds_msg_zcopy_queue *q)
|
|
|
+{
|
|
|
+ unsigned long flags;
|
|
|
+ LIST_HEAD(copy);
|
|
|
+ struct rds_msg_zcopy_info *info, *tmp;
|
|
|
+
|
|
|
+ spin_lock_irqsave(&q->lock, flags);
|
|
|
+ list_splice(&q->zcookie_head, ©);
|
|
|
+ INIT_LIST_HEAD(&q->zcookie_head);
|
|
|
+ spin_unlock_irqrestore(&q->lock, flags);
|
|
|
+
|
|
|
+ list_for_each_entry_safe(info, tmp, ©, rs_zcookie_next) {
|
|
|
+ list_del(&info->rs_zcookie_next);
|
|
|
+ kfree(info);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static void rds_rm_zerocopy_callback(struct rds_sock *rs,
|
|
|
struct rds_znotifier *znotif)
|
|
|
{
|
|
|
- struct sk_buff *skb, *tail;
|
|
|
- unsigned long flags;
|
|
|
- struct sk_buff_head *q;
|
|
|
+ struct rds_msg_zcopy_info *info;
|
|
|
+ struct rds_msg_zcopy_queue *q;
|
|
|
u32 cookie = znotif->z_cookie;
|
|
|
struct rds_zcopy_cookies *ck;
|
|
|
+ struct list_head *head;
|
|
|
+ unsigned long flags;
|
|
|
|
|
|
+ mm_unaccount_pinned_pages(&znotif->z_mmp);
|
|
|
q = &rs->rs_zcookie_queue;
|
|
|
spin_lock_irqsave(&q->lock, flags);
|
|
|
- tail = skb_peek_tail(q);
|
|
|
-
|
|
|
- if (tail && skb_zcookie_add(tail, cookie)) {
|
|
|
- spin_unlock_irqrestore(&q->lock, flags);
|
|
|
- mm_unaccount_pinned_pages(&znotif->z_mmp);
|
|
|
- consume_skb(rds_skb_from_znotifier(znotif));
|
|
|
- /* caller invokes rds_wake_sk_sleep() */
|
|
|
- return;
|
|
|
+ head = &q->zcookie_head;
|
|
|
+ if (!list_empty(head)) {
|
|
|
+ info = list_entry(head, struct rds_msg_zcopy_info,
|
|
|
+ rs_zcookie_next);
|
|
|
+ if (info && rds_zcookie_add(info, cookie)) {
|
|
|
+ spin_unlock_irqrestore(&q->lock, flags);
|
|
|
+ kfree(rds_info_from_znotifier(znotif));
|
|
|
+ /* caller invokes rds_wake_sk_sleep() */
|
|
|
+ return;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- skb = rds_skb_from_znotifier(znotif);
|
|
|
- ck = (struct rds_zcopy_cookies *)skb->cb;
|
|
|
+ info = rds_info_from_znotifier(znotif);
|
|
|
+ ck = &info->zcookies;
|
|
|
memset(ck, 0, sizeof(*ck));
|
|
|
- WARN_ON(!skb_zcookie_add(skb, cookie));
|
|
|
-
|
|
|
- __skb_queue_tail(q, skb);
|
|
|
+ WARN_ON(!rds_zcookie_add(info, cookie));
|
|
|
+ list_add_tail(&q->zcookie_head, &info->rs_zcookie_next);
|
|
|
|
|
|
spin_unlock_irqrestore(&q->lock, flags);
|
|
|
/* caller invokes rds_wake_sk_sleep() */
|
|
|
-
|
|
|
- mm_unaccount_pinned_pages(&znotif->z_mmp);
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -333,14 +355,14 @@ struct rds_message *rds_message_map_pages(unsigned long *page_addrs, unsigned in
|
|
|
return rm;
|
|
|
}
|
|
|
|
|
|
-int rds_message_copy_from_user(struct rds_message *rm, struct iov_iter *from,
|
|
|
- bool zcopy)
|
|
|
+int rds_message_zcopy_from_user(struct rds_message *rm, struct iov_iter *from)
|
|
|
{
|
|
|
- unsigned long to_copy, nbytes;
|
|
|
unsigned long sg_off;
|
|
|
struct scatterlist *sg;
|
|
|
int ret = 0;
|
|
|
int length = iov_iter_count(from);
|
|
|
+ int total_copied = 0;
|
|
|
+ struct rds_msg_zcopy_info *info;
|
|
|
|
|
|
rm->m_inc.i_hdr.h_len = cpu_to_be32(iov_iter_count(from));
|
|
|
|
|
@@ -350,54 +372,65 @@ int rds_message_copy_from_user(struct rds_message *rm, struct iov_iter *from,
|
|
|
sg = rm->data.op_sg;
|
|
|
sg_off = 0; /* Dear gcc, sg->page will be null from kzalloc. */
|
|
|
|
|
|
- if (zcopy) {
|
|
|
- int total_copied = 0;
|
|
|
- struct sk_buff *skb;
|
|
|
-
|
|
|
- skb = alloc_skb(0, GFP_KERNEL);
|
|
|
- if (!skb)
|
|
|
- return -ENOMEM;
|
|
|
- BUILD_BUG_ON(sizeof(skb->cb) <
|
|
|
- max_t(int, sizeof(struct rds_znotifier),
|
|
|
- sizeof(struct rds_zcopy_cookies)));
|
|
|
- rm->data.op_mmp_znotifier = RDS_ZCOPY_SKB(skb);
|
|
|
- if (mm_account_pinned_pages(&rm->data.op_mmp_znotifier->z_mmp,
|
|
|
- length)) {
|
|
|
- ret = -ENOMEM;
|
|
|
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
|
|
|
+ if (!info)
|
|
|
+ return -ENOMEM;
|
|
|
+ INIT_LIST_HEAD(&info->rs_zcookie_next);
|
|
|
+ rm->data.op_mmp_znotifier = &info->znotif;
|
|
|
+ if (mm_account_pinned_pages(&rm->data.op_mmp_znotifier->z_mmp,
|
|
|
+ length)) {
|
|
|
+ ret = -ENOMEM;
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+ while (iov_iter_count(from)) {
|
|
|
+ struct page *pages;
|
|
|
+ size_t start;
|
|
|
+ ssize_t copied;
|
|
|
+
|
|
|
+ copied = iov_iter_get_pages(from, &pages, PAGE_SIZE,
|
|
|
+ 1, &start);
|
|
|
+ if (copied < 0) {
|
|
|
+ struct mmpin *mmp;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < rm->data.op_nents; i++)
|
|
|
+ put_page(sg_page(&rm->data.op_sg[i]));
|
|
|
+ mmp = &rm->data.op_mmp_znotifier->z_mmp;
|
|
|
+ mm_unaccount_pinned_pages(mmp);
|
|
|
+ ret = -EFAULT;
|
|
|
goto err;
|
|
|
}
|
|
|
- while (iov_iter_count(from)) {
|
|
|
- struct page *pages;
|
|
|
- size_t start;
|
|
|
- ssize_t copied;
|
|
|
-
|
|
|
- copied = iov_iter_get_pages(from, &pages, PAGE_SIZE,
|
|
|
- 1, &start);
|
|
|
- if (copied < 0) {
|
|
|
- struct mmpin *mmp;
|
|
|
- int i;
|
|
|
-
|
|
|
- for (i = 0; i < rm->data.op_nents; i++)
|
|
|
- put_page(sg_page(&rm->data.op_sg[i]));
|
|
|
- mmp = &rm->data.op_mmp_znotifier->z_mmp;
|
|
|
- mm_unaccount_pinned_pages(mmp);
|
|
|
- ret = -EFAULT;
|
|
|
- goto err;
|
|
|
- }
|
|
|
- total_copied += copied;
|
|
|
- iov_iter_advance(from, copied);
|
|
|
- length -= copied;
|
|
|
- sg_set_page(sg, pages, copied, start);
|
|
|
- rm->data.op_nents++;
|
|
|
- sg++;
|
|
|
- }
|
|
|
- WARN_ON_ONCE(length != 0);
|
|
|
- return ret;
|
|
|
+ total_copied += copied;
|
|
|
+ iov_iter_advance(from, copied);
|
|
|
+ length -= copied;
|
|
|
+ sg_set_page(sg, pages, copied, start);
|
|
|
+ rm->data.op_nents++;
|
|
|
+ sg++;
|
|
|
+ }
|
|
|
+ WARN_ON_ONCE(length != 0);
|
|
|
+ return ret;
|
|
|
err:
|
|
|
- consume_skb(skb);
|
|
|
- rm->data.op_mmp_znotifier = NULL;
|
|
|
- return ret;
|
|
|
- } /* zcopy */
|
|
|
+ kfree(info);
|
|
|
+ rm->data.op_mmp_znotifier = NULL;
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+int rds_message_copy_from_user(struct rds_message *rm, struct iov_iter *from,
|
|
|
+ bool zcopy)
|
|
|
+{
|
|
|
+ unsigned long to_copy, nbytes;
|
|
|
+ unsigned long sg_off;
|
|
|
+ struct scatterlist *sg;
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+ rm->m_inc.i_hdr.h_len = cpu_to_be32(iov_iter_count(from));
|
|
|
+
|
|
|
+ /* now allocate and copy in the data payload. */
|
|
|
+ sg = rm->data.op_sg;
|
|
|
+ sg_off = 0; /* Dear gcc, sg->page will be null from kzalloc. */
|
|
|
+
|
|
|
+ if (zcopy)
|
|
|
+ return rds_message_zcopy_from_user(rm, from);
|
|
|
|
|
|
while (iov_iter_count(from)) {
|
|
|
if (!sg_page(sg)) {
|