io_uring: add rsrc referencing for notifiers
[linux-2.6-microblaze.git] / io_uring / notif.c
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
8 #include "io_uring.h"
9 #include "notif.h"
10 #include "rsrc.h"
11
12 static void __io_notif_complete_tw(struct callback_head *cb)
13 {
14         struct io_notif *notif = container_of(cb, struct io_notif, task_work);
15         struct io_rsrc_node *rsrc_node = notif->rsrc_node;
16         struct io_ring_ctx *ctx = notif->ctx;
17
18         if (likely(notif->task)) {
19                 io_put_task(notif->task, 1);
20                 notif->task = NULL;
21         }
22
23         io_cq_lock(ctx);
24         io_fill_cqe_aux(ctx, notif->tag, 0, notif->seq, true);
25
26         list_add(&notif->cache_node, &ctx->notif_list_locked);
27         ctx->notif_locked_nr++;
28         io_cq_unlock_post(ctx);
29
30         io_rsrc_put_node(rsrc_node, 1);
31         percpu_ref_put(&ctx->refs);
32 }
33
34 static inline void io_notif_complete(struct io_notif *notif)
35 {
36         __io_notif_complete_tw(&notif->task_work);
37 }
38
39 static void io_notif_complete_wq(struct work_struct *work)
40 {
41         struct io_notif *notif = container_of(work, struct io_notif, commit_work);
42
43         io_notif_complete(notif);
44 }
45
46 static void io_uring_tx_zerocopy_callback(struct sk_buff *skb,
47                                           struct ubuf_info *uarg,
48                                           bool success)
49 {
50         struct io_notif *notif = container_of(uarg, struct io_notif, uarg);
51
52         if (!refcount_dec_and_test(&uarg->refcnt))
53                 return;
54
55         if (likely(notif->task)) {
56                 init_task_work(&notif->task_work, __io_notif_complete_tw);
57                 if (likely(!task_work_add(notif->task, &notif->task_work,
58                                           TWA_SIGNAL)))
59                         return;
60         }
61
62         INIT_WORK(&notif->commit_work, io_notif_complete_wq);
63         queue_work(system_unbound_wq, &notif->commit_work);
64 }
65
66 static void io_notif_splice_cached(struct io_ring_ctx *ctx)
67         __must_hold(&ctx->uring_lock)
68 {
69         spin_lock(&ctx->completion_lock);
70         list_splice_init(&ctx->notif_list_locked, &ctx->notif_list);
71         ctx->notif_locked_nr = 0;
72         spin_unlock(&ctx->completion_lock);
73 }
74
75 void io_notif_cache_purge(struct io_ring_ctx *ctx)
76         __must_hold(&ctx->uring_lock)
77 {
78         io_notif_splice_cached(ctx);
79
80         while (!list_empty(&ctx->notif_list)) {
81                 struct io_notif *notif = list_first_entry(&ctx->notif_list,
82                                                 struct io_notif, cache_node);
83
84                 list_del(&notif->cache_node);
85                 kfree(notif);
86         }
87 }
88
89 static inline bool io_notif_has_cached(struct io_ring_ctx *ctx)
90         __must_hold(&ctx->uring_lock)
91 {
92         if (likely(!list_empty(&ctx->notif_list)))
93                 return true;
94         if (data_race(READ_ONCE(ctx->notif_locked_nr) <= IO_NOTIF_SPLICE_BATCH))
95                 return false;
96         io_notif_splice_cached(ctx);
97         return !list_empty(&ctx->notif_list);
98 }
99
100 struct io_notif *io_alloc_notif(struct io_ring_ctx *ctx,
101                                 struct io_notif_slot *slot)
102         __must_hold(&ctx->uring_lock)
103 {
104         struct io_notif *notif;
105
106         if (likely(io_notif_has_cached(ctx))) {
107                 notif = list_first_entry(&ctx->notif_list,
108                                          struct io_notif, cache_node);
109                 list_del(&notif->cache_node);
110         } else {
111                 notif = kzalloc(sizeof(*notif), GFP_ATOMIC | __GFP_ACCOUNT);
112                 if (!notif)
113                         return NULL;
114                 /* pre-initialise some fields */
115                 notif->ctx = ctx;
116                 notif->uarg.flags = SKBFL_ZEROCOPY_FRAG | SKBFL_DONT_ORPHAN;
117                 notif->uarg.callback = io_uring_tx_zerocopy_callback;
118         }
119
120         notif->seq = slot->seq++;
121         notif->tag = slot->tag;
122         /* master ref owned by io_notif_slot, will be dropped on flush */
123         refcount_set(&notif->uarg.refcnt, 1);
124         percpu_ref_get(&ctx->refs);
125         notif->rsrc_node = ctx->rsrc_node;
126         io_charge_rsrc_node(ctx);
127         return notif;
128 }
129
130 static void io_notif_slot_flush(struct io_notif_slot *slot)
131         __must_hold(&ctx->uring_lock)
132 {
133         struct io_notif *notif = slot->notif;
134
135         slot->notif = NULL;
136
137         if (WARN_ON_ONCE(in_interrupt()))
138                 return;
139         /* drop slot's master ref */
140         if (refcount_dec_and_test(&notif->uarg.refcnt))
141                 io_notif_complete(notif);
142 }
143
144 __cold int io_notif_unregister(struct io_ring_ctx *ctx)
145         __must_hold(&ctx->uring_lock)
146 {
147         int i;
148
149         if (!ctx->notif_slots)
150                 return -ENXIO;
151
152         for (i = 0; i < ctx->nr_notif_slots; i++) {
153                 struct io_notif_slot *slot = &ctx->notif_slots[i];
154
155                 if (!slot->notif)
156                         continue;
157                 if (WARN_ON_ONCE(slot->notif->task))
158                         slot->notif->task = NULL;
159                 io_notif_slot_flush(slot);
160         }
161
162         kvfree(ctx->notif_slots);
163         ctx->notif_slots = NULL;
164         ctx->nr_notif_slots = 0;
165         return 0;
166 }