diff options
| -rw-r--r-- | io_uring/notif.c | 71 | ||||
| -rw-r--r-- | io_uring/notif.h | 3 | 
2 files changed, 67 insertions, 7 deletions
| diff --git a/io_uring/notif.c b/io_uring/notif.c index 26680176335f..d58cdc01e691 100644 --- a/io_uring/notif.c +++ b/io_uring/notif.c @@ -9,18 +9,28 @@  #include "notif.h"  #include "rsrc.h" +static const struct ubuf_info_ops io_ubuf_ops; +  static void io_notif_tw_complete(struct io_kiocb *notif, struct io_tw_state *ts)  {  	struct io_notif_data *nd = io_notif_to_data(notif); -	if (unlikely(nd->zc_report) && (nd->zc_copied || !nd->zc_used)) -		notif->cqe.res |= IORING_NOTIF_USAGE_ZC_COPIED; +	do { +		notif = cmd_to_io_kiocb(nd); -	if (nd->account_pages && notif->ctx->user) { -		__io_unaccount_mem(notif->ctx->user, nd->account_pages); -		nd->account_pages = 0; -	} -	io_req_task_complete(notif, ts); +		lockdep_assert(refcount_read(&nd->uarg.refcnt) == 0); + +		if (unlikely(nd->zc_report) && (nd->zc_copied || !nd->zc_used)) +			notif->cqe.res |= IORING_NOTIF_USAGE_ZC_COPIED; + +		if (nd->account_pages && notif->ctx->user) { +			__io_unaccount_mem(notif->ctx->user, nd->account_pages); +			nd->account_pages = 0; +		} + +		nd = nd->next; +		io_req_task_complete(notif, ts); +	} while (nd);  }  void io_tx_ubuf_complete(struct sk_buff *skb, struct ubuf_info *uarg, @@ -39,12 +49,56 @@ void io_tx_ubuf_complete(struct sk_buff *skb, struct ubuf_info *uarg,  	if (!refcount_dec_and_test(&uarg->refcnt))  		return; +	if (nd->head != nd) { +		io_tx_ubuf_complete(skb, &nd->head->uarg, success); +		return; +	}  	notif->io_task_work.func = io_notif_tw_complete;  	__io_req_task_work_add(notif, IOU_F_TWQ_LAZY_WAKE);  } +static int io_link_skb(struct sk_buff *skb, struct ubuf_info *uarg) +{ +	struct io_notif_data *nd, *prev_nd; +	struct io_kiocb *prev_notif, *notif; +	struct ubuf_info *prev_uarg = skb_zcopy(skb); + +	nd = container_of(uarg, struct io_notif_data, uarg); +	notif = cmd_to_io_kiocb(nd); + +	if (!prev_uarg) { +		net_zcopy_get(&nd->uarg); +		skb_zcopy_init(skb, &nd->uarg); +		return 0; +	} +	/* handle it separately as we can't link a notif to itself */ +	if (unlikely(prev_uarg == &nd->uarg)) +		return 0; +	/* we can't join two links together, just request a fresh skb */ +	if (unlikely(nd->head != nd || nd->next)) +		return -EEXIST; +	/* don't mix zc providers */ +	if (unlikely(prev_uarg->ops != &io_ubuf_ops)) +		return -EEXIST; + +	prev_nd = container_of(prev_uarg, struct io_notif_data, uarg); +	prev_notif = cmd_to_io_kiocb(nd); + +	/* make sure all noifications can be finished in the same task_work */ +	if (unlikely(notif->ctx != prev_notif->ctx || +		     notif->task != prev_notif->task)) +		return -EEXIST; + +	nd->head = prev_nd->head; +	nd->next = prev_nd->next; +	prev_nd->next = nd; +	net_zcopy_get(&nd->head->uarg); +	return 0; +} +  static const struct ubuf_info_ops io_ubuf_ops = {  	.complete = io_tx_ubuf_complete, +	.link_skb = io_link_skb,  };  struct io_kiocb *io_alloc_notif(struct io_ring_ctx *ctx) @@ -65,6 +119,9 @@ struct io_kiocb *io_alloc_notif(struct io_ring_ctx *ctx)  	nd = io_notif_to_data(notif);  	nd->zc_report = false;  	nd->account_pages = 0; +	nd->next = NULL; +	nd->head = nd; +  	nd->uarg.flags = IO_NOTIF_UBUF_FLAGS;  	nd->uarg.ops = &io_ubuf_ops;  	refcount_set(&nd->uarg.refcnt, 1); diff --git a/io_uring/notif.h b/io_uring/notif.h index 2cf9ff6abd7a..f3589cfef4a9 100644 --- a/io_uring/notif.h +++ b/io_uring/notif.h @@ -14,6 +14,9 @@ struct io_notif_data {  	struct file		*file;  	struct ubuf_info	uarg; +	struct io_notif_data	*next; +	struct io_notif_data	*head; +  	unsigned		account_pages;  	bool			zc_report;  	bool			zc_used; | 
