source: mainline/uspace/srv/vfs/vfs_ops.c@ 151f1cc

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 151f1cc was 9c4cf0d, checked in by Jakub Jermar <jakub@…>, 8 years ago

Rename close() to vfs_put()

This is motivated mainly by the fact that a file handle does not
necessarily correspond to an open file and close() was no longer the
the opposite operation to open().

  • Property mode set to 100644
File size: 20.4 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 ENOENT;
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 if (file->node->size == -1)
443 file->node->size = vfs_node_get_size(file->node);
444 pos = file->node->size;
445 }
446
447 /*
448 * Handle communication with the endpoint FS.
449 */
450 ipc_call_t answer;
451 int rc = ipc_cb(fs_exch, file, pos, &answer, read, ipc_cb_data);
452
453 vfs_exchange_release(fs_exch);
454
455 if (file->node->type == VFS_NODE_DIRECTORY)
456 fibril_rwlock_read_unlock(&namespace_rwlock);
457
458 /* Unlock the VFS node. */
459 if (rlock) {
460 fibril_rwlock_read_unlock(&file->node->contents_rwlock);
461 } else {
462 /* Update the cached version of node's size. */
463 if (rc == EOK) {
464 file->node->size = MERGE_LOUP32(IPC_GET_ARG2(answer),
465 IPC_GET_ARG3(answer));
466 }
467 fibril_rwlock_write_unlock(&file->node->contents_rwlock);
468 }
469
470 vfs_file_put(file);
471
472 return rc;
473}
474
475int vfs_rdwr_internal(int fd, aoff64_t pos, bool read, rdwr_io_chunk_t *chunk)
476{
477 return vfs_rdwr(fd, pos, read, rdwr_ipc_internal, chunk);
478}
479
480int vfs_op_read(int fd, aoff64_t pos, size_t *out_bytes)
481{
482 return vfs_rdwr(fd, pos, true, rdwr_ipc_client, out_bytes);
483}
484
485int vfs_op_rename(int basefd, char *old, char *new)
486{
487 vfs_file_t *base_file = vfs_file_get(basefd);
488 if (!base_file)
489 return EBADF;
490
491 vfs_node_t *base = base_file->node;
492 vfs_node_addref(base);
493 vfs_file_put(base_file);
494
495 vfs_lookup_res_t base_lr;
496 vfs_lookup_res_t old_lr;
497 vfs_lookup_res_t new_lr_orig;
498 bool orig_unlinked = false;
499
500 int rc;
501
502 size_t shared = shared_path(old, new);
503
504 /* Do not allow one path to be a prefix of the other. */
505 if (old[shared] == 0 || new[shared] == 0) {
506 vfs_node_put(base);
507 return EINVAL;
508 }
509 assert(old[shared] == '/');
510 assert(new[shared] == '/');
511
512 fibril_rwlock_write_lock(&namespace_rwlock);
513
514 /* Resolve the shared portion of the path first. */
515 if (shared != 0) {
516 old[shared] = 0;
517 rc = vfs_lookup_internal(base, old, L_DIRECTORY, &base_lr);
518 if (rc != EOK) {
519 vfs_node_put(base);
520 fibril_rwlock_write_unlock(&namespace_rwlock);
521 return rc;
522 }
523
524 vfs_node_put(base);
525 base = vfs_node_get(&base_lr);
526 if (!base) {
527 fibril_rwlock_write_unlock(&namespace_rwlock);
528 return ENOMEM;
529 }
530 old[shared] = '/';
531 old += shared;
532 new += shared;
533 }
534
535 rc = vfs_lookup_internal(base, old, L_DISABLE_MOUNTS, &old_lr);
536 if (rc != EOK) {
537 vfs_node_put(base);
538 fibril_rwlock_write_unlock(&namespace_rwlock);
539 return rc;
540 }
541
542 rc = vfs_lookup_internal(base, new, L_UNLINK | L_DISABLE_MOUNTS,
543 &new_lr_orig);
544 if (rc == EOK) {
545 orig_unlinked = true;
546 } else if (rc != ENOENT) {
547 vfs_node_put(base);
548 fibril_rwlock_write_unlock(&namespace_rwlock);
549 return rc;
550 }
551
552 rc = vfs_link_internal(base, new, &old_lr.triplet);
553 if (rc != EOK) {
554 vfs_link_internal(base, old, &old_lr.triplet);
555 if (orig_unlinked)
556 vfs_link_internal(base, new, &new_lr_orig.triplet);
557 vfs_node_put(base);
558 fibril_rwlock_write_unlock(&namespace_rwlock);
559 return rc;
560 }
561
562 rc = vfs_lookup_internal(base, old, L_UNLINK | L_DISABLE_MOUNTS,
563 &old_lr);
564 if (rc != EOK) {
565 if (orig_unlinked)
566 vfs_link_internal(base, new, &new_lr_orig.triplet);
567 vfs_node_put(base);
568 fibril_rwlock_write_unlock(&namespace_rwlock);
569 return rc;
570 }
571
572 /* If the node is not held by anyone, try to destroy it. */
573 if (orig_unlinked) {
574 vfs_node_t *node = vfs_node_peek(&new_lr_orig);
575 if (!node)
576 out_destroy(&new_lr_orig.triplet);
577 else
578 vfs_node_put(node);
579 }
580
581 vfs_node_put(base);
582 fibril_rwlock_write_unlock(&namespace_rwlock);
583 return EOK;
584}
585
586int vfs_op_resize(int fd, int64_t size)
587{
588 vfs_file_t *file = vfs_file_get(fd);
589 if (!file)
590 return EBADF;
591
592 fibril_rwlock_write_lock(&file->node->contents_rwlock);
593
594 int rc = vfs_truncate_internal(file->node->fs_handle,
595 file->node->service_id, file->node->index, size);
596 if (rc == EOK)
597 file->node->size = size;
598
599 fibril_rwlock_write_unlock(&file->node->contents_rwlock);
600 vfs_file_put(file);
601 return rc;
602}
603
604int vfs_op_stat(int fd)
605{
606 vfs_file_t *file = vfs_file_get(fd);
607 if (!file)
608 return EBADF;
609
610 vfs_node_t *node = file->node;
611
612 async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
613 int rc = async_data_read_forward_fast(exch, VFS_OUT_STAT,
614 node->service_id, node->index, true, 0, NULL);
615 vfs_exchange_release(exch);
616
617 vfs_file_put(file);
618 return rc;
619}
620
621int vfs_op_statfs(int fd)
622{
623 vfs_file_t *file = vfs_file_get(fd);
624 if (!file)
625 return EBADF;
626
627 vfs_node_t *node = file->node;
628
629 async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
630 int rc = async_data_read_forward_fast(exch, VFS_OUT_STATFS,
631 node->service_id, node->index, false, 0, NULL);
632 vfs_exchange_release(exch);
633
634 vfs_file_put(file);
635 return rc;
636}
637
638int vfs_op_sync(int fd)
639{
640 vfs_file_t *file = vfs_file_get(fd);
641 if (!file)
642 return EBADF;
643
644 async_exch_t *fs_exch = vfs_exchange_grab(file->node->fs_handle);
645
646 aid_t msg;
647 ipc_call_t answer;
648 msg = async_send_2(fs_exch, VFS_OUT_SYNC, file->node->service_id,
649 file->node->index, &answer);
650
651 vfs_exchange_release(fs_exch);
652
653 sysarg_t rc;
654 async_wait_for(msg, &rc);
655
656 vfs_file_put(file);
657 return rc;
658
659}
660
661static int vfs_truncate_internal(fs_handle_t fs_handle, service_id_t service_id,
662 fs_index_t index, aoff64_t size)
663{
664 async_exch_t *exch = vfs_exchange_grab(fs_handle);
665 sysarg_t rc = async_req_4_0(exch, VFS_OUT_TRUNCATE,
666 (sysarg_t) service_id, (sysarg_t) index, LOWER32(size),
667 UPPER32(size));
668 vfs_exchange_release(exch);
669
670 return (int) rc;
671}
672
673int vfs_op_unlink(int parentfd, int expectfd, char *path)
674{
675 int rc = EOK;
676 vfs_file_t *parent = NULL;
677 vfs_file_t *expect = NULL;
678
679 if (parentfd == expectfd)
680 return EINVAL;
681
682 fibril_rwlock_write_lock(&namespace_rwlock);
683
684 /*
685 * Files are retrieved in order of file descriptors, to prevent
686 * deadlock.
687 */
688 if (parentfd < expectfd) {
689 parent = vfs_file_get(parentfd);
690 if (!parent) {
691 rc = EBADF;
692 goto exit;
693 }
694 }
695
696 if (expectfd >= 0) {
697 expect = vfs_file_get(expectfd);
698 if (!expect) {
699 rc = EBADF;
700 goto exit;
701 }
702 }
703
704 if (parentfd > expectfd) {
705 parent = vfs_file_get(parentfd);
706 if (!parent) {
707 rc = EBADF;
708 goto exit;
709 }
710 }
711
712 assert(parent != NULL);
713
714 if (expectfd >= 0) {
715 vfs_lookup_res_t lr;
716 rc = vfs_lookup_internal(parent->node, path, 0, &lr);
717 if (rc != EOK)
718 goto exit;
719
720 vfs_node_t *found_node = vfs_node_peek(&lr);
721 vfs_node_put(found_node);
722 if (expect->node != found_node) {
723 rc = ENOENT;
724 goto exit;
725 }
726
727 vfs_file_put(expect);
728 expect = NULL;
729 }
730
731 vfs_lookup_res_t lr;
732 rc = vfs_lookup_internal(parent->node, path, L_UNLINK, &lr);
733 if (rc != EOK)
734 goto exit;
735
736 /* If the node is not held by anyone, try to destroy it. */
737 vfs_node_t *node = vfs_node_peek(&lr);
738 if (!node)
739 out_destroy(&lr.triplet);
740 else
741 vfs_node_put(node);
742
743exit:
744 if (path)
745 free(path);
746 if (parent)
747 vfs_file_put(parent);
748 if (expect)
749 vfs_file_put(expect);
750 fibril_rwlock_write_unlock(&namespace_rwlock);
751 return rc;
752}
753
754int vfs_op_unmount(int mpfd)
755{
756 vfs_file_t *mp = vfs_file_get(mpfd);
757 if (mp == NULL)
758 return EBADF;
759
760 if (mp->node->mount == NULL) {
761 vfs_file_put(mp);
762 return ENOENT;
763 }
764
765 fibril_rwlock_write_lock(&namespace_rwlock);
766
767 /*
768 * Count the total number of references for the mounted file system. We
769 * are expecting at least one, which is held by the mount point.
770 * If we find more, it means that
771 * the file system cannot be gracefully unmounted at the moment because
772 * someone is working with it.
773 */
774 if (vfs_nodes_refcount_sum_get(mp->node->mount->fs_handle,
775 mp->node->mount->service_id) != 1) {
776 vfs_file_put(mp);
777 fibril_rwlock_write_unlock(&namespace_rwlock);
778 return EBUSY;
779 }
780
781 async_exch_t *exch = vfs_exchange_grab(mp->node->mount->fs_handle);
782 int rc = async_req_1_0(exch, VFS_OUT_UNMOUNTED,
783 mp->node->mount->service_id);
784 vfs_exchange_release(exch);
785
786 if (rc != EOK) {
787 vfs_file_put(mp);
788 fibril_rwlock_write_unlock(&namespace_rwlock);
789 return rc;
790 }
791
792 vfs_node_forget(mp->node->mount);
793 vfs_node_put(mp->node);
794 mp->node->mount = NULL;
795
796 fibril_rwlock_write_unlock(&namespace_rwlock);
797
798 vfs_file_put(mp);
799 return EOK;
800}
801
802int vfs_op_wait_handle(bool high_fd)
803{
804 return vfs_wait_handle_internal(high_fd);
805}
806
807static inline bool walk_flags_valid(int flags)
808{
809 if ((flags & ~WALK_ALL_FLAGS) != 0)
810 return false;
811 if ((flags & WALK_MAY_CREATE) && (flags & WALK_MUST_CREATE))
812 return false;
813 if ((flags & WALK_REGULAR) && (flags & WALK_DIRECTORY))
814 return false;
815 if ((flags & WALK_MAY_CREATE) || (flags & WALK_MUST_CREATE)) {
816 if (!(flags & WALK_DIRECTORY) && !(flags & WALK_REGULAR))
817 return false;
818 }
819 return true;
820}
821
822static inline int walk_lookup_flags(int flags)
823{
824 int lflags = 0;
825 if ((flags & WALK_MAY_CREATE) || (flags & WALK_MUST_CREATE))
826 lflags |= L_CREATE;
827 if (flags & WALK_MUST_CREATE)
828 lflags |= L_EXCLUSIVE;
829 if (flags & WALK_REGULAR)
830 lflags |= L_FILE;
831 if (flags & WALK_DIRECTORY)
832 lflags |= L_DIRECTORY;
833 if (flags & WALK_MOUNT_POINT)
834 lflags |= L_MP;
835 return lflags;
836}
837
838int vfs_op_walk(int parentfd, int flags, char *path, int *out_fd)
839{
840 if (!walk_flags_valid(flags))
841 return EINVAL;
842
843 vfs_file_t *parent = vfs_file_get(parentfd);
844 if (!parent)
845 return EBADF;
846
847 fibril_rwlock_read_lock(&namespace_rwlock);
848
849 vfs_lookup_res_t lr;
850 int rc = vfs_lookup_internal(parent->node, path,
851 walk_lookup_flags(flags), &lr);
852 if (rc != EOK) {
853 fibril_rwlock_read_unlock(&namespace_rwlock);
854 vfs_file_put(parent);
855 return rc;
856 }
857
858 vfs_node_t *node = vfs_node_get(&lr);
859 if (!node) {
860 fibril_rwlock_read_unlock(&namespace_rwlock);
861 vfs_file_put(parent);
862 return ENOMEM;
863 }
864
865 vfs_file_t *file;
866 int fd = vfs_fd_alloc(&file, false);
867 if (fd < 0) {
868 vfs_node_put(node);
869 vfs_file_put(parent);
870 return fd;
871 }
872 assert(file != NULL);
873
874 file->node = node;
875 file->permissions = parent->permissions;
876 file->open_read = false;
877 file->open_write = false;
878
879 vfs_file_put(file);
880 vfs_file_put(parent);
881
882 fibril_rwlock_read_unlock(&namespace_rwlock);
883
884 *out_fd = fd;
885 return EOK;
886}
887
888int vfs_op_write(int fd, aoff64_t pos, size_t *out_bytes)
889{
890 return vfs_rdwr(fd, pos, false, rdwr_ipc_client, out_bytes);
891}
892
893/**
894 * @}
895 */
Note: See TracBrowser for help on using the repository browser.