source: mainline/uspace/srv/vfs/vfs_ipc.c@ 8048931c

Last change on this file since 8048931c was f5837524, checked in by Jakub Jermar <jakub@…>, 7 years ago

Use user-defined labels instead of phone hashes

This commit changes the way how the async framework maps incomming calls
to connections. Instead of abusing the kernel addresses of attached
phones as identifiers, the IPC_M_CONNECT_TO_ME and IPC_M_CONNECT_ME_TO
messages allow the server to specify an arbitrary label which is
remembered in the connected phone and consequently imprinted on each
call which is routed through this phone.

The async framework uses the address of the connection structure as the
label. This removes the need for a connection hash table because each
incoming call already remembers the connection in its label.

To disambiguate this new label and the other user-defined label used for
answers, the call structure now has the request_label member for the
former and answer_label member for the latter.

This commit also moves the kernel definition of ipc_data_t to abi/ and
removes the uspace redefinition thereof. Finally, when forwarding the
IPC_M_CONNECT_TO_ME call, the phone capability and the kernel object
allocated in request_process are now correctly disposed of.

  • Property mode set to 100644
File size: 8.9 KB
Line 
1/*
2 * Copyright (c) 2008 Jakub Jermar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <vfs/vfs.h>
30#include "vfs.h"
31
32#include <errno.h>
33#include <stdlib.h>
34#include <str.h>
35#include <vfs/canonify.h>
36
37static void vfs_in_clone(ipc_call_t *req)
38{
39 int oldfd = IPC_GET_ARG1(*req);
40 int newfd = IPC_GET_ARG2(*req);
41 bool desc = IPC_GET_ARG3(*req);
42
43 int outfd = -1;
44 errno_t rc = vfs_op_clone(oldfd, newfd, desc, &outfd);
45 async_answer_1(req, rc, outfd);
46}
47
48static void vfs_in_fsprobe(ipc_call_t *req)
49{
50 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
51 char *fs_name = NULL;
52 vfs_fs_probe_info_t info;
53 errno_t rc;
54
55 /*
56 * Now we expect the client to send us data with the name of the file
57 * system.
58 */
59 rc = async_data_write_accept((void **) &fs_name, true, 0,
60 FS_NAME_MAXLEN, 0, NULL);
61 if (rc != EOK) {
62 async_answer_0(req, rc);
63 return;
64 }
65
66 rc = vfs_op_fsprobe(fs_name, service_id, &info);
67 async_answer_0(req, rc);
68 if (rc != EOK)
69 goto out;
70
71 /* Now we should get a read request */
72 ipc_call_t call;
73 size_t len;
74 if (!async_data_read_receive(&call, &len))
75 goto out;
76
77 if (len > sizeof(info))
78 len = sizeof(info);
79 (void) async_data_read_finalize(&call, &info, len);
80
81out:
82 free(fs_name);
83}
84
85static void vfs_in_fstypes(ipc_call_t *req)
86{
87 vfs_fstypes_t fstypes;
88 errno_t rc;
89
90 rc = vfs_get_fstypes(&fstypes);
91 if (rc != EOK) {
92 async_answer_0(req, ENOMEM);
93 return;
94 }
95
96 /* Send size of the data */
97 async_answer_1(req, EOK, fstypes.size);
98
99 /* Now we should get a read request */
100 ipc_call_t call;
101 size_t len;
102 if (!async_data_read_receive(&call, &len))
103 goto out;
104
105 if (len > fstypes.size)
106 len = fstypes.size;
107 (void) async_data_read_finalize(&call, fstypes.buf, len);
108
109out:
110 vfs_fstypes_free(&fstypes);
111}
112
113static void vfs_in_mount(ipc_call_t *req)
114{
115 int mpfd = IPC_GET_ARG1(*req);
116
117 /*
118 * We expect the library to do the device-name to device-handle
119 * translation for us, thus the device handle will arrive as ARG1
120 * in the request.
121 */
122 service_id_t service_id = (service_id_t) IPC_GET_ARG2(*req);
123
124 unsigned int flags = (unsigned int) IPC_GET_ARG3(*req);
125 unsigned int instance = IPC_GET_ARG4(*req);
126
127 char *opts = NULL;
128 char *fs_name = NULL;
129
130 /* Now we expect to receive the mount options. */
131 errno_t rc = async_data_write_accept((void **) &opts, true, 0,
132 MAX_MNTOPTS_LEN, 0, NULL);
133 if (rc != EOK) {
134 async_answer_0(req, rc);
135 return;
136 }
137
138 /*
139 * Now we expect the client to send us data with the name of the file
140 * system.
141 */
142 rc = async_data_write_accept((void **) &fs_name, true, 0,
143 FS_NAME_MAXLEN, 0, NULL);
144 if (rc != EOK) {
145 free(opts);
146 async_answer_0(req, rc);
147 return;
148 }
149
150 int outfd = 0;
151 rc = vfs_op_mount(mpfd, service_id, flags, instance, opts, fs_name,
152 &outfd);
153 async_answer_1(req, rc, outfd);
154
155 free(opts);
156 free(fs_name);
157}
158
159static void vfs_in_open(ipc_call_t *req)
160{
161 int fd = IPC_GET_ARG1(*req);
162 int mode = IPC_GET_ARG2(*req);
163
164 errno_t rc = vfs_op_open(fd, mode);
165 async_answer_0(req, rc);
166}
167
168static void vfs_in_put(ipc_call_t *req)
169{
170 int fd = IPC_GET_ARG1(*req);
171 errno_t rc = vfs_op_put(fd);
172 async_answer_0(req, rc);
173}
174
175static void vfs_in_read(ipc_call_t *req)
176{
177 int fd = IPC_GET_ARG1(*req);
178 aoff64_t pos = MERGE_LOUP32(IPC_GET_ARG2(*req),
179 IPC_GET_ARG3(*req));
180
181 size_t bytes = 0;
182 errno_t rc = vfs_op_read(fd, pos, &bytes);
183 async_answer_1(req, rc, bytes);
184}
185
186static void vfs_in_rename(ipc_call_t *req)
187{
188 /* The common base directory. */
189 int basefd;
190 char *old = NULL;
191 char *new = NULL;
192 errno_t rc;
193
194 basefd = IPC_GET_ARG1(*req);
195
196 /* Retrieve the old path. */
197 rc = async_data_write_accept((void **) &old, true, 0, 0, 0, NULL);
198 if (rc != EOK)
199 goto out;
200
201 /* Retrieve the new path. */
202 rc = async_data_write_accept((void **) &new, true, 0, 0, 0, NULL);
203 if (rc != EOK)
204 goto out;
205
206 size_t olen;
207 size_t nlen;
208 char *oldc = canonify(old, &olen);
209 char *newc = canonify(new, &nlen);
210
211 if ((!oldc) || (!newc)) {
212 rc = EINVAL;
213 goto out;
214 }
215
216 assert(oldc[olen] == '\0');
217 assert(newc[nlen] == '\0');
218
219 rc = vfs_op_rename(basefd, oldc, newc);
220
221out:
222 async_answer_0(req, rc);
223
224 if (old)
225 free(old);
226 if (new)
227 free(new);
228}
229
230static void vfs_in_resize(ipc_call_t *req)
231{
232 int fd = IPC_GET_ARG1(*req);
233 int64_t size = MERGE_LOUP32(IPC_GET_ARG2(*req), IPC_GET_ARG3(*req));
234 errno_t rc = vfs_op_resize(fd, size);
235 async_answer_0(req, rc);
236}
237
238static void vfs_in_stat(ipc_call_t *req)
239{
240 int fd = IPC_GET_ARG1(*req);
241 errno_t rc = vfs_op_stat(fd);
242 async_answer_0(req, rc);
243}
244
245static void vfs_in_statfs(ipc_call_t *req)
246{
247 int fd = (int) IPC_GET_ARG1(*req);
248
249 errno_t rc = vfs_op_statfs(fd);
250 async_answer_0(req, rc);
251}
252
253static void vfs_in_sync(ipc_call_t *req)
254{
255 int fd = IPC_GET_ARG1(*req);
256 errno_t rc = vfs_op_sync(fd);
257 async_answer_0(req, rc);
258}
259
260static void vfs_in_unlink(ipc_call_t *req)
261{
262 int parentfd = IPC_GET_ARG1(*req);
263 int expectfd = IPC_GET_ARG2(*req);
264
265 char *path;
266 errno_t rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL);
267 if (rc == EOK)
268 rc = vfs_op_unlink(parentfd, expectfd, path);
269
270 async_answer_0(req, rc);
271}
272
273static void vfs_in_unmount(ipc_call_t *req)
274{
275 int mpfd = IPC_GET_ARG1(*req);
276 errno_t rc = vfs_op_unmount(mpfd);
277 async_answer_0(req, rc);
278}
279
280static void vfs_in_wait_handle(ipc_call_t *req)
281{
282 bool high_fd = IPC_GET_ARG1(*req);
283 int fd = -1;
284 errno_t rc = vfs_op_wait_handle(high_fd, &fd);
285 async_answer_1(req, rc, fd);
286}
287
288static void vfs_in_walk(ipc_call_t *req)
289{
290 /*
291 * Parent is our relative root for file lookup.
292 * For defined flags, see <ipc/vfs.h>.
293 */
294 int parentfd = IPC_GET_ARG1(*req);
295 int flags = IPC_GET_ARG2(*req);
296
297 int fd = 0;
298 char *path;
299 errno_t rc = async_data_write_accept((void **)&path, true, 0, 0, 0, NULL);
300 if (rc == EOK) {
301 rc = vfs_op_walk(parentfd, flags, path, &fd);
302 free(path);
303 }
304 async_answer_1(req, rc, fd);
305}
306
307static void vfs_in_write(ipc_call_t *req)
308{
309 int fd = IPC_GET_ARG1(*req);
310 aoff64_t pos = MERGE_LOUP32(IPC_GET_ARG2(*req),
311 IPC_GET_ARG3(*req));
312
313 size_t bytes = 0;
314 errno_t rc = vfs_op_write(fd, pos, &bytes);
315 async_answer_1(req, rc, bytes);
316}
317
318void vfs_connection(ipc_call_t *icall, void *arg)
319{
320 bool cont = true;
321
322 /*
323 * The connection was opened via the IPC_CONNECT_ME_TO call.
324 * This call needs to be answered.
325 */
326 async_answer_5(icall, EOK, 0, 0, 0, 0, async_get_label());
327
328 while (cont) {
329 ipc_call_t call;
330 async_get_call(&call);
331
332 if (!IPC_GET_IMETHOD(call)) {
333 async_answer_0(&call, EOK);
334 break;
335 }
336
337 switch (IPC_GET_IMETHOD(call)) {
338 case VFS_IN_CLONE:
339 vfs_in_clone(&call);
340 break;
341 case VFS_IN_FSPROBE:
342 vfs_in_fsprobe(&call);
343 break;
344 case VFS_IN_FSTYPES:
345 vfs_in_fstypes(&call);
346 break;
347 case VFS_IN_MOUNT:
348 vfs_in_mount(&call);
349 break;
350 case VFS_IN_OPEN:
351 vfs_in_open(&call);
352 break;
353 case VFS_IN_PUT:
354 vfs_in_put(&call);
355 break;
356 case VFS_IN_READ:
357 vfs_in_read(&call);
358 break;
359 case VFS_IN_REGISTER:
360 vfs_register(&call);
361 cont = false;
362 break;
363 case VFS_IN_RENAME:
364 vfs_in_rename(&call);
365 break;
366 case VFS_IN_RESIZE:
367 vfs_in_resize(&call);
368 break;
369 case VFS_IN_STAT:
370 vfs_in_stat(&call);
371 break;
372 case VFS_IN_STATFS:
373 vfs_in_statfs(&call);
374 break;
375 case VFS_IN_SYNC:
376 vfs_in_sync(&call);
377 break;
378 case VFS_IN_UNLINK:
379 vfs_in_unlink(&call);
380 break;
381 case VFS_IN_UNMOUNT:
382 vfs_in_unmount(&call);
383 break;
384 case VFS_IN_WAIT_HANDLE:
385 vfs_in_wait_handle(&call);
386 break;
387 case VFS_IN_WALK:
388 vfs_in_walk(&call);
389 break;
390 case VFS_IN_WRITE:
391 vfs_in_write(&call);
392 break;
393 default:
394 async_answer_0(&call, ENOTSUP);
395 break;
396 }
397 }
398
399 /*
400 * Open files for this client will be cleaned up when its last
401 * connection fibril terminates.
402 */
403}
Note: See TracBrowser for help on using the repository browser.