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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b7c62a9 was b7c62a9, checked in by Jiri Zarevucky <zarevucky.jiri@…>, 12 years ago

Make the server oblivious to the link count. It is just another source of potential problems. Also clean up some confusion with file types and node refcount.

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