source: mainline/uspace/srv/vfs/vfs_ops.c@ b14d9f9

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

Mount should be able to print the list of available file system types.

  • Property mode set to 100644
File size: 20.3 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/** @addtogroup fs
30 * @{
31 */
32
33/**
34 * @file vfs_ops.c
35 * @brief Operations that VFS offers to its clients.
36 */
37
38#include "vfs.h"
39#include <macros.h>
40#include <stdint.h>
41#include <async.h>
42#include <errno.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <str.h>
46#include <stdbool.h>
47#include <fibril_synch.h>
48#include <adt/list.h>
49#include <unistd.h>
50#include <ctype.h>
51#include <assert.h>
52#include <vfs/canonify.h>
53
54/* Forward declarations of static functions. */
55static int vfs_truncate_internal(fs_handle_t, service_id_t, fs_index_t,
56 aoff64_t);
57
58/**
59 * This rwlock prevents the race between a triplet-to-VFS-node resolution and a
60 * concurrent VFS operation which modifies the file system namespace.
61 */
62FIBRIL_RWLOCK_INITIALIZE(namespace_rwlock);
63
64static size_t shared_path(char *a, char *b)
65{
66 size_t res = 0;
67
68 while (a[res] == b[res] && a[res] != 0)
69 res++;
70
71 if (a[res] == b[res])
72 return res;
73
74 res--;
75 while (a[res] != '/')
76 res--;
77 return res;
78}
79
80/* This call destroys the file if and only if there are no hard links left. */
81static void out_destroy(vfs_triplet_t *file)
82{
83 async_exch_t *exch = vfs_exchange_grab(file->fs_handle);
84 async_msg_2(exch, VFS_OUT_DESTROY, (sysarg_t) file->service_id,
85 (sysarg_t) file->index);
86 vfs_exchange_release(exch);
87}
88
89int vfs_op_clone(int oldfd, int newfd, bool desc)
90{
91 int rc;
92
93 /* If the file descriptors are the same, do nothing. */
94 if (oldfd == newfd)
95 return EOK;
96
97 /* Lookup the file structure corresponding to fd. */
98 vfs_file_t *oldfile = vfs_file_get(oldfd);
99 if (oldfile == NULL)
100 return EBADF;
101
102 assert(oldfile->node != NULL);
103
104 if (newfd != -1) {
105 /* Make sure newfd is closed. */
106 (void) vfs_fd_free(newfd);
107 /* Assign the old file to newfd. */
108 rc = vfs_fd_assign(oldfile, newfd);
109 } else {
110 vfs_file_t *newfile;
111 int newfd = vfs_fd_alloc(&newfile, desc);
112 if (newfd >= 0) {
113 newfile->node = oldfile->node;
114 newfile->permissions = oldfile->permissions;
115 vfs_node_addref(newfile->node);
116
117 vfs_file_put(newfile);
118 }
119 rc = newfd;
120 }
121 vfs_file_put(oldfile);
122
123 return rc;
124}
125
126int vfs_op_put(int fd)
127{
128 return vfs_fd_free(fd);
129}
130
131static int vfs_connect_internal(service_id_t service_id, unsigned flags,
132 unsigned instance, const char *options, const char *fsname,
133 vfs_node_t **root)
134{
135 fs_handle_t fs_handle = 0;
136
137 fibril_mutex_lock(&fs_list_lock);
138 while (true) {
139 fs_handle = fs_name_to_handle(instance, fsname, false);
140
141 if (fs_handle != 0 || !(flags & VFS_MOUNT_BLOCKING))
142 break;
143
144 fibril_condvar_wait(&fs_list_cv, &fs_list_lock);
145 }
146 fibril_mutex_unlock(&fs_list_lock);
147
148 if (fs_handle == 0)
149 return ENOFS;
150
151 /* Tell the mountee that it is being mounted. */
152 ipc_call_t answer;
153 async_exch_t *exch = vfs_exchange_grab(fs_handle);
154 aid_t msg = async_send_1(exch, VFS_OUT_MOUNTED, (sysarg_t) service_id,
155 &answer);
156 /* Send the mount options */
157 sysarg_t rc = async_data_write_start(exch, options, str_size(options));
158 if (rc != EOK) {
159 async_forget(msg);
160 vfs_exchange_release(exch);
161 return rc;
162 }
163
164 async_wait_for(msg, &rc);
165 if (rc != EOK) {
166 vfs_exchange_release(exch);
167 return rc;
168 }
169
170 vfs_lookup_res_t res;
171 res.triplet.fs_handle = fs_handle;
172 res.triplet.service_id = service_id;
173 res.triplet.index = (fs_index_t) IPC_GET_ARG1(answer);
174 res.size = (int64_t) MERGE_LOUP32(IPC_GET_ARG2(answer),
175 IPC_GET_ARG3(answer));
176 res.type = VFS_NODE_DIRECTORY;
177
178 /* Add reference to the mounted root. */
179 *root = vfs_node_get(&res);
180 if (!*root) {
181 aid_t msg = async_send_1(exch, VFS_OUT_UNMOUNTED,
182 (sysarg_t) service_id, NULL);
183 async_forget(msg);
184 vfs_exchange_release(exch);
185 return ENOMEM;
186 }
187
188 vfs_exchange_release(exch);
189
190 return EOK;
191}
192
193int vfs_op_mount(int mpfd, unsigned service_id, unsigned flags,
194 unsigned instance, const char *opts, const char *fs_name, int *outfd)
195{
196 int rc;
197 vfs_file_t *mp = NULL;
198 vfs_file_t *file = NULL;
199 int fd = -1;
200
201 if (!(flags & VFS_MOUNT_CONNECT_ONLY)) {
202 mp = vfs_file_get(mpfd);
203 if (mp == NULL) {
204 rc = EBADF;
205 goto out;
206 }
207
208 if (mp->node->mount != NULL) {
209 rc = EBUSY;
210 goto out;
211 }
212
213 if (mp->node->type != VFS_NODE_DIRECTORY) {
214 rc = ENOTDIR;
215 goto out;
216 }
217
218 if (vfs_node_has_children(mp->node)) {
219 rc = ENOTEMPTY;
220 goto out;
221 }
222 }
223
224 if (!(flags & VFS_MOUNT_NO_REF)) {
225 fd = vfs_fd_alloc(&file, false);
226 if (fd < 0) {
227 rc = fd;
228 goto out;
229 }
230 }
231
232 vfs_node_t *root = NULL;
233
234 fibril_rwlock_write_lock(&namespace_rwlock);
235
236 rc = vfs_connect_internal(service_id, flags, instance, opts, fs_name,
237 &root);
238 if (rc == EOK && !(flags & VFS_MOUNT_CONNECT_ONLY)) {
239 vfs_node_addref(mp->node);
240 vfs_node_addref(root);
241 mp->node->mount = root;
242 }
243
244 fibril_rwlock_write_unlock(&namespace_rwlock);
245
246 if (rc != EOK)
247 goto out;
248
249 if (flags & VFS_MOUNT_NO_REF) {
250 vfs_node_delref(root);
251 } else {
252 assert(file != NULL);
253
254 file->node = root;
255 file->permissions = MODE_READ | MODE_WRITE | MODE_APPEND;
256 file->open_read = false;
257 file->open_write = false;
258 }
259
260out:
261 if (mp)
262 vfs_file_put(mp);
263 if (file)
264 vfs_file_put(file);
265
266 if (rc != EOK && fd >= 0) {
267 vfs_fd_free(fd);
268 fd = 0;
269 }
270
271 *outfd = fd;
272 return rc;
273}
274
275int vfs_op_open(int fd, int mode)
276{
277 if (mode == 0)
278 return EINVAL;
279
280 vfs_file_t *file = vfs_file_get(fd);
281 if (!file)
282 return EBADF;
283
284 if ((mode & ~file->permissions) != 0) {
285 vfs_file_put(file);
286 return EPERM;
287 }
288
289 if (file->open_read || file->open_write) {
290 vfs_file_put(file);
291 return EBUSY;
292 }
293
294 file->open_read = (mode & MODE_READ) != 0;
295 file->open_write = (mode & (MODE_WRITE | MODE_APPEND)) != 0;
296 file->append = (mode & MODE_APPEND) != 0;
297
298 if (!file->open_read && !file->open_write) {
299 vfs_file_put(file);
300 return EINVAL;
301 }
302
303 if (file->node->type == VFS_NODE_DIRECTORY && file->open_write) {
304 file->open_read = file->open_write = false;
305 vfs_file_put(file);
306 return EINVAL;
307 }
308
309 int rc = vfs_open_node_remote(file->node);
310 if (rc != EOK) {
311 file->open_read = file->open_write = false;
312 vfs_file_put(file);
313 return rc;
314 }
315
316 vfs_file_put(file);
317 return EOK;
318}
319
320typedef int (* rdwr_ipc_cb_t)(async_exch_t *, vfs_file_t *, aoff64_t,
321 ipc_call_t *, bool, void *);
322
323static int rdwr_ipc_client(async_exch_t *exch, vfs_file_t *file, aoff64_t pos,
324 ipc_call_t *answer, bool read, void *data)
325{
326 size_t *bytes = (size_t *) data;
327 int rc;
328
329 /*
330 * Make a VFS_READ/VFS_WRITE request at the destination FS server
331 * and forward the IPC_M_DATA_READ/IPC_M_DATA_WRITE request to the
332 * destination FS server. The call will be routed as if sent by
333 * ourselves. Note that call arguments are immutable in this case so we
334 * don't have to bother.
335 */
336
337 if (read) {
338 rc = async_data_read_forward_4_1(exch, VFS_OUT_READ,
339 file->node->service_id, file->node->index,
340 LOWER32(pos), UPPER32(pos), answer);
341 } else {
342 rc = async_data_write_forward_4_1(exch, VFS_OUT_WRITE,
343 file->node->service_id, file->node->index,
344 LOWER32(pos), UPPER32(pos), answer);
345 }
346
347 *bytes = IPC_GET_ARG1(*answer);
348 return rc;
349}
350
351static int rdwr_ipc_internal(async_exch_t *exch, vfs_file_t *file, aoff64_t pos,
352 ipc_call_t *answer, bool read, void *data)
353{
354 rdwr_io_chunk_t *chunk = (rdwr_io_chunk_t *) data;
355
356 if (exch == NULL)
357 return ENOENT;
358
359 aid_t msg = async_send_fast(exch, read ? VFS_OUT_READ : VFS_OUT_WRITE,
360 file->node->service_id, file->node->index, LOWER32(pos),
361 UPPER32(pos), answer);
362 if (msg == 0)
363 return EINVAL;
364
365 int retval = async_data_read_start(exch, chunk->buffer, chunk->size);
366 if (retval != EOK) {
367 async_forget(msg);
368 return retval;
369 }
370
371 sysarg_t rc;
372 async_wait_for(msg, &rc);
373
374 chunk->size = IPC_GET_ARG1(*answer);
375
376 return (int) rc;
377}
378
379static int vfs_rdwr(int fd, aoff64_t pos, bool read, rdwr_ipc_cb_t ipc_cb,
380 void *ipc_cb_data)
381{
382 /*
383 * The following code strongly depends on the fact that the files data
384 * structure can be only accessed by a single fibril and all file
385 * operations are serialized (i.e. the reads and writes cannot
386 * interleave and a file cannot be closed while it is being read).
387 *
388 * Additional synchronization needs to be added once the table of
389 * open files supports parallel access!
390 */
391
392 /* Lookup the file structure corresponding to the file descriptor. */
393 vfs_file_t *file = vfs_file_get(fd);
394 if (!file)
395 return EBADF;
396
397 if ((read && !file->open_read) || (!read && !file->open_write)) {
398 vfs_file_put(file);
399 return EINVAL;
400 }
401
402 vfs_info_t *fs_info = fs_handle_to_info(file->node->fs_handle);
403 assert(fs_info);
404
405 bool rlock = read ||
406 (fs_info->concurrent_read_write && fs_info->write_retains_size);
407
408 /*
409 * Lock the file's node so that no other client can read/write to it at
410 * the same time unless the FS supports concurrent reads/writes and its
411 * write implementation does not modify the file size.
412 */
413 if (rlock)
414 fibril_rwlock_read_lock(&file->node->contents_rwlock);
415 else
416 fibril_rwlock_write_lock(&file->node->contents_rwlock);
417
418 if (file->node->type == VFS_NODE_DIRECTORY) {
419 /*
420 * Make sure that no one is modifying the namespace
421 * while we are in readdir().
422 */
423
424 if (!read) {
425 if (rlock) {
426 fibril_rwlock_read_unlock(
427 &file->node->contents_rwlock);
428 } else {
429 fibril_rwlock_write_unlock(
430 &file->node->contents_rwlock);
431 }
432 vfs_file_put(file);
433 return EINVAL;
434 }
435
436 fibril_rwlock_read_lock(&namespace_rwlock);
437 }
438
439 async_exch_t *fs_exch = vfs_exchange_grab(file->node->fs_handle);
440
441 if (!read && file->append)
442 pos = file->node->size;
443
444 /*
445 * Handle communication with the endpoint FS.
446 */
447 ipc_call_t answer;
448 int rc = ipc_cb(fs_exch, file, pos, &answer, read, ipc_cb_data);
449
450 vfs_exchange_release(fs_exch);
451
452 if (file->node->type == VFS_NODE_DIRECTORY)
453 fibril_rwlock_read_unlock(&namespace_rwlock);
454
455 /* Unlock the VFS node. */
456 if (rlock) {
457 fibril_rwlock_read_unlock(&file->node->contents_rwlock);
458 } else {
459 /* Update the cached version of node's size. */
460 if (rc == EOK) {
461 file->node->size = MERGE_LOUP32(IPC_GET_ARG2(answer),
462 IPC_GET_ARG3(answer));
463 }
464 fibril_rwlock_write_unlock(&file->node->contents_rwlock);
465 }
466
467 vfs_file_put(file);
468
469 return rc;
470}
471
472int vfs_rdwr_internal(int fd, aoff64_t pos, bool read, rdwr_io_chunk_t *chunk)
473{
474 return vfs_rdwr(fd, pos, read, rdwr_ipc_internal, chunk);
475}
476
477int vfs_op_read(int fd, aoff64_t pos, size_t *out_bytes)
478{
479 return vfs_rdwr(fd, pos, true, rdwr_ipc_client, out_bytes);
480}
481
482int vfs_op_rename(int basefd, char *old, char *new)
483{
484 vfs_file_t *base_file = vfs_file_get(basefd);
485 if (!base_file)
486 return EBADF;
487
488 vfs_node_t *base = base_file->node;
489 vfs_node_addref(base);
490 vfs_file_put(base_file);
491
492 vfs_lookup_res_t base_lr;
493 vfs_lookup_res_t old_lr;
494 vfs_lookup_res_t new_lr_orig;
495 bool orig_unlinked = false;
496
497 int rc;
498
499 size_t shared = shared_path(old, new);
500
501 /* Do not allow one path to be a prefix of the other. */
502 if (old[shared] == 0 || new[shared] == 0) {
503 vfs_node_put(base);
504 return EINVAL;
505 }
506 assert(old[shared] == '/');
507 assert(new[shared] == '/');
508
509 fibril_rwlock_write_lock(&namespace_rwlock);
510
511 /* Resolve the shared portion of the path first. */
512 if (shared != 0) {
513 old[shared] = 0;
514 rc = vfs_lookup_internal(base, old, L_DIRECTORY, &base_lr);
515 if (rc != EOK) {
516 vfs_node_put(base);
517 fibril_rwlock_write_unlock(&namespace_rwlock);
518 return rc;
519 }
520
521 vfs_node_put(base);
522 base = vfs_node_get(&base_lr);
523 if (!base) {
524 fibril_rwlock_write_unlock(&namespace_rwlock);
525 return ENOMEM;
526 }
527 old[shared] = '/';
528 old += shared;
529 new += shared;
530 }
531
532 rc = vfs_lookup_internal(base, old, L_DISABLE_MOUNTS, &old_lr);
533 if (rc != EOK) {
534 vfs_node_put(base);
535 fibril_rwlock_write_unlock(&namespace_rwlock);
536 return rc;
537 }
538
539 rc = vfs_lookup_internal(base, new, L_UNLINK | L_DISABLE_MOUNTS,
540 &new_lr_orig);
541 if (rc == EOK) {
542 orig_unlinked = true;
543 } else if (rc != ENOENT) {
544 vfs_node_put(base);
545 fibril_rwlock_write_unlock(&namespace_rwlock);
546 return rc;
547 }
548
549 rc = vfs_link_internal(base, new, &old_lr.triplet);
550 if (rc != EOK) {
551 vfs_link_internal(base, old, &old_lr.triplet);
552 if (orig_unlinked)
553 vfs_link_internal(base, new, &new_lr_orig.triplet);
554 vfs_node_put(base);
555 fibril_rwlock_write_unlock(&namespace_rwlock);
556 return rc;
557 }
558
559 rc = vfs_lookup_internal(base, old, L_UNLINK | L_DISABLE_MOUNTS,
560 &old_lr);
561 if (rc != EOK) {
562 if (orig_unlinked)
563 vfs_link_internal(base, new, &new_lr_orig.triplet);
564 vfs_node_put(base);
565 fibril_rwlock_write_unlock(&namespace_rwlock);
566 return rc;
567 }
568
569 /* If the node is not held by anyone, try to destroy it. */
570 if (orig_unlinked) {
571 vfs_node_t *node = vfs_node_peek(&new_lr_orig);
572 if (!node)
573 out_destroy(&new_lr_orig.triplet);
574 else
575 vfs_node_put(node);
576 }
577
578 vfs_node_put(base);
579 fibril_rwlock_write_unlock(&namespace_rwlock);
580 return EOK;
581}
582
583int vfs_op_resize(int fd, int64_t size)
584{
585 vfs_file_t *file = vfs_file_get(fd);
586 if (!file)
587 return EBADF;
588
589 fibril_rwlock_write_lock(&file->node->contents_rwlock);
590
591 int rc = vfs_truncate_internal(file->node->fs_handle,
592 file->node->service_id, file->node->index, size);
593 if (rc == EOK)
594 file->node->size = size;
595
596 fibril_rwlock_write_unlock(&file->node->contents_rwlock);
597 vfs_file_put(file);
598 return rc;
599}
600
601int vfs_op_stat(int fd)
602{
603 vfs_file_t *file = vfs_file_get(fd);
604 if (!file)
605 return EBADF;
606
607 vfs_node_t *node = file->node;
608
609 async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
610 int rc = async_data_read_forward_fast(exch, VFS_OUT_STAT,
611 node->service_id, node->index, true, 0, NULL);
612 vfs_exchange_release(exch);
613
614 vfs_file_put(file);
615 return rc;
616}
617
618int vfs_op_statfs(int fd)
619{
620 vfs_file_t *file = vfs_file_get(fd);
621 if (!file)
622 return EBADF;
623
624 vfs_node_t *node = file->node;
625
626 async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
627 int rc = async_data_read_forward_fast(exch, VFS_OUT_STATFS,
628 node->service_id, node->index, false, 0, NULL);
629 vfs_exchange_release(exch);
630
631 vfs_file_put(file);
632 return rc;
633}
634
635int vfs_op_sync(int fd)
636{
637 vfs_file_t *file = vfs_file_get(fd);
638 if (!file)
639 return EBADF;
640
641 async_exch_t *fs_exch = vfs_exchange_grab(file->node->fs_handle);
642
643 aid_t msg;
644 ipc_call_t answer;
645 msg = async_send_2(fs_exch, VFS_OUT_SYNC, file->node->service_id,
646 file->node->index, &answer);
647
648 vfs_exchange_release(fs_exch);
649
650 sysarg_t rc;
651 async_wait_for(msg, &rc);
652
653 vfs_file_put(file);
654 return rc;
655
656}
657
658static int vfs_truncate_internal(fs_handle_t fs_handle, service_id_t service_id,
659 fs_index_t index, aoff64_t size)
660{
661 async_exch_t *exch = vfs_exchange_grab(fs_handle);
662 sysarg_t rc = async_req_4_0(exch, VFS_OUT_TRUNCATE,
663 (sysarg_t) service_id, (sysarg_t) index, LOWER32(size),
664 UPPER32(size));
665 vfs_exchange_release(exch);
666
667 return (int) rc;
668}
669
670int vfs_op_unlink(int parentfd, int expectfd, char *path)
671{
672 int rc = EOK;
673 vfs_file_t *parent = NULL;
674 vfs_file_t *expect = NULL;
675
676 if (parentfd == expectfd)
677 return EINVAL;
678
679 fibril_rwlock_write_lock(&namespace_rwlock);
680
681 /*
682 * Files are retrieved in order of file descriptors, to prevent
683 * deadlock.
684 */
685 if (parentfd < expectfd) {
686 parent = vfs_file_get(parentfd);
687 if (!parent) {
688 rc = EBADF;
689 goto exit;
690 }
691 }
692
693 if (expectfd >= 0) {
694 expect = vfs_file_get(expectfd);
695 if (!expect) {
696 rc = EBADF;
697 goto exit;
698 }
699 }
700
701 if (parentfd > expectfd) {
702 parent = vfs_file_get(parentfd);
703 if (!parent) {
704 rc = EBADF;
705 goto exit;
706 }
707 }
708
709 assert(parent != NULL);
710
711 if (expectfd >= 0) {
712 vfs_lookup_res_t lr;
713 rc = vfs_lookup_internal(parent->node, path, 0, &lr);
714 if (rc != EOK)
715 goto exit;
716
717 vfs_node_t *found_node = vfs_node_peek(&lr);
718 vfs_node_put(found_node);
719 if (expect->node != found_node) {
720 rc = ENOENT;
721 goto exit;
722 }
723
724 vfs_file_put(expect);
725 expect = NULL;
726 }
727
728 vfs_lookup_res_t lr;
729 rc = vfs_lookup_internal(parent->node, path, L_UNLINK, &lr);
730 if (rc != EOK)
731 goto exit;
732
733 /* If the node is not held by anyone, try to destroy it. */
734 vfs_node_t *node = vfs_node_peek(&lr);
735 if (!node)
736 out_destroy(&lr.triplet);
737 else
738 vfs_node_put(node);
739
740exit:
741 if (path)
742 free(path);
743 if (parent)
744 vfs_file_put(parent);
745 if (expect)
746 vfs_file_put(expect);
747 fibril_rwlock_write_unlock(&namespace_rwlock);
748 return rc;
749}
750
751int vfs_op_unmount(int mpfd)
752{
753 vfs_file_t *mp = vfs_file_get(mpfd);
754 if (mp == NULL)
755 return EBADF;
756
757 if (mp->node->mount == NULL) {
758 vfs_file_put(mp);
759 return ENOENT;
760 }
761
762 fibril_rwlock_write_lock(&namespace_rwlock);
763
764 /*
765 * Count the total number of references for the mounted file system. We
766 * are expecting at least one, which is held by the mount point.
767 * If we find more, it means that
768 * the file system cannot be gracefully unmounted at the moment because
769 * someone is working with it.
770 */
771 if (vfs_nodes_refcount_sum_get(mp->node->mount->fs_handle,
772 mp->node->mount->service_id) != 1) {
773 vfs_file_put(mp);
774 fibril_rwlock_write_unlock(&namespace_rwlock);
775 return EBUSY;
776 }
777
778 async_exch_t *exch = vfs_exchange_grab(mp->node->mount->fs_handle);
779 int rc = async_req_1_0(exch, VFS_OUT_UNMOUNTED,
780 mp->node->mount->service_id);
781 vfs_exchange_release(exch);
782
783 if (rc != EOK) {
784 vfs_file_put(mp);
785 fibril_rwlock_write_unlock(&namespace_rwlock);
786 return rc;
787 }
788
789 vfs_node_forget(mp->node->mount);
790 vfs_node_put(mp->node);
791 mp->node->mount = NULL;
792
793 fibril_rwlock_write_unlock(&namespace_rwlock);
794
795 vfs_file_put(mp);
796 return EOK;
797}
798
799int vfs_op_wait_handle(bool high_fd)
800{
801 return vfs_wait_handle_internal(high_fd);
802}
803
804static inline bool walk_flags_valid(int flags)
805{
806 if ((flags & ~WALK_ALL_FLAGS) != 0)
807 return false;
808 if ((flags & WALK_MAY_CREATE) && (flags & WALK_MUST_CREATE))
809 return false;
810 if ((flags & WALK_REGULAR) && (flags & WALK_DIRECTORY))
811 return false;
812 if ((flags & WALK_MAY_CREATE) || (flags & WALK_MUST_CREATE)) {
813 if (!(flags & WALK_DIRECTORY) && !(flags & WALK_REGULAR))
814 return false;
815 }
816 return true;
817}
818
819static inline int walk_lookup_flags(int flags)
820{
821 int lflags = 0;
822 if ((flags & WALK_MAY_CREATE) || (flags & WALK_MUST_CREATE))
823 lflags |= L_CREATE;
824 if (flags & WALK_MUST_CREATE)
825 lflags |= L_EXCLUSIVE;
826 if (flags & WALK_REGULAR)
827 lflags |= L_FILE;
828 if (flags & WALK_DIRECTORY)
829 lflags |= L_DIRECTORY;
830 if (flags & WALK_MOUNT_POINT)
831 lflags |= L_MP;
832 return lflags;
833}
834
835int vfs_op_walk(int parentfd, int flags, char *path, int *out_fd)
836{
837 if (!walk_flags_valid(flags))
838 return EINVAL;
839
840 vfs_file_t *parent = vfs_file_get(parentfd);
841 if (!parent)
842 return EBADF;
843
844 fibril_rwlock_read_lock(&namespace_rwlock);
845
846 vfs_lookup_res_t lr;
847 int rc = vfs_lookup_internal(parent->node, path,
848 walk_lookup_flags(flags), &lr);
849 if (rc != EOK) {
850 fibril_rwlock_read_unlock(&namespace_rwlock);
851 vfs_file_put(parent);
852 return rc;
853 }
854
855 vfs_node_t *node = vfs_node_get(&lr);
856 if (!node) {
857 fibril_rwlock_read_unlock(&namespace_rwlock);
858 vfs_file_put(parent);
859 return ENOMEM;
860 }
861
862 vfs_file_t *file;
863 int fd = vfs_fd_alloc(&file, false);
864 if (fd < 0) {
865 vfs_node_put(node);
866 vfs_file_put(parent);
867 return fd;
868 }
869 assert(file != NULL);
870
871 file->node = node;
872 file->permissions = parent->permissions;
873 file->open_read = false;
874 file->open_write = false;
875
876 vfs_file_put(file);
877 vfs_file_put(parent);
878
879 fibril_rwlock_read_unlock(&namespace_rwlock);
880
881 *out_fd = fd;
882 return EOK;
883}
884
885int vfs_op_write(int fd, aoff64_t pos, size_t *out_bytes)
886{
887 return vfs_rdwr(fd, pos, false, rdwr_ipc_client, out_bytes);
888}
889
890/**
891 * @}
892 */
Note: See TracBrowser for help on using the repository browser.