notif.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. #include <linux/kernel.h>
  2. #include <linux/errno.h>
  3. #include <linux/file.h>
  4. #include <linux/slab.h>
  5. #include <linux/net.h>
  6. #include <linux/io_uring.h>
  7. #include "io_uring.h"
  8. #include "notif.h"
  9. #include "rsrc.h"
  10. static const struct ubuf_info_ops io_ubuf_ops;
  11. static void io_notif_tw_complete(struct io_kiocb *notif, struct io_tw_state *ts)
  12. {
  13. struct io_notif_data *nd = io_notif_to_data(notif);
  14. do {
  15. notif = cmd_to_io_kiocb(nd);
  16. lockdep_assert(refcount_read(&nd->uarg.refcnt) == 0);
  17. if (unlikely(nd->zc_report) && (nd->zc_copied || !nd->zc_used))
  18. notif->cqe.res |= IORING_NOTIF_USAGE_ZC_COPIED;
  19. if (nd->account_pages && notif->ctx->user) {
  20. __io_unaccount_mem(notif->ctx->user, nd->account_pages);
  21. nd->account_pages = 0;
  22. }
  23. nd = nd->next;
  24. io_req_task_complete(notif, ts);
  25. } while (nd);
  26. }
  27. void io_tx_ubuf_complete(struct sk_buff *skb, struct ubuf_info *uarg,
  28. bool success)
  29. {
  30. struct io_notif_data *nd = container_of(uarg, struct io_notif_data, uarg);
  31. struct io_kiocb *notif = cmd_to_io_kiocb(nd);
  32. unsigned tw_flags;
  33. if (nd->zc_report) {
  34. if (success && !nd->zc_used && skb)
  35. WRITE_ONCE(nd->zc_used, true);
  36. else if (!success && !nd->zc_copied)
  37. WRITE_ONCE(nd->zc_copied, true);
  38. }
  39. if (!refcount_dec_and_test(&uarg->refcnt))
  40. return;
  41. if (nd->head != nd) {
  42. io_tx_ubuf_complete(skb, &nd->head->uarg, success);
  43. return;
  44. }
  45. tw_flags = nd->next ? 0 : IOU_F_TWQ_LAZY_WAKE;
  46. notif->io_task_work.func = io_notif_tw_complete;
  47. __io_req_task_work_add(notif, tw_flags);
  48. }
  49. static int io_link_skb(struct sk_buff *skb, struct ubuf_info *uarg)
  50. {
  51. struct io_notif_data *nd, *prev_nd;
  52. struct io_kiocb *prev_notif, *notif;
  53. struct ubuf_info *prev_uarg = skb_zcopy(skb);
  54. nd = container_of(uarg, struct io_notif_data, uarg);
  55. notif = cmd_to_io_kiocb(nd);
  56. if (!prev_uarg) {
  57. net_zcopy_get(&nd->uarg);
  58. skb_zcopy_init(skb, &nd->uarg);
  59. return 0;
  60. }
  61. /* handle it separately as we can't link a notif to itself */
  62. if (unlikely(prev_uarg == &nd->uarg))
  63. return 0;
  64. /* we can't join two links together, just request a fresh skb */
  65. if (unlikely(nd->head != nd || nd->next))
  66. return -EEXIST;
  67. /* don't mix zc providers */
  68. if (unlikely(prev_uarg->ops != &io_ubuf_ops))
  69. return -EEXIST;
  70. prev_nd = container_of(prev_uarg, struct io_notif_data, uarg);
  71. prev_notif = cmd_to_io_kiocb(prev_nd);
  72. /* make sure all noifications can be finished in the same task_work */
  73. if (unlikely(notif->ctx != prev_notif->ctx ||
  74. notif->task != prev_notif->task))
  75. return -EEXIST;
  76. nd->head = prev_nd->head;
  77. nd->next = prev_nd->next;
  78. prev_nd->next = nd;
  79. net_zcopy_get(&nd->head->uarg);
  80. return 0;
  81. }
  82. static const struct ubuf_info_ops io_ubuf_ops = {
  83. .complete = io_tx_ubuf_complete,
  84. .link_skb = io_link_skb,
  85. };
  86. struct io_kiocb *io_alloc_notif(struct io_ring_ctx *ctx)
  87. __must_hold(&ctx->uring_lock)
  88. {
  89. struct io_kiocb *notif;
  90. struct io_notif_data *nd;
  91. if (unlikely(!io_alloc_req(ctx, &notif)))
  92. return NULL;
  93. notif->opcode = IORING_OP_NOP;
  94. notif->flags = 0;
  95. notif->file = NULL;
  96. notif->task = current;
  97. io_get_task_refs(1);
  98. notif->rsrc_node = NULL;
  99. nd = io_notif_to_data(notif);
  100. nd->zc_report = false;
  101. nd->account_pages = 0;
  102. nd->next = NULL;
  103. nd->head = nd;
  104. nd->uarg.flags = IO_NOTIF_UBUF_FLAGS;
  105. nd->uarg.ops = &io_ubuf_ops;
  106. refcount_set(&nd->uarg.refcnt, 1);
  107. return notif;
  108. }