kdbus: the driver, original and non-working
[platform/kernel/linux-exynos.git] / ipc / kdbus / reply.c
1 #include <linux/init.h>
2 #include <linux/mm.h>
3 #include <linux/module.h>
4 #include <linux/mutex.h>
5 #include <linux/slab.h>
6 #include <linux/uio.h>
7
8 #include "bus.h"
9 #include "connection.h"
10 #include "endpoint.h"
11 #include "message.h"
12 #include "metadata.h"
13 #include "names.h"
14 #include "domain.h"
15 #include "item.h"
16 #include "notify.h"
17 #include "policy.h"
18 #include "reply.h"
19 #include "util.h"
20
21 /**
22  * kdbus_reply_new() - Allocate and set up a new kdbus_reply object
23  * @reply_src:          The connection a reply is expected from
24  * @reply_dst:          The connection this reply object belongs to
25  * @msg:                Message associated with the reply
26  * @name_entry:         Name entry used to send the message
27  * @sync:               Whether or not to make this reply synchronous
28  *
29  * Allocate and fill a new kdbus_reply object.
30  *
31  * Return: New kdbus_conn object on success, ERR_PTR on error.
32  */
33 struct kdbus_reply *kdbus_reply_new(struct kdbus_conn *reply_src,
34                                     struct kdbus_conn *reply_dst,
35                                     const struct kdbus_msg *msg,
36                                     struct kdbus_name_entry *name_entry,
37                                     bool sync)
38 {
39         struct kdbus_reply *r;
40         int ret;
41
42         if (atomic_inc_return(&reply_dst->request_count) >
43             KDBUS_CONN_MAX_REQUESTS_PENDING) {
44                 ret = -EMLINK;
45                 goto exit_dec_request_count;
46         }
47
48         r = kzalloc(sizeof(*r), GFP_KERNEL);
49         if (!r) {
50                 ret = -ENOMEM;
51                 goto exit_dec_request_count;
52         }
53
54         kref_init(&r->kref);
55         INIT_LIST_HEAD(&r->entry);
56         r->reply_src = kdbus_conn_ref(reply_src);
57         r->reply_dst = kdbus_conn_ref(reply_dst);
58         r->cookie = msg->cookie;
59         r->name_id = name_entry ? name_entry->name_id : 0;
60         r->deadline_ns = msg->timeout_ns;
61
62         if (sync) {
63                 r->sync = true;
64                 r->waiting = true;
65         }
66
67         return r;
68
69 exit_dec_request_count:
70         atomic_dec(&reply_dst->request_count);
71         return ERR_PTR(ret);
72 }
73
74 static void __kdbus_reply_free(struct kref *kref)
75 {
76         struct kdbus_reply *reply =
77                 container_of(kref, struct kdbus_reply, kref);
78
79         atomic_dec(&reply->reply_dst->request_count);
80         kdbus_conn_unref(reply->reply_src);
81         kdbus_conn_unref(reply->reply_dst);
82         kfree(reply);
83 }
84
85 /**
86  * kdbus_reply_ref() - Increase reference on kdbus_reply
87  * @r:          The reply, may be %NULL
88  *
89  * Return: The reply object with an extra reference
90  */
91 struct kdbus_reply *kdbus_reply_ref(struct kdbus_reply *r)
92 {
93         if (r)
94                 kref_get(&r->kref);
95         return r;
96 }
97
98 /**
99  * kdbus_reply_unref() - Decrease reference on kdbus_reply
100  * @r:          The reply, may be %NULL
101  *
102  * Return: NULL
103  */
104 struct kdbus_reply *kdbus_reply_unref(struct kdbus_reply *r)
105 {
106         if (r)
107                 kref_put(&r->kref, __kdbus_reply_free);
108         return NULL;
109 }
110
111 /**
112  * kdbus_reply_link() - Link reply object into target connection
113  * @r:          Reply to link
114  */
115 void kdbus_reply_link(struct kdbus_reply *r)
116 {
117         if (WARN_ON(!list_empty(&r->entry)))
118                 return;
119
120         list_add_tail(&r->entry, &r->reply_dst->reply_list);
121         kdbus_reply_ref(r);
122 }
123
124 /**
125  * kdbus_reply_unlink() - Unlink reply object from target connection
126  * @r:          Reply to unlink
127  */
128 void kdbus_reply_unlink(struct kdbus_reply *r)
129 {
130         if (!list_empty(&r->entry)) {
131                 list_del_init(&r->entry);
132                 kdbus_reply_unref(r);
133         }
134 }
135
136 /**
137  * kdbus_sync_reply_wakeup() - Wake a synchronously blocking reply
138  * @reply:      The reply object
139  * @err:        Error code to set on the remote side
140  *
141  * Wake up remote peer (method origin) with the appropriate synchronous reply
142  * code.
143  */
144 void kdbus_sync_reply_wakeup(struct kdbus_reply *reply, int err)
145 {
146         if (WARN_ON(!reply->sync))
147                 return;
148
149         reply->waiting = false;
150         reply->err = err;
151         wake_up_interruptible(&reply->reply_dst->wait);
152 }
153
154 /**
155  * kdbus_reply_find() - Find the corresponding reply object
156  * @replying:   The replying connection or NULL
157  * @reply_dst:  The connection the reply will be sent to
158  *              (method origin)
159  * @cookie:     The cookie of the requesting message
160  *
161  * Lookup a reply object that should be sent as a reply by
162  * @replying to @reply_dst with the given cookie.
163  *
164  * Callers must take the @reply_dst lock.
165  *
166  * Return: the corresponding reply object or NULL if not found
167  */
168 struct kdbus_reply *kdbus_reply_find(struct kdbus_conn *replying,
169                                      struct kdbus_conn *reply_dst,
170                                      u64 cookie)
171 {
172         struct kdbus_reply *r;
173
174         list_for_each_entry(r, &reply_dst->reply_list, entry) {
175                 if (r->cookie == cookie &&
176                     (!replying || r->reply_src == replying))
177                         return r;
178         }
179
180         return NULL;
181 }
182
183 /**
184  * kdbus_reply_list_scan_work() - Worker callback to scan the replies of a
185  *                                connection for exceeded timeouts
186  * @work:               Work struct of the connection to scan
187  *
188  * Walk the list of replies stored with a connection and look for entries
189  * that have exceeded their timeout. If such an entry is found, a timeout
190  * notification is sent to the waiting peer, and the reply is removed from
191  * the list.
192  *
193  * The work is rescheduled to the nearest timeout found during the list
194  * iteration.
195  */
196 void kdbus_reply_list_scan_work(struct work_struct *work)
197 {
198         struct kdbus_conn *conn =
199                 container_of(work, struct kdbus_conn, work.work);
200         struct kdbus_reply *reply, *reply_tmp;
201         u64 deadline = ~0ULL;
202         u64 now;
203
204         now = ktime_get_ns();
205
206         mutex_lock(&conn->lock);
207         if (!kdbus_conn_active(conn)) {
208                 mutex_unlock(&conn->lock);
209                 return;
210         }
211
212         list_for_each_entry_safe(reply, reply_tmp, &conn->reply_list, entry) {
213                 /*
214                  * If the reply block is waiting for synchronous I/O,
215                  * the timeout is handled by wait_event_*_timeout(),
216                  * so we don't have to care for it here.
217                  */
218                 if (reply->sync && !reply->interrupted)
219                         continue;
220
221                 WARN_ON(reply->reply_dst != conn);
222
223                 if (reply->deadline_ns > now) {
224                         /* remember next timeout */
225                         if (deadline > reply->deadline_ns)
226                                 deadline = reply->deadline_ns;
227
228                         continue;
229                 }
230
231                 /*
232                  * A zero deadline means the connection died, was
233                  * cleaned up already and the notification was sent.
234                  * Don't send notifications for reply trackers that were
235                  * left in an interrupted syscall state.
236                  */
237                 if (reply->deadline_ns != 0 && !reply->interrupted)
238                         kdbus_notify_reply_timeout(conn->ep->bus, conn->id,
239                                                    reply->cookie);
240
241                 kdbus_reply_unlink(reply);
242         }
243
244         /* rearm delayed work with next timeout */
245         if (deadline != ~0ULL)
246                 schedule_delayed_work(&conn->work,
247                                       nsecs_to_jiffies(deadline - now));
248
249         mutex_unlock(&conn->lock);
250
251         kdbus_notify_flush(conn->ep->bus);
252 }