source: mainline/uspace/lib/fs/libfs.c@ eec201d

Last change on this file since eec201d 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: 20.3 KB
Line 
1/*
2 * Copyright (c) 2009 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/** @addtogroup libfs
30 * @{
31 */
32/**
33 * @file
34 * Glue code which is common to all FS implementations.
35 */
36
37#include "libfs.h"
38#include <macros.h>
39#include <errno.h>
40#include <async.h>
41#include <as.h>
42#include <assert.h>
43#include <dirent.h>
44#include <mem.h>
45#include <str.h>
46#include <stdlib.h>
47#include <fibril_synch.h>
48#include <ipc/vfs.h>
49#include <vfs/vfs.h>
50
51#define on_error(rc, action) \
52 do { \
53 if ((rc) != EOK) \
54 action; \
55 } while (0)
56
57#define combine_rc(rc1, rc2) \
58 ((rc1) == EOK ? (rc2) : (rc1))
59
60#define answer_and_return(call, rc) \
61 do { \
62 async_answer_0((call), (rc)); \
63 return; \
64 } while (0)
65
66static fs_reg_t reg;
67
68static vfs_out_ops_t *vfs_out_ops = NULL;
69static libfs_ops_t *libfs_ops = NULL;
70
71static char fs_name[FS_NAME_MAXLEN + 1];
72
73static void libfs_link(libfs_ops_t *, fs_handle_t, ipc_call_t *);
74static void libfs_lookup(libfs_ops_t *, fs_handle_t, ipc_call_t *);
75static void libfs_stat(libfs_ops_t *, fs_handle_t, ipc_call_t *);
76static void libfs_open_node(libfs_ops_t *, fs_handle_t, ipc_call_t *);
77static void libfs_statfs(libfs_ops_t *, fs_handle_t, ipc_call_t *);
78
79static void vfs_out_fsprobe(ipc_call_t *req)
80{
81 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
82 errno_t rc;
83 vfs_fs_probe_info_t info;
84
85 ipc_call_t call;
86 size_t size;
87 if ((!async_data_read_receive(&call, &size)) ||
88 (size != sizeof(info))) {
89 async_answer_0(&call, EIO);
90 async_answer_0(req, EIO);
91 return;
92 }
93
94 memset(&info, 0, sizeof(info));
95 rc = vfs_out_ops->fsprobe(service_id, &info);
96 if (rc != EOK) {
97 async_answer_0(&call, EIO);
98 async_answer_0(req, rc);
99 return;
100 }
101
102 async_data_read_finalize(&call, &info, sizeof(info));
103 async_answer_0(req, EOK);
104}
105
106static void vfs_out_mounted(ipc_call_t *req)
107{
108 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
109 char *opts;
110 errno_t rc;
111
112 /* Accept the mount options. */
113 rc = async_data_write_accept((void **) &opts, true, 0, 0, 0, NULL);
114 if (rc != EOK) {
115 async_answer_0(req, rc);
116 return;
117 }
118
119 fs_index_t index;
120 aoff64_t size;
121 rc = vfs_out_ops->mounted(service_id, opts, &index, &size);
122
123 if (rc == EOK) {
124 async_answer_3(req, EOK, index, LOWER32(size),
125 UPPER32(size));
126 } else
127 async_answer_0(req, rc);
128
129 free(opts);
130}
131
132static void vfs_out_unmounted(ipc_call_t *req)
133{
134 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
135 errno_t rc;
136
137 rc = vfs_out_ops->unmounted(service_id);
138
139 async_answer_0(req, rc);
140}
141
142static void vfs_out_link(ipc_call_t *req)
143{
144 libfs_link(libfs_ops, reg.fs_handle, req);
145}
146
147static void vfs_out_lookup(ipc_call_t *req)
148{
149 libfs_lookup(libfs_ops, reg.fs_handle, req);
150}
151
152static void vfs_out_read(ipc_call_t *req)
153{
154 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
155 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
156 aoff64_t pos = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*req),
157 IPC_GET_ARG4(*req));
158 size_t rbytes;
159 errno_t rc;
160
161 rc = vfs_out_ops->read(service_id, index, pos, &rbytes);
162
163 if (rc == EOK)
164 async_answer_1(req, EOK, rbytes);
165 else
166 async_answer_0(req, rc);
167}
168
169static void vfs_out_write(ipc_call_t *req)
170{
171 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
172 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
173 aoff64_t pos = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*req),
174 IPC_GET_ARG4(*req));
175 size_t wbytes;
176 aoff64_t nsize;
177 errno_t rc;
178
179 rc = vfs_out_ops->write(service_id, index, pos, &wbytes, &nsize);
180
181 if (rc == EOK) {
182 async_answer_3(req, EOK, wbytes, LOWER32(nsize),
183 UPPER32(nsize));
184 } else
185 async_answer_0(req, rc);
186}
187
188static void vfs_out_truncate(ipc_call_t *req)
189{
190 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
191 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
192 aoff64_t size = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*req),
193 IPC_GET_ARG4(*req));
194 errno_t rc;
195
196 rc = vfs_out_ops->truncate(service_id, index, size);
197
198 async_answer_0(req, rc);
199}
200
201static void vfs_out_close(ipc_call_t *req)
202{
203 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
204 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
205 errno_t rc;
206
207 rc = vfs_out_ops->close(service_id, index);
208
209 async_answer_0(req, rc);
210}
211
212static void vfs_out_destroy(ipc_call_t *req)
213{
214 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
215 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
216
217 errno_t rc;
218 fs_node_t *node = NULL;
219 rc = libfs_ops->node_get(&node, service_id, index);
220 if (rc == EOK && node != NULL) {
221 bool destroy = (libfs_ops->lnkcnt_get(node) == 0);
222 libfs_ops->node_put(node);
223 if (destroy)
224 rc = vfs_out_ops->destroy(service_id, index);
225 }
226 async_answer_0(req, rc);
227}
228
229static void vfs_out_open_node(ipc_call_t *req)
230{
231 libfs_open_node(libfs_ops, reg.fs_handle, req);
232}
233
234static void vfs_out_stat(ipc_call_t *req)
235{
236 libfs_stat(libfs_ops, reg.fs_handle, req);
237}
238
239static void vfs_out_sync(ipc_call_t *req)
240{
241 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
242 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
243 errno_t rc;
244
245 rc = vfs_out_ops->sync(service_id, index);
246
247 async_answer_0(req, rc);
248}
249
250static void vfs_out_statfs(ipc_call_t *req)
251{
252 libfs_statfs(libfs_ops, reg.fs_handle, req);
253}
254
255static void vfs_out_is_empty(ipc_call_t *req)
256{
257 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
258 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
259 errno_t rc;
260
261 fs_node_t *node = NULL;
262 rc = libfs_ops->node_get(&node, service_id, index);
263 if (rc != EOK)
264 async_answer_0(req, rc);
265 if (node == NULL)
266 async_answer_0(req, EINVAL);
267
268 bool children = false;
269 rc = libfs_ops->has_children(&children, node);
270 libfs_ops->node_put(node);
271
272 if (rc != EOK)
273 async_answer_0(req, rc);
274 async_answer_0(req, children ? ENOTEMPTY : EOK);
275}
276
277static void vfs_connection(ipc_call_t *icall, void *arg)
278{
279 if (icall->cap_handle) {
280 /*
281 * This only happens for connections opened by
282 * IPC_M_CONNECT_ME_TO calls as opposed to callback connections
283 * created by IPC_M_CONNECT_TO_ME.
284 */
285 async_answer_5(icall, EOK, 0, 0, 0, 0, async_get_label());
286 }
287
288 while (true) {
289 ipc_call_t call;
290 async_get_call(&call);
291
292 if (!IPC_GET_IMETHOD(call)) {
293 async_answer_0(&call, EOK);
294 return;
295 }
296
297 switch (IPC_GET_IMETHOD(call)) {
298 case VFS_OUT_FSPROBE:
299 vfs_out_fsprobe(&call);
300 break;
301 case VFS_OUT_MOUNTED:
302 vfs_out_mounted(&call);
303 break;
304 case VFS_OUT_UNMOUNTED:
305 vfs_out_unmounted(&call);
306 break;
307 case VFS_OUT_LINK:
308 vfs_out_link(&call);
309 break;
310 case VFS_OUT_LOOKUP:
311 vfs_out_lookup(&call);
312 break;
313 case VFS_OUT_READ:
314 vfs_out_read(&call);
315 break;
316 case VFS_OUT_WRITE:
317 vfs_out_write(&call);
318 break;
319 case VFS_OUT_TRUNCATE:
320 vfs_out_truncate(&call);
321 break;
322 case VFS_OUT_CLOSE:
323 vfs_out_close(&call);
324 break;
325 case VFS_OUT_DESTROY:
326 vfs_out_destroy(&call);
327 break;
328 case VFS_OUT_OPEN_NODE:
329 vfs_out_open_node(&call);
330 break;
331 case VFS_OUT_STAT:
332 vfs_out_stat(&call);
333 break;
334 case VFS_OUT_SYNC:
335 vfs_out_sync(&call);
336 break;
337 case VFS_OUT_STATFS:
338 vfs_out_statfs(&call);
339 break;
340 case VFS_OUT_IS_EMPTY:
341 vfs_out_is_empty(&call);
342 break;
343 default:
344 async_answer_0(&call, ENOTSUP);
345 break;
346 }
347 }
348}
349
350/** Register file system server.
351 *
352 * This function abstracts away the tedious registration protocol from
353 * file system implementations and lets them to reuse this registration glue
354 * code.
355 *
356 * @param sess Session for communication with VFS.
357 * @param info VFS info structure supplied by the file system
358 * implementation.
359 * @param vops Address of the vfs_out_ops_t structure.
360 * @param lops Address of the libfs_ops_t structure.
361 *
362 * @return EOK on success or a non-zero error code on errror.
363 *
364 */
365errno_t fs_register(async_sess_t *sess, vfs_info_t *info, vfs_out_ops_t *vops,
366 libfs_ops_t *lops)
367{
368 /*
369 * Tell VFS that we are here and want to get registered.
370 * We use the async framework because VFS will answer the request
371 * out-of-order, when it knows that the operation succeeded or failed.
372 */
373
374 async_exch_t *exch = async_exchange_begin(sess);
375
376 ipc_call_t answer;
377 aid_t req = async_send_0(exch, VFS_IN_REGISTER, &answer);
378
379 /*
380 * Send our VFS info structure to VFS.
381 */
382 errno_t rc = async_data_write_start(exch, info, sizeof(*info));
383
384 if (rc != EOK) {
385 async_exchange_end(exch);
386 async_forget(req);
387 return rc;
388 }
389
390 /*
391 * Set VFS_OUT and libfs operations.
392 */
393 vfs_out_ops = vops;
394 libfs_ops = lops;
395
396 str_cpy(fs_name, sizeof(fs_name), info->name);
397
398 /*
399 * Ask VFS for callback connection.
400 */
401 port_id_t port;
402 rc = async_create_callback_port(exch, INTERFACE_VFS_DRIVER_CB, 0, 0,
403 vfs_connection, NULL, &port);
404
405 /*
406 * Request sharing the Path Lookup Buffer with VFS.
407 */
408 rc = async_share_in_start_0_0(exch, PLB_SIZE, (void *) &reg.plb_ro);
409 if (reg.plb_ro == AS_MAP_FAILED) {
410 async_exchange_end(exch);
411 async_forget(req);
412 return ENOMEM;
413 }
414
415 async_exchange_end(exch);
416
417 if (rc) {
418 async_forget(req);
419 return rc;
420 }
421
422 /*
423 * Pick up the answer for the request to the VFS_IN_REQUEST call.
424 */
425 async_wait_for(req, NULL);
426 reg.fs_handle = (int) IPC_GET_ARG1(answer);
427
428 return IPC_GET_RETVAL(answer);
429}
430
431void fs_node_initialize(fs_node_t *fn)
432{
433 memset(fn, 0, sizeof(fs_node_t));
434}
435
436static char plb_get_char(unsigned pos)
437{
438 return reg.plb_ro[pos % PLB_SIZE];
439}
440
441static errno_t plb_get_component(char *dest, unsigned *sz, unsigned *ppos,
442 unsigned last)
443{
444 unsigned pos = *ppos;
445 unsigned size = 0;
446
447 if (pos == last) {
448 *sz = 0;
449 return ERANGE;
450 }
451
452 char c = plb_get_char(pos);
453 if (c == '/')
454 pos++;
455
456 for (int i = 0; i <= NAME_MAX; i++) {
457 c = plb_get_char(pos);
458 if (pos == last || c == '/') {
459 dest[i] = 0;
460 *ppos = pos;
461 *sz = size;
462 return EOK;
463 }
464 dest[i] = c;
465 pos++;
466 size++;
467 }
468 return ENAMETOOLONG;
469}
470
471static errno_t receive_fname(char *buffer)
472{
473 ipc_call_t call;
474 size_t size;
475
476 if (!async_data_write_receive(&call, &size))
477 return ENOENT;
478
479 if (size > NAME_MAX + 1) {
480 async_answer_0(&call, ERANGE);
481 return ERANGE;
482 }
483
484 return async_data_write_finalize(&call, buffer, size);
485}
486
487/** Link a file at a path.
488 *
489 */
490void libfs_link(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_call_t *req)
491{
492 service_id_t parent_sid = IPC_GET_ARG1(*req);
493 fs_index_t parent_index = IPC_GET_ARG2(*req);
494 fs_index_t child_index = IPC_GET_ARG3(*req);
495
496 char component[NAME_MAX + 1];
497 errno_t rc = receive_fname(component);
498 if (rc != EOK) {
499 async_answer_0(req, rc);
500 return;
501 }
502
503 fs_node_t *parent = NULL;
504 rc = ops->node_get(&parent, parent_sid, parent_index);
505 if (parent == NULL) {
506 async_answer_0(req, rc == EOK ? EBADF : rc);
507 return;
508 }
509
510 fs_node_t *child = NULL;
511 rc = ops->node_get(&child, parent_sid, child_index);
512 if (child == NULL) {
513 async_answer_0(req, rc == EOK ? EBADF : rc);
514 ops->node_put(parent);
515 return;
516 }
517
518 rc = ops->link(parent, child, component);
519 ops->node_put(parent);
520 ops->node_put(child);
521 async_answer_0(req, rc);
522}
523
524/** Lookup VFS triplet by name in the file system name space.
525 *
526 * The path passed in the PLB must be in the canonical file system path format
527 * as returned by the canonify() function.
528 *
529 * @param ops libfs operations structure with function pointers to
530 * file system implementation
531 * @param fs_handle File system handle of the file system where to perform
532 * the lookup.
533 * @param req VFS_OUT_LOOKUP request data itself.
534 *
535 */
536void libfs_lookup(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_call_t *req)
537{
538 unsigned first = IPC_GET_ARG1(*req);
539 unsigned len = IPC_GET_ARG2(*req);
540 service_id_t service_id = IPC_GET_ARG3(*req);
541 fs_index_t index = IPC_GET_ARG4(*req);
542 int lflag = IPC_GET_ARG5(*req);
543
544 // TODO: Validate flags.
545
546 unsigned next = first;
547 unsigned last = first + len;
548
549 char component[NAME_MAX + 1];
550 errno_t rc;
551
552 fs_node_t *par = NULL;
553 fs_node_t *cur = NULL;
554 fs_node_t *tmp = NULL;
555 unsigned clen = 0;
556
557 rc = ops->node_get(&cur, service_id, index);
558 if (rc != EOK) {
559 async_answer_0(req, rc);
560 goto out;
561 }
562
563 assert(cur != NULL);
564
565 /* Find the file and its parent. */
566
567 unsigned last_next = 0;
568
569 while (next != last) {
570 if (cur == NULL) {
571 assert(par != NULL);
572 goto out1;
573 }
574
575 if (!ops->is_directory(cur)) {
576 async_answer_0(req, ENOTDIR);
577 goto out;
578 }
579
580 last_next = next;
581 /* Collect the component */
582 rc = plb_get_component(component, &clen, &next, last);
583 assert(rc != ERANGE);
584 if (rc != EOK) {
585 async_answer_0(req, rc);
586 goto out;
587 }
588
589 if (clen == 0) {
590 /* The path is just "/". */
591 break;
592 }
593
594 assert(component[clen] == 0);
595
596 /* Match the component */
597 rc = ops->match(&tmp, cur, component);
598 if (rc != EOK) {
599 async_answer_0(req, rc);
600 goto out;
601 }
602
603 /* Descend one level */
604 if (par) {
605 rc = ops->node_put(par);
606 if (rc != EOK) {
607 async_answer_0(req, rc);
608 goto out;
609 }
610 }
611
612 par = cur;
613 cur = tmp;
614 tmp = NULL;
615 }
616
617 /*
618 * At this point, par is either NULL or a directory.
619 * If cur is NULL, the looked up file does not exist yet.
620 */
621
622 assert(par == NULL || ops->is_directory(par));
623 assert(par != NULL || cur != NULL);
624
625 /* Check for some error conditions. */
626
627 if (cur && (lflag & L_FILE) && (ops->is_directory(cur))) {
628 async_answer_0(req, EISDIR);
629 goto out;
630 }
631
632 if (cur && (lflag & L_DIRECTORY) && (ops->is_file(cur))) {
633 async_answer_0(req, ENOTDIR);
634 goto out;
635 }
636
637 /* Unlink. */
638
639 if (lflag & L_UNLINK) {
640 if (!cur) {
641 async_answer_0(req, ENOENT);
642 goto out;
643 }
644 if (!par) {
645 async_answer_0(req, EINVAL);
646 goto out;
647 }
648
649 rc = ops->unlink(par, cur, component);
650 if (rc == EOK) {
651 aoff64_t size = ops->size_get(cur);
652 async_answer_5(req, EOK, fs_handle,
653 ops->index_get(cur),
654 (ops->is_directory(cur) << 16) | last,
655 LOWER32(size), UPPER32(size));
656 } else {
657 async_answer_0(req, rc);
658 }
659 goto out;
660 }
661
662 /* Create. */
663
664 if (lflag & L_CREATE) {
665 if (cur && (lflag & L_EXCLUSIVE)) {
666 async_answer_0(req, EEXIST);
667 goto out;
668 }
669
670 if (!cur) {
671 rc = ops->create(&cur, service_id,
672 lflag & (L_FILE | L_DIRECTORY));
673 if (rc != EOK) {
674 async_answer_0(req, rc);
675 goto out;
676 }
677 if (!cur) {
678 async_answer_0(req, ENOSPC);
679 goto out;
680 }
681
682 rc = ops->link(par, cur, component);
683 if (rc != EOK) {
684 (void) ops->destroy(cur);
685 cur = NULL;
686 async_answer_0(req, rc);
687 goto out;
688 }
689 }
690 }
691
692 /* Return. */
693out1:
694 if (!cur) {
695 async_answer_5(req, EOK, fs_handle, ops->index_get(par),
696 (ops->is_directory(par) << 16) | last_next,
697 LOWER32(ops->size_get(par)), UPPER32(ops->size_get(par)));
698 goto out;
699 }
700
701 async_answer_5(req, EOK, fs_handle, ops->index_get(cur),
702 (ops->is_directory(cur) << 16) | last, LOWER32(ops->size_get(cur)),
703 UPPER32(ops->size_get(cur)));
704
705out:
706 if (par)
707 (void) ops->node_put(par);
708
709 if (cur)
710 (void) ops->node_put(cur);
711
712 if (tmp)
713 (void) ops->node_put(tmp);
714}
715
716void libfs_stat(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_call_t *req)
717{
718 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
719 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
720
721 fs_node_t *fn;
722 errno_t rc = ops->node_get(&fn, service_id, index);
723 on_error(rc, answer_and_return(req, rc));
724
725 ipc_call_t call;
726 size_t size;
727 if ((!async_data_read_receive(&call, &size)) ||
728 (size != sizeof(vfs_stat_t))) {
729 ops->node_put(fn);
730 async_answer_0(&call, EINVAL);
731 async_answer_0(req, EINVAL);
732 return;
733 }
734
735 vfs_stat_t stat;
736 memset(&stat, 0, sizeof(vfs_stat_t));
737
738 stat.fs_handle = fs_handle;
739 stat.service_id = service_id;
740 stat.index = index;
741 stat.lnkcnt = ops->lnkcnt_get(fn);
742 stat.is_file = ops->is_file(fn);
743 stat.is_directory = ops->is_directory(fn);
744 stat.size = ops->size_get(fn);
745 stat.service = ops->service_get(fn);
746
747 ops->node_put(fn);
748
749 async_data_read_finalize(&call, &stat, sizeof(vfs_stat_t));
750 async_answer_0(req, EOK);
751}
752
753void libfs_statfs(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_call_t *req)
754{
755 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
756 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
757
758 fs_node_t *fn;
759 errno_t rc = ops->node_get(&fn, service_id, index);
760 on_error(rc, answer_and_return(req, rc));
761
762 ipc_call_t call;
763 size_t size;
764 if ((!async_data_read_receive(&call, &size)) ||
765 (size != sizeof(vfs_statfs_t))) {
766 goto error;
767 }
768
769 vfs_statfs_t st;
770 memset(&st, 0, sizeof(vfs_statfs_t));
771
772 str_cpy(st.fs_name, sizeof(st.fs_name), fs_name);
773
774 if (ops->size_block != NULL) {
775 rc = ops->size_block(service_id, &st.f_bsize);
776 if (rc != EOK)
777 goto error;
778 }
779
780 if (ops->total_block_count != NULL) {
781 rc = ops->total_block_count(service_id, &st.f_blocks);
782 if (rc != EOK)
783 goto error;
784 }
785
786 if (ops->free_block_count != NULL) {
787 rc = ops->free_block_count(service_id, &st.f_bfree);
788 if (rc != EOK)
789 goto error;
790 }
791
792 ops->node_put(fn);
793 async_data_read_finalize(&call, &st, sizeof(vfs_statfs_t));
794 async_answer_0(req, EOK);
795 return;
796
797error:
798 ops->node_put(fn);
799 async_answer_0(&call, EINVAL);
800 async_answer_0(req, EINVAL);
801}
802
803/** Open VFS triplet.
804 *
805 * @param ops libfs operations structure with function pointers to
806 * file system implementation
807 * @param req VFS_OUT_OPEN_NODE request data itself.
808 *
809 */
810void libfs_open_node(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_call_t *req)
811{
812 service_id_t service_id = IPC_GET_ARG1(*req);
813 fs_index_t index = IPC_GET_ARG2(*req);
814
815 fs_node_t *fn;
816 errno_t rc = ops->node_get(&fn, service_id, index);
817 on_error(rc, answer_and_return(req, rc));
818
819 if (fn == NULL) {
820 async_answer_0(req, ENOENT);
821 return;
822 }
823
824 rc = ops->node_open(fn);
825 aoff64_t size = ops->size_get(fn);
826 async_answer_4(req, rc, LOWER32(size), UPPER32(size),
827 ops->lnkcnt_get(fn),
828 (ops->is_file(fn) ? L_FILE : 0) |
829 (ops->is_directory(fn) ? L_DIRECTORY : 0));
830
831 (void) ops->node_put(fn);
832}
833
834static FIBRIL_MUTEX_INITIALIZE(instances_mutex);
835static LIST_INITIALIZE(instances_list);
836
837typedef struct {
838 service_id_t service_id;
839 link_t link;
840 void *data;
841} fs_instance_t;
842
843errno_t fs_instance_create(service_id_t service_id, void *data)
844{
845 fs_instance_t *inst = malloc(sizeof(fs_instance_t));
846 if (!inst)
847 return ENOMEM;
848
849 link_initialize(&inst->link);
850 inst->service_id = service_id;
851 inst->data = data;
852
853 fibril_mutex_lock(&instances_mutex);
854 list_foreach(instances_list, link, fs_instance_t, cur) {
855 if (cur->service_id == service_id) {
856 fibril_mutex_unlock(&instances_mutex);
857 free(inst);
858 return EEXIST;
859 }
860
861 /* keep the list sorted */
862 if (cur->service_id < service_id) {
863 list_insert_before(&inst->link, &cur->link);
864 fibril_mutex_unlock(&instances_mutex);
865 return EOK;
866 }
867 }
868 list_append(&inst->link, &instances_list);
869 fibril_mutex_unlock(&instances_mutex);
870
871 return EOK;
872}
873
874errno_t fs_instance_get(service_id_t service_id, void **idp)
875{
876 fibril_mutex_lock(&instances_mutex);
877
878 list_foreach(instances_list, link, fs_instance_t, inst) {
879 if (inst->service_id == service_id) {
880 *idp = inst->data;
881 fibril_mutex_unlock(&instances_mutex);
882 return EOK;
883 }
884 }
885
886 fibril_mutex_unlock(&instances_mutex);
887 return ENOENT;
888}
889
890errno_t fs_instance_destroy(service_id_t service_id)
891{
892 fibril_mutex_lock(&instances_mutex);
893
894 list_foreach(instances_list, link, fs_instance_t, inst) {
895 if (inst->service_id == service_id) {
896 list_remove(&inst->link);
897 fibril_mutex_unlock(&instances_mutex);
898 free(inst);
899 return EOK;
900 }
901 }
902
903 fibril_mutex_unlock(&instances_mutex);
904 return ENOENT;
905}
906
907/** @}
908 */
Note: See TracBrowser for help on using the repository browser.