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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b688fd8 was b688fd8, checked in by Martin Decky <martin@…>, 10 years ago

gradually introduce async ports, initial phase

The initial phase is to reimplement the traditional async client connections as an untyped fallback port. This creates the possibility to introduce ports typed by interface type gradually in later changesets.

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