Changeset 368ee04 in mainline for uspace/srv


Ignore:
Timestamp:
2017-04-05T18:10:39Z (9 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
93ad8166
Parents:
39f892a9 (diff), 2166728 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge from lp:~jakub/helenos/vfs-2.5-cherrypick

This merge cherry-picks some of the changesets from Jiri Zarevucky's:

lp:~zarevucky-jiri/helenos/vfs-2.5

and then continues independently, yet sometime in a similar vein.

Roughly speaking, Jiri's branch is merged entirely up to its revision
1926 and then cherry-picked on and off until its revision 1965. Among
these changes are:

  • relativization of the API,
  • client-side roots,
  • server-side mounts,
  • inbox for passing arbitrary files from parent to child,
  • some streamlining and cleanup.

Additional changes include:

  • addressing issues introduced by the above changes,
  • client-side I/O cursors (file positions),
  • all HelenOS file system APIs begin with the vfs_ prefix and can be used after including vfs/vfs.h,
  • removal of some POSIX-ish headers and definitions,
  • additional cleanup.
Location:
uspace/srv
Files:
1 added
20 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/devman/driver.c

    r39f892a9 r368ee04  
    3333#include <dirent.h>
    3434#include <errno.h>
    35 #include <fcntl.h>
    36 #include <sys/stat.h>
    3735#include <io/log.h>
     36#include <vfs/vfs.h>
    3837#include <loc.h>
    3938#include <str_error.h>
     
    142141        /* Check whether the driver's binary exists. */
    143142        struct stat s;
    144         if (stat(drv->binary_path, &s) != 0) {
     143        if (vfs_stat_path(drv->binary_path, &s) != EOK) {
    145144                log_msg(LOG_DEFAULT, LVL_ERROR, "Driver not found at path `%s'.",
    146145                    drv->binary_path);
  • uspace/srv/devman/match.c

    r39f892a9 r368ee04  
    3232
    3333#include <errno.h>
    34 #include <fcntl.h>
    3534#include <io/log.h>
    3635#include <str.h>
    3736#include <str_error.h>
    3837#include <sys/types.h>
    39 #include <sys/stat.h>
     38#include <vfs/vfs.h>
    4039
    4140#include "devman.h"
     
    201200        int fd;
    202201        size_t len = 0;
    203        
    204         fd = open(conf_path, O_RDONLY);
     202        struct stat st;
     203       
     204        fd = vfs_lookup_open(conf_path, WALK_REGULAR, MODE_READ);
    205205        if (fd < 0) {
    206206                log_msg(LOG_DEFAULT, LVL_ERROR, "Unable to open `%s' for reading: %s.",
     
    210210        opened = true;
    211211       
    212         len = lseek(fd, 0, SEEK_END);
    213         lseek(fd, 0, SEEK_SET);
     212        if (vfs_stat(fd, &st) != EOK) {
     213                log_msg(LOG_DEFAULT, LVL_ERROR, "Unable to fstat %d: %s.", fd,
     214                    str_error(errno));
     215                goto cleanup;
     216        }
     217        len = st.size;
    214218        if (len == 0) {
    215219                log_msg(LOG_DEFAULT, LVL_ERROR, "Configuration file '%s' is empty.",
     
    225229        }
    226230       
    227         ssize_t read_bytes = read(fd, buf, len);
     231        ssize_t read_bytes = vfs_read(fd, (aoff64_t []) {0}, buf, len);
    228232        if (read_bytes <= 0) {
    229233                log_msg(LOG_DEFAULT, LVL_ERROR, "Unable to read file '%s' (%d).", conf_path,
     
    239243       
    240244        if (opened)
    241                 close(fd);
     245                vfs_put(fd);
    242246       
    243247        return suc;
  • uspace/srv/fs/fat/fat.h

    r39f892a9 r368ee04  
    4141#include <sys/types.h>
    4242#include <stdbool.h>
     43#include <macros.h>
    4344#include "../../vfs/vfs.h"
    4445
     
    4647#define dprintf(...)    printf(__VA_ARGS__)
    4748#endif
    48 
    49 #define min(a, b)       ((a) < (b) ? (a) : (b))
    5049
    5150/*
  • uspace/srv/fs/locfs/locfs_ops.c

    r39f892a9 r368ee04  
    4545#include <adt/hash_table.h>
    4646#include <ipc/loc.h>
    47 #include <sys/stat.h>
    4847#include <assert.h>
    4948#include "locfs.h"
  • uspace/srv/fs/mfs/mfs.h

    r39f892a9 r368ee04  
    4545#include <assert.h>
    4646#include <stdbool.h>
     47#include <macros.h>
    4748#include "../../vfs/vfs.h"
    4849
     
    5051
    5152/* #define DEBUG_MODE */
    52 
    53 #define min(a, b)       ((a) < (b) ? (a) : (b))
    5453
    5554#ifdef DEBUG_MODE
  • uspace/srv/fs/tmpfs/tmpfs_ops.c

    r39f892a9 r368ee04  
    5454#include <libfs.h>
    5555
    56 #define min(a, b)               ((a) < (b) ? (a) : (b))
    57 #define max(a, b)               ((a) > (b) ? (a) : (b))
    58 
    5956/** All root nodes have index 0. */
    6057#define TMPFS_SOME_ROOT         0
  • uspace/srv/hid/input/ctl/kbdev.c

    r39f892a9 r368ee04  
    3939#include <stdbool.h>
    4040#include <errno.h>
    41 #include <fcntl.h>
    4241#include <io/console.h>
    4342#include <io/keycode.h>
  • uspace/srv/hid/input/port/adb.c

    r39f892a9 r368ee04  
    3838#include <async.h>
    3939#include <vfs/vfs.h>
    40 #include <fcntl.h>
    4140#include <errno.h>
    4241#include <loc.h>
  • uspace/srv/hid/input/proto/mousedev.c

    r39f892a9 r368ee04  
    3737
    3838#include <stdio.h>
    39 #include <fcntl.h>
    4039#include <vfs/vfs_sess.h>
    4140#include <malloc.h>
  • uspace/srv/loader/main.c

    r39f892a9 r368ee04  
    4848#include <unistd.h>
    4949#include <stdbool.h>
    50 #include <fcntl.h>
    5150#include <sys/types.h>
    5251#include <ipc/services.h>
     
    6261#include <elf/elf_load.h>
    6362#include <vfs/vfs.h>
     63#include <vfs/inbox.h>
    6464
    6565#define DPRINTF(...)
    6666
    67 /** Pathname of the file that will be loaded */
    68 static char *pathname = NULL;
     67/** File that will be loaded */
     68static char *progname = NULL;
     69static int program_fd = -1;
    6970
    7071/** The Program control block */
     
    8182static char *arg_buf = NULL;
    8283
    83 /** Number of preset files */
    84 static unsigned int filc = 0;
     84/** Inbox entries. */
     85static struct pcb_inbox_entry inbox[INBOX_MAX_ENTRIES];
     86static int inbox_entries = 0;
    8587
    8688static elf_info_t prog_info;
     
    130132}
    131133
    132 /** Receive a call setting pathname of the program to execute.
    133  *
    134  * @param rid
    135  * @param request
    136  */
    137 static void ldr_set_pathname(ipc_callid_t rid, ipc_call_t *request)
    138 {
    139         char *buf;
    140         int rc = async_data_write_accept((void **) &buf, true, 0, 0, 0, NULL);
    141        
    142         if (rc == EOK) {
    143                 if (pathname != NULL)
    144                         free(pathname);
    145                
    146                 pathname = buf;
    147         }
    148        
    149         async_answer_0(rid, rc);
     134/** Receive a call setting the program to execute.
     135 *
     136 * @param rid
     137 * @param request
     138 */
     139static void ldr_set_program(ipc_callid_t rid, ipc_call_t *request)
     140{
     141        ipc_callid_t writeid;
     142        size_t namesize;
     143        if (!async_data_write_receive(&writeid, &namesize)) {
     144                async_answer_0(rid, EINVAL);
     145                return;
     146        }
     147
     148        char* name = malloc(namesize);
     149        int rc = async_data_write_finalize(writeid, name, namesize);
     150        if (rc != EOK) {
     151                async_answer_0(rid, EINVAL);
     152                return;
     153        }
     154
     155        int file = vfs_receive_handle(true);
     156        if (file < 0) {
     157                async_answer_0(rid, EINVAL);
     158                return;
     159        }
     160       
     161        progname = name;
     162        program_fd = file;
     163        async_answer_0(rid, EOK);
    150164}
    151165
     
    215229}
    216230
    217 /** Receive a call setting preset files of the program to execute.
    218  *
    219  * @param rid
    220  * @param request
    221  */
    222 static void ldr_set_files(ipc_callid_t rid, ipc_call_t *request)
    223 {
    224         size_t count = IPC_GET_ARG1(*request);
    225 
    226         async_exch_t *vfs_exch = vfs_exchange_begin();
    227 
    228         for (filc = 0; filc < count; filc++) {
    229                 ipc_callid_t callid;
    230                 int fd;
    231 
    232                 if (!async_state_change_receive(&callid, NULL, NULL, NULL)) {
    233                         async_answer_0(callid, EINVAL);
    234                         break;
    235                 }
    236                 async_state_change_finalize(callid, vfs_exch);
    237                 fd = vfs_fd_wait();
    238                 assert(fd == (int) filc);
    239         }
    240 
    241         vfs_exchange_end(vfs_exch);
    242 
     231/** Receive a call setting inbox files of the program to execute.
     232 *
     233 * @param rid
     234 * @param request
     235 */
     236static void ldr_add_inbox(ipc_callid_t rid, ipc_call_t *request)
     237{
     238        if (inbox_entries == INBOX_MAX_ENTRIES) {
     239                async_answer_0(rid, ERANGE);
     240                return;
     241        }
     242
     243        ipc_callid_t writeid;
     244        size_t namesize;
     245        if (!async_data_write_receive(&writeid, &namesize)) {
     246                async_answer_0(rid, EINVAL);
     247                return;
     248        }
     249
     250        char* name = malloc(namesize);
     251        int rc = async_data_write_finalize(writeid, name, namesize);
     252        if (rc != EOK) {
     253                async_answer_0(rid, EINVAL);
     254                return;
     255        }
     256
     257        int file = vfs_receive_handle(true);
     258        if (file < 0) {
     259                async_answer_0(rid, EINVAL);
     260                return;
     261        }
     262
     263        /*
     264         * We need to set the root early for dynamically linked binaries so
     265         * that the loader can use it too.
     266         */
     267        if (str_cmp(name, "root") == 0)
     268                vfs_root_set(file);
     269
     270        inbox[inbox_entries].name = name;
     271        inbox[inbox_entries].file = file;
     272        inbox_entries++;
    243273        async_answer_0(rid, EOK);
    244274}
     
    252282static int ldr_load(ipc_callid_t rid, ipc_call_t *request)
    253283{
    254         int rc;
    255        
    256         rc = elf_load(pathname, &prog_info);
     284        int rc = elf_load(program_fd, &prog_info);
    257285        if (rc != EE_OK) {
    258                 DPRINTF("Failed to load executable '%s'.\n", pathname);
     286                DPRINTF("Failed to load executable for '%s'.\n", progname);
    259287                async_answer_0(rid, EINVAL);
    260288                return 1;
     
    268296        pcb.argv = argv;
    269297       
    270         pcb.filc = filc;
     298        pcb.inbox = inbox;
     299        pcb.inbox_entries = inbox_entries;
    271300       
    272301        async_answer_0(rid, rc);
     
    282311static void ldr_run(ipc_callid_t rid, ipc_call_t *request)
    283312{
    284         const char *cp;
    285        
    286313        DPRINTF("Set task name\n");
    287314
    288315        /* Set the task name. */
    289         cp = str_rchr(pathname, '/');
    290         cp = (cp == NULL) ? pathname : (cp + 1);
    291         task_set_name(cp);
     316        task_set_name(progname);
    292317       
    293318        /* Run program */
     
    336361                        ldr_set_cwd(callid, &call);
    337362                        continue;
    338                 case LOADER_SET_PATHNAME:
    339                         ldr_set_pathname(callid, &call);
     363                case LOADER_SET_PROGRAM:
     364                        ldr_set_program(callid, &call);
    340365                        continue;
    341366                case LOADER_SET_ARGS:
    342367                        ldr_set_args(callid, &call);
    343368                        continue;
    344                 case LOADER_SET_FILES:
    345                         ldr_set_files(callid, &call);
     369                case LOADER_ADD_INBOX:
     370                        ldr_add_inbox(callid, &call);
    346371                        continue;
    347372                case LOADER_LOAD:
  • uspace/srv/logger/ctl.c

    r39f892a9 r368ee04  
    4141#include <io/logctl.h>
    4242#include <ipc/logger.h>
     43#include <vfs/vfs.h>
    4344#include "logger.h"
    4445
     
    8687                        break;
    8788                }
     89                case LOGGER_CONTROL_SET_ROOT: {
     90                        int fd = vfs_receive_handle(true);
     91                        vfs_root_set(fd);
     92                        async_answer_0(callid, fd >= 0 ? EOK : fd);
     93                        break;
     94                }
    8895                default:
    8996                        async_answer_0(callid, EINVAL);
  • uspace/srv/vfs/Makefile

    r39f892a9 r368ee04  
    3939        vfs_lookup.c \
    4040        vfs_register.c \
     41        vfs_ipc.c \
    4142        vfs_pager.c
    4243
  • uspace/srv/vfs/vfs.c

    r39f892a9 r368ee04  
    7676}
    7777
    78 static void vfs_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
    79 {
    80         bool cont = true;
    81        
    82         /*
    83          * The connection was opened via the IPC_CONNECT_ME_TO call.
    84          * This call needs to be answered.
    85          */
    86         async_answer_0(iid, EOK);
    87        
    88         while (cont) {
    89                 ipc_call_t call;
    90                 ipc_callid_t callid = async_get_call(&call);
    91                
    92                 if (!IPC_GET_IMETHOD(call))
    93                         break;
    94                
    95                 switch (IPC_GET_IMETHOD(call)) {
    96                 case VFS_IN_REGISTER:
    97                         vfs_register(callid, &call);
    98                         cont = false;
    99                         break;
    100                 case VFS_IN_MOUNT:
    101                         vfs_mount_srv(callid, &call);
    102                         break;
    103                 case VFS_IN_UNMOUNT:
    104                         vfs_unmount_srv(callid, &call);
    105                         break;
    106                 case VFS_IN_OPEN:
    107                         vfs_open(callid, &call);
    108                         break;
    109                 case VFS_IN_CLOSE:
    110                         vfs_close(callid, &call);
    111                         break;
    112                 case VFS_IN_READ:
    113                         vfs_read(callid, &call);
    114                         break;
    115                 case VFS_IN_WRITE:
    116                         vfs_write(callid, &call);
    117                         break;
    118                 case VFS_IN_SEEK:
    119                         vfs_seek(callid, &call);
    120                         break;
    121                 case VFS_IN_TRUNCATE:
    122                         vfs_truncate(callid, &call);
    123                         break;
    124                 case VFS_IN_FSTAT:
    125                         vfs_fstat(callid, &call);
    126                         break;
    127                 case VFS_IN_STAT:
    128                         vfs_stat(callid, &call);
    129                         break;
    130                 case VFS_IN_MKDIR:
    131                         vfs_mkdir(callid, &call);
    132                         break;
    133                 case VFS_IN_UNLINK:
    134                         vfs_unlink(callid, &call);
    135                         break;
    136                 case VFS_IN_RENAME:
    137                         vfs_rename(callid, &call);
    138                         break;
    139                 case VFS_IN_SYNC:
    140                         vfs_sync(callid, &call);
    141                         break;
    142                 case VFS_IN_DUP:
    143                         vfs_dup(callid, &call);
    144                         break;
    145                 case VFS_IN_WAIT_HANDLE:
    146                         vfs_wait_handle(callid, &call);
    147                         break;
    148                 case VFS_IN_MTAB_GET:
    149                         vfs_get_mtab(callid, &call);
    150                         break;
    151                 case VFS_IN_STATFS:
    152                         vfs_statfs(callid, &call);
    153                         break;
    154                 default:
    155                         async_answer_0(callid, ENOTSUP);
    156                         break;
    157                 }
    158         }
    159        
    160         /*
    161          * Open files for this client will be cleaned up when its last
    162          * connection fibril terminates.
    163          */
    164 }
    165 
    16678static void notification_handler(ipc_callid_t callid, ipc_call_t *call, void *arg)
    16779{
    16880        if (IPC_GET_ARG1(*call) == VFS_PASS_HANDLE)
    169                 vfs_pass_handle(
     81                vfs_op_pass_handle(
    17082                    (task_id_t) MERGE_LOUP32(IPC_GET_ARG4(*call),
    17183                    IPC_GET_ARG5(*call)), call->in_task_id,
  • uspace/srv/vfs/vfs.h

    r39f892a9 r368ee04  
    9494        vfs_node_type_t type;
    9595        aoff64_t size;
    96         unsigned int lnkcnt;
    9796} vfs_lookup_res_t;
    9897
     
    101100 * which may be associated with it.
    102101 */
    103 typedef struct {
     102typedef struct _vfs_node {
    104103        VFS_TRIPLET;            /**< Identity of the node. */
    105104
     
    110109        unsigned refcnt;
    111110       
    112         /** Number of names this node has in the file system namespace. */
    113         unsigned lnkcnt;
    114 
    115111        ht_link_t nh_link;              /**< Node hash-table link. */
    116112
     
    123119         */
    124120        fibril_rwlock_t contents_rwlock;
     121       
     122        struct _vfs_node *mount;
    125123} vfs_node_t;
    126124
     
    131129typedef struct {
    132130        /** Serializes access to this open file. */
    133         fibril_mutex_t lock;
     131        fibril_mutex_t _lock;
    134132
    135133        vfs_node_t *node;
     
    138136        unsigned refcnt;
    139137
     138        int permissions;
     139        bool open_read;
     140        bool open_write;
     141
    140142        /** Append on write. */
    141143        bool append;
    142 
    143         /** Current absolute position in the file. */
    144         aoff64_t pos;
    145144} vfs_file_t;
    146145
     
    173172extern void vfs_exchange_release(async_exch_t *);
    174173
    175 extern fs_handle_t fs_name_to_handle(unsigned int instance, char *, bool);
     174extern fs_handle_t fs_name_to_handle(unsigned int instance, const char *, bool);
    176175extern vfs_info_t *fs_handle_to_info(fs_handle_t);
    177176
    178 extern int vfs_lookup_internal(char *, int, vfs_lookup_res_t *,
    179     vfs_pair_t *, ...);
     177extern int vfs_lookup_internal(vfs_node_t *, char *, int, vfs_lookup_res_t *);
     178extern int vfs_link_internal(vfs_node_t *, char *, vfs_triplet_t *);
    180179
    181180extern bool vfs_nodes_init(void);
    182181extern vfs_node_t *vfs_node_get(vfs_lookup_res_t *);
     182extern vfs_node_t *vfs_node_peek(vfs_lookup_res_t *result);
    183183extern void vfs_node_put(vfs_node_t *);
    184184extern void vfs_node_forget(vfs_node_t *);
    185185extern unsigned vfs_nodes_refcount_sum_get(fs_handle_t, service_id_t);
    186186
    187 
    188 #define MAX_OPEN_FILES  128
     187extern bool vfs_node_has_children(vfs_node_t *node);
    189188
    190189extern void *vfs_client_data_create(void);
    191190extern void vfs_client_data_destroy(void *);
    192191
    193 extern void vfs_pass_handle(task_id_t, task_id_t, int);
    194 extern int vfs_wait_handle_internal(void);
     192extern void vfs_op_pass_handle(task_id_t, task_id_t, int);
     193extern int vfs_wait_handle_internal(bool);
    195194
    196195extern vfs_file_t *vfs_file_get(int);
    197196extern void vfs_file_put(vfs_file_t *);
    198197extern int vfs_fd_assign(vfs_file_t *, int);
    199 extern int vfs_fd_alloc(bool desc);
     198extern int vfs_fd_alloc(vfs_file_t **file, bool desc);
    200199extern int vfs_fd_free(int);
    201200
     
    204203extern int vfs_open_node_remote(vfs_node_t *);
    205204
     205extern int vfs_op_clone(int oldfd, int newfd, bool desc);
     206extern int vfs_op_mount(int mpfd, unsigned servid, unsigned flags, unsigned instance, const char *opts, const char *fsname, int *outfd);
     207extern int vfs_op_mtab_get(void);
     208extern int vfs_op_open(int fd, int flags);
     209extern int vfs_op_put(int fd);
     210extern int vfs_op_read(int fd, aoff64_t, size_t *out_bytes);
     211extern int vfs_op_rename(int basefd, char *old, char *new);
     212extern int vfs_op_resize(int fd, int64_t size);
     213extern int vfs_op_stat(int fd);
     214extern int vfs_op_statfs(int fd);
     215extern int vfs_op_sync(int fd);
     216extern int vfs_op_unlink(int parentfd, int expectfd, char *path);
     217extern int vfs_op_unmount(int mpfd);
     218extern int vfs_op_wait_handle(bool high_fd);
     219extern int vfs_op_walk(int parentfd, int flags, char *path, int *out_fd);
     220extern int vfs_op_write(int fd, aoff64_t, size_t *out_bytes);
     221
    206222extern void vfs_register(ipc_callid_t, ipc_call_t *);
    207 extern void vfs_mount_srv(ipc_callid_t, ipc_call_t *);
    208 extern void vfs_unmount_srv(ipc_callid_t, ipc_call_t *);
    209 extern void vfs_open(ipc_callid_t, ipc_call_t *);
    210 extern void vfs_sync(ipc_callid_t, ipc_call_t *);
    211 extern void vfs_dup(ipc_callid_t, ipc_call_t *);
    212 extern void vfs_close(ipc_callid_t, ipc_call_t *);
    213 extern void vfs_read(ipc_callid_t, ipc_call_t *);
    214 extern void vfs_write(ipc_callid_t, ipc_call_t *);
    215 extern void vfs_seek(ipc_callid_t, ipc_call_t *);
    216 extern void vfs_truncate(ipc_callid_t, ipc_call_t *);
    217 extern void vfs_fstat(ipc_callid_t, ipc_call_t *);
    218 extern void vfs_stat(ipc_callid_t, ipc_call_t *);
    219 extern void vfs_mkdir(ipc_callid_t, ipc_call_t *);
    220 extern void vfs_unlink(ipc_callid_t, ipc_call_t *);
    221 extern void vfs_rename(ipc_callid_t, ipc_call_t *);
    222 extern void vfs_wait_handle(ipc_callid_t, ipc_call_t *);
    223 extern void vfs_get_mtab(ipc_callid_t, ipc_call_t *);
    224 extern void vfs_statfs(ipc_callid_t, ipc_call_t *);
    225223
    226224extern void vfs_page_in(ipc_callid_t, ipc_call_t *);
     
    231229} rdwr_io_chunk_t;
    232230
    233 extern int vfs_rdwr_internal(int, bool, rdwr_io_chunk_t *);
     231extern int vfs_rdwr_internal(int, aoff64_t, bool, rdwr_io_chunk_t *);
     232
     233extern void vfs_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg);
    234234
    235235#endif
  • uspace/srv/vfs/vfs_file.c

    r39f892a9 r368ee04  
    4545#include <adt/list.h>
    4646#include <task.h>
     47#include <vfs/vfs.h>
    4748#include "vfs.h"
    4849
     
    5960typedef struct {
    6061        link_t link;
    61         int handle;
     62        vfs_node_t *node;
     63        int permissions;
    6264} vfs_boxed_handle_t;
    6365
     
    177179                 * endpoint FS and drop our reference to the underlying VFS node.
    178180                 */
    179                 rc = vfs_file_close_remote(file);
    180                 vfs_node_delref(file->node);
     181               
     182                if (file->node != NULL) {
     183                        if (file->open_read || file->open_write) {
     184                                rc = vfs_file_close_remote(file);
     185                        }
     186                        vfs_node_delref(file->node);
     187                }
    181188                free(file);
    182189        }
     
    185192}
    186193
    187 static int _vfs_fd_alloc(vfs_client_data_t *vfs_data, bool desc)
     194static int _vfs_fd_alloc(vfs_client_data_t *vfs_data, vfs_file_t **file, bool desc)
    188195{
    189196        if (!vfs_files_init(vfs_data))
     
    205212                        }
    206213                       
     214                       
    207215                        memset(vfs_data->files[i], 0, sizeof(vfs_file_t));
    208                         fibril_mutex_initialize(&vfs_data->files[i]->lock);
     216                       
     217                        fibril_mutex_initialize(&vfs_data->files[i]->_lock);
     218                        fibril_mutex_lock(&vfs_data->files[i]->_lock);
    209219                        vfs_file_addref(vfs_data, vfs_data->files[i]);
     220                       
     221                        *file = vfs_data->files[i];
     222                        vfs_file_addref(vfs_data, *file);
     223                       
    210224                        fibril_mutex_unlock(&vfs_data->lock);
    211225                        return (int) i;
     
    231245/** Allocate a file descriptor.
    232246 *
     247 * @param file Is set to point to the newly created file structure. Must be put afterwards.
    233248 * @param desc If true, look for an available file descriptor
    234249 *             in a descending order.
     
    237252 *         code.
    238253 */
    239 int vfs_fd_alloc(bool desc)
    240 {
    241         return _vfs_fd_alloc(VFS_DATA, desc);
     254int vfs_fd_alloc(vfs_file_t **file, bool desc)
     255{
     256        return _vfs_fd_alloc(VFS_DATA, file, desc);
    242257}
    243258
     
    289304
    290305        fibril_mutex_lock(&VFS_DATA->lock);     
    291         if ((fd < 0) || (fd >= MAX_OPEN_FILES) || (FILES[fd] != NULL)) {
     306        if ((fd < 0) || (fd >= MAX_OPEN_FILES)) {
    292307                fibril_mutex_unlock(&VFS_DATA->lock);
    293                 return EINVAL;
     308                return EBADF;
     309        }
     310        if (FILES[fd] != NULL) {
     311                fibril_mutex_unlock(&VFS_DATA->lock);
     312                return EEXIST;
    294313        }
    295314       
     
    299318       
    300319        return EOK;
     320}
     321
     322static void _vfs_file_put(vfs_client_data_t *vfs_data, vfs_file_t *file)
     323{
     324        fibril_mutex_unlock(&file->_lock);
     325       
     326        fibril_mutex_lock(&vfs_data->lock);
     327        vfs_file_delref(vfs_data, file);
     328        fibril_mutex_unlock(&vfs_data->lock);
    301329}
    302330
     
    312340                        vfs_file_addref(vfs_data, file);
    313341                        fibril_mutex_unlock(&vfs_data->lock);
     342                       
     343                        fibril_mutex_lock(&file->_lock);
     344                        if (file->node == NULL) {
     345                                _vfs_file_put(vfs_data, file);
     346                                return NULL;
     347                        }
     348                        assert(file != NULL);
     349                        assert(file->node != NULL);
    314350                        return file;
    315351                }
     
    331367}
    332368
    333 static void _vfs_file_put(vfs_client_data_t *vfs_data, vfs_file_t *file)
    334 {
    335         fibril_mutex_lock(&vfs_data->lock);
    336         vfs_file_delref(vfs_data, file);
    337         fibril_mutex_unlock(&vfs_data->lock);
    338 }
    339 
    340369/** Stop using a file structure.
    341370 *
     
    347376}
    348377
    349 void vfs_pass_handle(task_id_t donor_id, task_id_t acceptor_id, int donor_fd)
     378void vfs_op_pass_handle(task_id_t donor_id, task_id_t acceptor_id, int donor_fd)
    350379{
    351380        vfs_client_data_t *donor_data = NULL;
    352381        vfs_client_data_t *acceptor_data = NULL;
    353382        vfs_file_t *donor_file = NULL;
    354         vfs_file_t *acceptor_file = NULL;
    355383        vfs_boxed_handle_t *bh;
    356         int acceptor_fd;
    357384
    358385        acceptor_data = async_get_client_data_by_id(acceptor_id);
     
    364391
    365392        link_initialize(&bh->link);
    366         bh->handle = -1;
     393        bh->node = NULL;
    367394
    368395        donor_data = async_get_client_data_by_id(donor_id);
     
    373400        if (!donor_file)
    374401                goto out;
    375 
    376         acceptor_fd = _vfs_fd_alloc(acceptor_data, false);
    377         if (acceptor_fd < 0)
    378                 goto out;
    379 
    380         bh->handle = acceptor_fd;
    381402
    382403        /*
     
    384405         */
    385406        vfs_node_addref(donor_file->node);
    386         (void) vfs_open_node_remote(donor_file->node);
    387 
    388         acceptor_file = _vfs_file_get(acceptor_data, acceptor_fd);
    389         assert(acceptor_file);
    390 
    391         /*
    392          * Inherit attributes from the donor.
    393          */
    394         acceptor_file->node = donor_file->node;
    395         acceptor_file->append = donor_file->append;
    396         acceptor_file->pos = donor_file->pos;
     407        bh->node = donor_file->node;
     408        bh->permissions = donor_file->permissions;
    397409
    398410out:
     
    408420        if (donor_file)
    409421                _vfs_file_put(donor_data, donor_file);
    410         if (acceptor_file)
    411                 _vfs_file_put(acceptor_data, acceptor_file);
    412 
    413 }
    414 
    415 int vfs_wait_handle_internal(void)
     422}
     423
     424int vfs_wait_handle_internal(bool high_fd)
    416425{
    417426        vfs_client_data_t *vfs_data = VFS_DATA;
    418         int fd;
    419427       
    420428        fibril_mutex_lock(&vfs_data->lock);
     
    426434
    427435        vfs_boxed_handle_t *bh = list_get_instance(lnk, vfs_boxed_handle_t, link);
    428         fd = bh->handle;
     436
     437        vfs_file_t *file;
     438        int fd = _vfs_fd_alloc(vfs_data, &file, high_fd);
     439        if (fd < 0) {
     440                vfs_node_delref(bh->node);
     441                free(bh);
     442                return fd;
     443        }
     444       
     445        file->node = bh->node;
     446        file->permissions = bh->permissions;
     447        vfs_file_put(file);
    429448        free(bh);
    430 
    431449        return fd;
    432450}
  • uspace/srv/vfs/vfs_lookup.c

    r39f892a9 r368ee04  
    4646#include <adt/list.h>
    4747#include <vfs/canonify.h>
    48 
    49 #define min(a, b)  ((a) < (b) ? (a) : (b))
     48#include <dirent.h>
     49#include <assert.h>
    5050
    5151FIBRIL_MUTEX_INITIALIZE(plb_mutex);
     
    5353uint8_t *plb = NULL;
    5454
    55 /** Perform a path lookup.
    56  *
    57  * @param path    Path to be resolved; it must be a NULL-terminated
    58  *                string.
    59  * @param lflag   Flags to be used during lookup.
    60  * @param result  Empty structure where the lookup result will be stored.
    61  *                Can be NULL.
    62  * @param altroot If non-empty, will be used instead of rootfs as the root
    63  *                of the whole VFS tree.
    64  *
    65  * @return EOK on success or an error code from errno.h.
    66  *
    67  */
    68 int vfs_lookup_internal(char *path, int lflag, vfs_lookup_res_t *result,
    69     vfs_pair_t *altroot, ...)
    70 {
    71         vfs_pair_t *root;
    72 
    73         if (altroot)
    74                 root = altroot;
    75         else
    76                 root = &rootfs;
    77 
    78         if (!root->fs_handle)
    79                 return ENOENT;
    80        
    81         size_t len;
    82         path = canonify(path, &len);
    83         if (!path)
    84                 return EINVAL;
    85        
    86         fs_index_t index = 0;
    87         if (lflag & L_LINK) {
    88                 va_list ap;
    89 
    90                 va_start(ap, altroot);
    91                 index = va_arg(ap, fs_index_t);
    92                 va_end(ap);
    93         }
    94        
     55static int plb_insert_entry(plb_entry_t *entry, char *path, size_t *start,
     56    size_t len)
     57{
    9558        fibril_mutex_lock(&plb_mutex);
    9659
    97         plb_entry_t entry;
    98         link_initialize(&entry.plb_link);
    99         entry.len = len;
     60        link_initialize(&entry->plb_link);
     61        entry->len = len;
    10062
    10163        size_t first;   /* the first free index */
     
    138100         */
    139101
    140         entry.index = first;
    141         entry.len = len;
     102        entry->index = first;
     103        entry->len = len;
    142104
    143105        /*
     
    145107         * buffer.
    146108         */
    147         list_append(&entry.plb_link, &plb_entries);
     109        list_append(&entry->plb_link, &plb_entries);
    148110       
    149111        fibril_mutex_unlock(&plb_mutex);
     
    158120        memcpy(plb, &path[cnt1], cnt2);
    159121
    160         ipc_call_t answer;
    161         async_exch_t *exch = vfs_exchange_grab(root->fs_handle);
    162         aid_t req = async_send_5(exch, VFS_OUT_LOOKUP, (sysarg_t) first,
    163             (sysarg_t) (first + len - 1) % PLB_SIZE,
    164             (sysarg_t) root->service_id, (sysarg_t) lflag, (sysarg_t) index,
    165             &answer);
    166        
    167         sysarg_t rc;
    168         async_wait_for(req, &rc);
    169         vfs_exchange_release(exch);
    170        
     122        *start = first;
     123        return EOK;
     124}
     125
     126static void plb_clear_entry(plb_entry_t *entry, size_t first, size_t len)
     127{
    171128        fibril_mutex_lock(&plb_mutex);
    172         list_remove(&entry.plb_link);
     129        list_remove(&entry->plb_link);
    173130        /*
    174131         * Erasing the path from PLB will come handy for debugging purposes.
    175132         */
     133        size_t cnt1 = min(len, (PLB_SIZE - first) + 1);
     134        size_t cnt2 = len - cnt1;
    176135        memset(&plb[first], 0, cnt1);
    177136        memset(plb, 0, cnt2);
    178137        fibril_mutex_unlock(&plb_mutex);
    179        
    180         if ((int) rc < EOK)
     138}
     139
     140int vfs_link_internal(vfs_node_t *base, char *path, vfs_triplet_t *child)
     141{
     142        assert(base != NULL);
     143        assert(child != NULL);
     144        assert(base->fs_handle);
     145        assert(child->fs_handle);
     146        assert(path != NULL);
     147       
     148        vfs_lookup_res_t res;
     149        char component[NAME_MAX + 1];
     150        int rc;
     151       
     152        size_t len;
     153        char *npath = canonify(path, &len);
     154        if (!npath) {
     155                rc = EINVAL;
     156                goto out;
     157        }
     158        path = npath;
     159       
     160        vfs_triplet_t *triplet;
     161       
     162        char *slash = str_rchr(path, L'/');
     163        if (slash && slash != path) {
     164                if (slash[1] == 0) {
     165                        rc = EINVAL;
     166                        goto out;
     167                }
     168               
     169                memcpy(component, slash + 1, str_size(slash));
     170                *slash = 0;
     171               
     172                rc = vfs_lookup_internal(base, path, L_DIRECTORY, &res);
     173                if (rc != EOK)
     174                        goto out;
     175                triplet = &res.triplet;
     176               
     177                *slash = '/';
     178        } else {
     179                if (base->mount != NULL) {
     180                        rc = EINVAL;
     181                        goto out;
     182                }
     183               
     184                memcpy(component, path + 1, str_size(path));
     185                triplet = (vfs_triplet_t *) base;
     186        }
     187       
     188        if (triplet->fs_handle != child->fs_handle ||
     189            triplet->service_id != child->service_id) {
     190                rc = EXDEV;
     191                goto out;
     192        }
     193       
     194        async_exch_t *exch = vfs_exchange_grab(triplet->fs_handle);
     195        aid_t req = async_send_3(exch, VFS_OUT_LINK, triplet->service_id,
     196            triplet->index, child->index, NULL);
     197       
     198        rc = async_data_write_start(exch, component, str_size(component) + 1);
     199        sysarg_t orig_rc;
     200        async_wait_for(req, &orig_rc);
     201        vfs_exchange_release(exch);
     202        if (orig_rc != EOK)
     203                rc = orig_rc;
     204       
     205out:
     206        return rc;
     207}
     208
     209static int out_lookup(vfs_triplet_t *base, size_t *pfirst, size_t *plen,
     210    int lflag, vfs_lookup_res_t *result)
     211{
     212        assert(base);
     213        assert(result);
     214       
     215        sysarg_t rc;
     216        ipc_call_t answer;
     217        async_exch_t *exch = vfs_exchange_grab(base->fs_handle);
     218        aid_t req = async_send_5(exch, VFS_OUT_LOOKUP, (sysarg_t) *pfirst,
     219            (sysarg_t) *plen, (sysarg_t) base->service_id,
     220            (sysarg_t) base->index, (sysarg_t) lflag, &answer);
     221        async_wait_for(req, &rc);
     222        vfs_exchange_release(exch);
     223       
     224        if ((int) rc < 0)
    181225                return (int) rc;
    182 
    183         if (!result)
    184                 return EOK;
     226       
     227        unsigned last = *pfirst + *plen;
     228        *pfirst = IPC_GET_ARG3(answer) & 0xffff;
     229        *plen = last - *pfirst;
    185230       
    186231        result->triplet.fs_handle = (fs_handle_t) rc;
    187232        result->triplet.service_id = (service_id_t) IPC_GET_ARG1(answer);
    188233        result->triplet.index = (fs_index_t) IPC_GET_ARG2(answer);
    189         result->size =
    190             (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(answer), IPC_GET_ARG4(answer));
    191         result->lnkcnt = (unsigned int) IPC_GET_ARG5(answer);
    192        
    193         if (lflag & L_FILE)
    194                 result->type = VFS_NODE_FILE;
    195         else if (lflag & L_DIRECTORY)
    196                 result->type = VFS_NODE_DIRECTORY;
    197         else
    198                 result->type = VFS_NODE_UNKNOWN;
    199        
     234        result->size = MERGE_LOUP32(IPC_GET_ARG4(answer), IPC_GET_ARG5(answer));
     235        result->type = (IPC_GET_ARG3(answer) >> 16) ?
     236            VFS_NODE_DIRECTORY : VFS_NODE_FILE;
    200237        return EOK;
     238}
     239
     240static int _vfs_lookup_internal(vfs_node_t *base, char *path, int lflag,
     241    vfs_lookup_res_t *result, size_t len)
     242{
     243        size_t first;
     244        int rc;
     245
     246        plb_entry_t entry;
     247        rc = plb_insert_entry(&entry, path, &first, len);
     248        if (rc != EOK)
     249                return rc;
     250       
     251        size_t next = first;
     252        size_t nlen = len;
     253       
     254        vfs_lookup_res_t res;
     255       
     256        /* Resolve path as long as there are mount points to cross. */
     257        while (nlen > 0) {
     258                while (base->mount) {
     259                        if (lflag & L_DISABLE_MOUNTS) {
     260                                rc = EXDEV;
     261                                goto out;
     262                        }
     263                       
     264                        base = base->mount;
     265                }
     266               
     267                rc = out_lookup((vfs_triplet_t *) base, &next, &nlen, lflag,
     268                    &res);
     269                if (rc != EOK)
     270                        goto out;
     271               
     272                if (nlen > 0) {
     273                        base = vfs_node_peek(&res);
     274                        if (!base) {
     275                                rc = ENOENT;
     276                                goto out;
     277                        }
     278                        if (!base->mount) {
     279                                vfs_node_put(base);
     280                                rc = ENOENT;
     281                                goto out;
     282                        }
     283                        vfs_node_put(base);
     284                        if (lflag & L_DISABLE_MOUNTS) {
     285                                rc = EXDEV;
     286                                goto out;
     287                        }
     288                }
     289        }
     290       
     291        assert(nlen == 0);
     292        rc = EOK;
     293       
     294        if (result != NULL) {
     295                /* The found file may be a mount point. Try to cross it. */
     296                if (!(lflag & (L_MP | L_DISABLE_MOUNTS))) {
     297                        base = vfs_node_peek(&res);
     298                        if (base && base->mount) {
     299                                while (base->mount) {
     300                                        vfs_node_addref(base->mount);
     301                                        vfs_node_t *nbase = base->mount;
     302                                        vfs_node_put(base);
     303                                        base = nbase;
     304                                }
     305                               
     306                                result->triplet = *((vfs_triplet_t *) base);
     307                                result->type = base->type;
     308                                result->size = base->size;
     309                                vfs_node_put(base);
     310                                goto out;
     311                        }
     312                        if (base)
     313                                vfs_node_put(base);
     314                }
     315
     316                *result = res;
     317        }
     318       
     319out:
     320        plb_clear_entry(&entry, first, len);
     321        return rc;
     322}
     323
     324/** Perform a path lookup.
     325 *
     326 * @param base    The file from which to perform the lookup.
     327 * @param path    Path to be resolved; it must be a NULL-terminated
     328 *                string.
     329 * @param lflag   Flags to be used during lookup.
     330 * @param result  Empty structure where the lookup result will be stored.
     331 *                Can be NULL.
     332 *
     333 * @return EOK on success or an error code from errno.h.
     334 *
     335 */
     336int vfs_lookup_internal(vfs_node_t *base, char *path, int lflag,
     337    vfs_lookup_res_t *result)
     338{
     339        assert(base != NULL);
     340        assert(path != NULL);
     341       
     342        size_t len;
     343        int rc;
     344        char *npath = canonify(path, &len);
     345        if (!npath) {
     346                rc = EINVAL;
     347                return rc;
     348        }
     349        path = npath;
     350       
     351        assert(path[0] == '/');
     352
     353
     354        if (lflag & (L_CREATE | L_UNLINK)) {
     355
     356                /*
     357                 * Creation and destruction of names must be done in two
     358                 * separate steps: lookup of the parent node and the name
     359                 * link/unlink operation itself.  Otherwise the parent
     360                 * filesystem would not be able to tell when a mountpoint is
     361                 * crossed. It would attempt to perform the link/unlink in
     362                 * itself instead of letting the mounted filesystem do it,
     363                 * resulting in wrong behavior. This is the wages of server-side
     364                 * mountpoints.
     365                 */
     366
     367                char *slash = str_rchr(path, L'/');
     368                vfs_node_t *parent = base;
     369               
     370                if (slash != path) {
     371                        int tflag = lflag;
     372                        vfs_lookup_res_t tres;
     373
     374                        tflag &= ~(L_CREATE | L_EXCLUSIVE | L_UNLINK | L_FILE);
     375                        tflag |= L_DIRECTORY;
     376                        rc = _vfs_lookup_internal(base, path, tflag, &tres,
     377                            slash - path);
     378                        if (rc != EOK)
     379                                return rc;
     380                        parent = vfs_node_get(&tres);
     381                        if (!parent)
     382                                return ENOMEM;
     383                } else
     384                        vfs_node_addref(parent);
     385
     386                rc = _vfs_lookup_internal(parent, slash, lflag, result,
     387                    len - (slash - path));
     388
     389                vfs_node_put(parent);
     390
     391        } else {
     392                rc = _vfs_lookup_internal(base, path, lflag, result, len);
     393        }
     394       
     395        return rc;
    201396}
    202397
  • uspace/srv/vfs/vfs_node.c

    r39f892a9 r368ee04  
    4545#include <async.h>
    4646#include <errno.h>
     47#include <macros.h>
    4748
    4849/** Mutex protecting the VFS node hash table. */
     
    106107void vfs_node_delref(vfs_node_t *node)
    107108{
    108         bool free_vfs_node = false;
    109         bool free_fs_node = false;
    110        
    111         fibril_mutex_lock(&nodes_mutex);
    112        
    113         if (node->refcnt-- == 1) {
    114                
     109        bool free_node = false;
     110       
     111        fibril_mutex_lock(&nodes_mutex);
     112       
     113        node->refcnt--;
     114        if (node->refcnt == 0) {
    115115                /*
    116116                 * We are dropping the last reference to this node.
     
    119119               
    120120                hash_table_remove_item(&nodes, &node->nh_link);
    121                 free_vfs_node = true;
    122                
    123                 if (!node->lnkcnt)
    124                         free_fs_node = true;
     121                free_node = true;
    125122        }
    126123       
    127124        fibril_mutex_unlock(&nodes_mutex);
    128125       
    129         if (free_fs_node) {
    130                
     126        if (free_node) {
    131127                /*
    132                  * The node is not visible in the file system namespace.
    133                  * Free up its resources.
     128                 * VFS_OUT_DESTROY will free up the file's resources if there
     129                 * are no more hard links.
    134130                 */
    135131               
    136132                async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
    137                 sysarg_t rc = async_req_2_0(exch, VFS_OUT_DESTROY,
    138                     (sysarg_t) node->service_id, (sysarg_t)node->index);
    139                
    140                 assert(rc == EOK);
     133                async_msg_2(exch, VFS_OUT_DESTROY, (sysarg_t) node->service_id,
     134                    (sysarg_t)node->index);
    141135                vfs_exchange_release(exch);
     136
     137                free(node);
    142138        }
    143        
    144         if (free_vfs_node)
    145                 free(node);
    146139}
    147140
     
    190183                node->index = result->triplet.index;
    191184                node->size = result->size;
    192                 node->lnkcnt = result->lnkcnt;
    193185                node->type = result->type;
    194186                fibril_rwlock_initialize(&node->contents_rwlock);
     
    196188        } else {
    197189                node = hash_table_get_inst(tmp, vfs_node_t, nh_link);
    198                 if (node->type == VFS_NODE_UNKNOWN &&
    199                     result->type != VFS_NODE_UNKNOWN) {
    200                         /* Upgrade the node type. */
    201                         node->type = result->type;
    202                 }
    203190        }
    204191
    205         assert(node->size == result->size || node->type != VFS_NODE_FILE);
    206         assert(node->lnkcnt == result->lnkcnt);
    207         assert(node->type == result->type || result->type == VFS_NODE_UNKNOWN);
    208 
    209192        _vfs_node_addref(node);
     193        fibril_mutex_unlock(&nodes_mutex);
     194
     195        return node;
     196}
     197
     198vfs_node_t *vfs_node_peek(vfs_lookup_res_t *result)
     199{
     200        vfs_node_t *node = NULL;
     201
     202        fibril_mutex_lock(&nodes_mutex);
     203        ht_link_t *tmp = hash_table_find(&nodes, &result->triplet);
     204        if (tmp) {
     205                node = hash_table_get_inst(tmp, vfs_node_t, nh_link);
     206                _vfs_node_addref(node);
     207        }
    210208        fibril_mutex_unlock(&nodes_mutex);
    211209
     
    302300        vfs_triplet_t *tri = key;
    303301        vfs_node_t *node = hash_table_get_inst(item, vfs_node_t, nh_link);
    304         return node->fs_handle == tri->fs_handle
    305                 && node->service_id == tri->service_id
    306                 && node->index == tri->index;
     302        return node->fs_handle == tri->fs_handle &&
     303            node->service_id == tri->service_id && node->index == tri->index;
    307304}
    308305
     
    318315}
    319316
     317bool vfs_node_has_children(vfs_node_t *node)
     318{
     319        async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
     320        int rc = async_req_2_0(exch, VFS_OUT_IS_EMPTY, node->service_id,
     321            node->index);
     322        vfs_exchange_release(exch);
     323        return rc == ENOTEMPTY;
     324}
     325
    320326/**
    321327 * @}
  • uspace/srv/vfs/vfs_ops.c

    r39f892a9 r368ee04  
    4949#include <unistd.h>
    5050#include <ctype.h>
    51 #include <fcntl.h>
    5251#include <assert.h>
    5352#include <vfs/canonify.h>
    54 #include <vfs/vfs_mtab.h>
    55 
    56 FIBRIL_MUTEX_INITIALIZE(mtab_list_lock);
    57 LIST_INITIALIZE(mtab_list);
    58 static size_t mtab_size = 0;
    5953
    6054/* Forward declarations of static functions. */
     
    6862FIBRIL_RWLOCK_INITIALIZE(namespace_rwlock);
    6963
    70 vfs_pair_t rootfs = {
    71         .fs_handle = 0,
    72         .service_id = 0
    73 };
    74 
    75 static int vfs_mount_internal(ipc_callid_t rid, service_id_t service_id,
    76     fs_handle_t fs_handle, char *mp, char *opts)
    77 {
    78         vfs_lookup_res_t mp_res;
    79         vfs_lookup_res_t mr_res;
    80         vfs_node_t *mp_node = NULL;
    81         vfs_node_t *mr_node;
    82         fs_index_t rindex;
    83         aoff64_t rsize;
    84         unsigned rlnkcnt;
    85         async_exch_t *exch;
    86         sysarg_t rc;
    87         aid_t msg;
     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. */
    88152        ipc_call_t answer;
    89        
    90         /* Resolve the path to the mountpoint. */
    91         fibril_rwlock_write_lock(&namespace_rwlock);
    92         if (rootfs.fs_handle) {
    93                 /* We already have the root FS. */
    94                 if (str_cmp(mp, "/") == 0) {
    95                         /* Trying to mount root FS over root FS */
    96                         fibril_rwlock_write_unlock(&namespace_rwlock);
    97                         async_answer_0(rid, EBUSY);
    98                         return EBUSY;
    99                 }
    100                
    101                 rc = vfs_lookup_internal(mp, L_MP, &mp_res, NULL);
    102                 if (rc != EOK) {
    103                         /* The lookup failed for some reason. */
    104                         fibril_rwlock_write_unlock(&namespace_rwlock);
    105                         async_answer_0(rid, rc);
    106                         return rc;
    107                 }
    108                
    109                 mp_node = vfs_node_get(&mp_res);
    110                 if (!mp_node) {
    111                         fibril_rwlock_write_unlock(&namespace_rwlock);
    112                         async_answer_0(rid, ENOMEM);
    113                         return ENOMEM;
    114                 }
    115                
    116                 /*
    117                  * Now we hold a reference to mp_node.
    118                  * It will be dropped upon the corresponding VFS_IN_UNMOUNT.
    119                  * This prevents the mount point from being deleted.
    120                  */
    121         } else {
    122                 /* We still don't have the root file system mounted. */
    123                 if (str_cmp(mp, "/") == 0) {
    124                         /*
    125                          * For this simple, but important case,
    126                          * we are almost done.
    127                          */
    128                        
    129                         /* Tell the mountee that it is being mounted. */
    130                         exch = vfs_exchange_grab(fs_handle);
    131                         msg = async_send_1(exch, VFS_OUT_MOUNTED,
    132                             (sysarg_t) service_id, &answer);
    133                         /* Send the mount options */
    134                         rc = async_data_write_start(exch, (void *)opts,
    135                             str_size(opts));
    136                         vfs_exchange_release(exch);
    137                        
    138                         if (rc != EOK) {
    139                                 async_forget(msg);
    140                                 fibril_rwlock_write_unlock(&namespace_rwlock);
    141                                 async_answer_0(rid, rc);
    142                                 return rc;
    143                         }
    144                         async_wait_for(msg, &rc);
    145                        
    146                         if (rc != EOK) {
    147                                 fibril_rwlock_write_unlock(&namespace_rwlock);
    148                                 async_answer_0(rid, rc);
    149                                 return rc;
    150                         }
    151 
    152                         rindex = (fs_index_t) IPC_GET_ARG1(answer);
    153                         rsize = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG2(answer),
    154                             IPC_GET_ARG3(answer));
    155                         rlnkcnt = (unsigned) IPC_GET_ARG4(answer);
    156                        
    157                         mr_res.triplet.fs_handle = fs_handle;
    158                         mr_res.triplet.service_id = service_id;
    159                         mr_res.triplet.index = rindex;
    160                         mr_res.size = rsize;
    161                         mr_res.lnkcnt = rlnkcnt;
    162                         mr_res.type = VFS_NODE_DIRECTORY;
    163                        
    164                         rootfs.fs_handle = fs_handle;
    165                         rootfs.service_id = service_id;
    166                        
    167                         /* Add reference to the mounted root. */
    168                         mr_node = vfs_node_get(&mr_res);
    169                         assert(mr_node);
    170                        
    171                         fibril_rwlock_write_unlock(&namespace_rwlock);
    172                         async_answer_0(rid, rc);
    173                         return rc;
    174                 } else {
    175                         /*
    176                          * We can't resolve this without the root filesystem
    177                          * being mounted first.
    178                          */
    179                         fibril_rwlock_write_unlock(&namespace_rwlock);
    180                         async_answer_0(rid, ENOENT);
    181                         return ENOENT;
    182                 }
    183         }
    184        
    185         /*
    186          * At this point, we have all necessary pieces: file system handle
    187          * and service ID, and we know the mount point VFS node.
    188          */
    189        
    190         async_exch_t *mountee_exch = vfs_exchange_grab(fs_handle);
    191         assert(mountee_exch);
    192        
    193         exch = vfs_exchange_grab(mp_res.triplet.fs_handle);
    194         msg = async_send_4(exch, VFS_OUT_MOUNT,
    195             (sysarg_t) mp_res.triplet.service_id,
    196             (sysarg_t) mp_res.triplet.index,
    197             (sysarg_t) fs_handle,
    198             (sysarg_t) service_id, &answer);
    199        
    200         /* Send connection */
    201         rc = async_exchange_clone(exch, mountee_exch);
    202         vfs_exchange_release(mountee_exch);
    203        
     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);
    204165        if (rc != EOK) {
    205166                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);
    206183                async_forget(msg);
    207                
    208                 /* Mount failed, drop reference to mp_node. */
    209                 if (mp_node)
    210                         vfs_node_put(mp_node);
    211                
    212                 async_answer_0(rid, rc);
    213                 fibril_rwlock_write_unlock(&namespace_rwlock);
     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);
    214313                return rc;
    215314        }
    216315       
    217         /* send the mount options */
    218         rc = async_data_write_start(exch, (void *) opts, str_size(opts));
    219         if (rc != EOK) {
    220                 vfs_exchange_release(exch);
    221                 async_forget(msg);
    222                
    223                 /* Mount failed, drop reference to mp_node. */
    224                 if (mp_node)
    225                         vfs_node_put(mp_node);
    226                
    227                 fibril_rwlock_write_unlock(&namespace_rwlock);
    228                 async_answer_0(rid, rc);
    229                 return rc;
    230         }
    231        
    232         /*
    233          * Wait for the answer before releasing the exchange to avoid deadlock
    234          * in case the answer depends on further calls to the same file system.
    235          * Think of a case when mounting a FS on a file_bd backed by a file on
    236          * the same FS.
    237          */
    238         async_wait_for(msg, &rc);
    239         vfs_exchange_release(exch);
    240        
    241         if (rc == EOK) {
    242                 rindex = (fs_index_t) IPC_GET_ARG1(answer);
    243                 rsize = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG2(answer),
    244                     IPC_GET_ARG3(answer));
    245                 rlnkcnt = (unsigned) IPC_GET_ARG4(answer);
    246                
    247                 mr_res.triplet.fs_handle = fs_handle;
    248                 mr_res.triplet.service_id = service_id;
    249                 mr_res.triplet.index = rindex;
    250                 mr_res.size = rsize;
    251                 mr_res.lnkcnt = rlnkcnt;
    252                 mr_res.type = VFS_NODE_DIRECTORY;
    253                
    254                 /* Add reference to the mounted root. */
    255                 mr_node = vfs_node_get(&mr_res);
    256                 assert(mr_node);
    257         } else {
    258                 /* Mount failed, drop reference to mp_node. */
    259                 if (mp_node)
    260                         vfs_node_put(mp_node);
    261         }
    262        
    263         async_answer_0(rid, rc);
    264         fibril_rwlock_write_unlock(&namespace_rwlock);
    265         return rc;
    266 }
    267 
    268 void vfs_mount_srv(ipc_callid_t rid, ipc_call_t *request)
    269 {
    270         service_id_t service_id;
    271 
    272         /*
    273          * We expect the library to do the device-name to device-handle
    274          * translation for us, thus the device handle will arrive as ARG1
    275          * in the request.
    276          */
    277         service_id = (service_id_t) IPC_GET_ARG1(*request);
    278        
    279         /*
    280          * Mount flags are passed as ARG2.
    281          */
    282         unsigned int flags = (unsigned int) IPC_GET_ARG2(*request);
    283        
    284         /*
    285          * Instance number is passed as ARG3.
    286          */
    287         unsigned int instance = IPC_GET_ARG3(*request);
    288 
    289         /* We want the client to send us the mount point. */
    290         char *mp;
    291         int rc = async_data_write_accept((void **) &mp, true, 0, MAX_PATH_LEN,
    292             0, NULL);
    293         if (rc != EOK) {
    294                 async_answer_0(rid, rc);
    295                 return;
    296         }
    297        
    298         /* Now we expect to receive the mount options. */
    299         char *opts;
    300         rc = async_data_write_accept((void **) &opts, true, 0, MAX_MNTOPTS_LEN,
    301             0, NULL);
    302         if (rc != EOK) {
    303                 free(mp);
    304                 async_answer_0(rid, rc);
    305                 return;
    306         }
    307        
    308         /*
    309          * Now, we expect the client to send us data with the name of the file
    310          * system.
    311          */
    312         char *fs_name;
    313         rc = async_data_write_accept((void **) &fs_name, true, 0,
    314             FS_NAME_MAXLEN, 0, NULL);
    315         if (rc != EOK) {
    316                 free(mp);
    317                 free(opts);
    318                 async_answer_0(rid, rc);
    319                 return;
    320         }
    321        
    322         /*
    323          * Wait for VFS_IN_PING so that we can return an error if we don't know
    324          * fs_name.
    325          */
    326         ipc_call_t data;
    327         ipc_callid_t callid = async_get_call(&data);
    328         if (IPC_GET_IMETHOD(data) != VFS_IN_PING) {
    329                 async_answer_0(callid, ENOTSUP);
    330                 async_answer_0(rid, ENOTSUP);
    331                 free(mp);
    332                 free(opts);
    333                 free(fs_name);
    334                 return;
    335         }
    336 
    337         /*
    338          * Check if we know a file system with the same name as is in fs_name.
    339          * This will also give us its file system handle.
    340          */
    341         fibril_mutex_lock(&fs_list_lock);
    342         fs_handle_t fs_handle;
    343 recheck:
    344         fs_handle = fs_name_to_handle(instance, fs_name, false);
    345         if (!fs_handle) {
    346                 if (flags & IPC_FLAG_BLOCKING) {
    347                         fibril_condvar_wait(&fs_list_cv, &fs_list_lock);
    348                         goto recheck;
    349                 }
    350                
    351                 fibril_mutex_unlock(&fs_list_lock);
    352                 async_answer_0(callid, ENOENT);
    353                 async_answer_0(rid, ENOENT);
    354                 free(mp);
    355                 free(fs_name);
    356                 free(opts);
    357                 return;
    358         }
    359         fibril_mutex_unlock(&fs_list_lock);
    360 
    361         /* Add the filesystem info to the list of mounted filesystems */
    362         mtab_ent_t *mtab_ent = malloc(sizeof(mtab_ent_t));
    363         if (!mtab_ent) {
    364                 async_answer_0(callid, ENOMEM);
    365                 async_answer_0(rid, ENOMEM);
    366                 free(mp);
    367                 free(fs_name);
    368                 free(opts);
    369                 return;
    370         }
    371 
    372         /* Do the mount */
    373         rc = vfs_mount_internal(rid, service_id, fs_handle, mp, opts);
    374         if (rc != EOK) {
    375                 async_answer_0(callid, ENOTSUP);
    376                 async_answer_0(rid, ENOTSUP);
    377                 free(mtab_ent);
    378                 free(mp);
    379                 free(opts);
    380                 free(fs_name);
    381                 return;
    382         }
    383 
    384         /* Add the filesystem info to the list of mounted filesystems */
    385 
    386         str_cpy(mtab_ent->mp, MAX_PATH_LEN, mp);
    387         str_cpy(mtab_ent->fs_name, FS_NAME_MAXLEN, fs_name);
    388         str_cpy(mtab_ent->opts, MAX_MNTOPTS_LEN, opts);
    389         mtab_ent->instance = instance;
    390         mtab_ent->service_id = service_id;
    391 
    392         link_initialize(&mtab_ent->link);
    393 
    394         fibril_mutex_lock(&mtab_list_lock);
    395         list_append(&mtab_ent->link, &mtab_list);
    396         mtab_size++;
    397         fibril_mutex_unlock(&mtab_list_lock);
    398 
    399         free(mp);
    400         free(fs_name);
    401         free(opts);
    402 
    403         /* Acknowledge that we know fs_name. */
    404         async_answer_0(callid, EOK);
    405 }
    406 
    407 void vfs_unmount_srv(ipc_callid_t rid, ipc_call_t *request)
    408 {
    409         int rc;
    410         char *mp;
    411         vfs_lookup_res_t mp_res;
    412         vfs_lookup_res_t mr_res;
    413         vfs_node_t *mr_node;
    414         async_exch_t *exch;
    415        
    416         /*
    417          * Receive the mount point path.
    418          */
    419         rc = async_data_write_accept((void **) &mp, true, 0, MAX_PATH_LEN,
    420             0, NULL);
    421         if (rc != EOK)
    422                 async_answer_0(rid, rc);
    423        
    424         /*
    425          * Taking the namespace lock will do two things for us. First, it will
    426          * prevent races with other lookup operations. Second, it will stop new
    427          * references to already existing VFS nodes and creation of new VFS
    428          * nodes. This is because new references are added as a result of some
    429          * lookup operation or at least of some operation which is protected by
    430          * the namespace lock.
    431          */
    432         fibril_rwlock_write_lock(&namespace_rwlock);
    433        
    434         /*
    435          * Lookup the mounted root and instantiate it.
    436          */
    437         rc = vfs_lookup_internal(mp, L_ROOT, &mr_res, NULL);
    438         if (rc != EOK) {
    439                 fibril_rwlock_write_unlock(&namespace_rwlock);
    440                 free(mp);
    441                 async_answer_0(rid, rc);
    442                 return;
    443         }
    444         mr_node = vfs_node_get(&mr_res);
    445         if (!mr_node) {
    446                 fibril_rwlock_write_unlock(&namespace_rwlock);
    447                 free(mp);
    448                 async_answer_0(rid, ENOMEM);
    449                 return;
    450         }
    451        
    452         /*
    453          * Count the total number of references for the mounted file system. We
    454          * are expecting at least two. One which we got above and one which we
    455          * got when the file system was mounted. If we find more, it means that
    456          * the file system cannot be gracefully unmounted at the moment because
    457          * someone is working with it.
    458          */
    459         if (vfs_nodes_refcount_sum_get(mr_node->fs_handle,
    460             mr_node->service_id) != 2) {
    461                 fibril_rwlock_write_unlock(&namespace_rwlock);
    462                 vfs_node_put(mr_node);
    463                 free(mp);
    464                 async_answer_0(rid, EBUSY);
    465                 return;
    466         }
    467        
    468         if (str_cmp(mp, "/") == 0) {
    469                
    470                 /*
    471                  * Unmounting the root file system.
    472                  *
    473                  * In this case, there is no mount point node and we send
    474                  * VFS_OUT_UNMOUNTED directly to the mounted file system.
    475                  */
    476                
    477                 exch = vfs_exchange_grab(mr_node->fs_handle);
    478                 rc = async_req_1_0(exch, VFS_OUT_UNMOUNTED,
    479                     mr_node->service_id);
    480                 vfs_exchange_release(exch);
    481                
    482                 if (rc != EOK) {
    483                         fibril_rwlock_write_unlock(&namespace_rwlock);
    484                         free(mp);
    485                         vfs_node_put(mr_node);
    486                         async_answer_0(rid, rc);
    487                         return;
    488                 }
    489                
    490                 rootfs.fs_handle = 0;
    491                 rootfs.service_id = 0;
    492         } else {
    493                
    494                 /*
    495                  * Unmounting a non-root file system.
    496                  *
    497                  * We have a regular mount point node representing the parent
    498                  * file system, so we delegate the operation to it.
    499                  */
    500                
    501                 rc = vfs_lookup_internal(mp, L_MP, &mp_res, NULL);
    502                 if (rc != EOK) {
    503                         fibril_rwlock_write_unlock(&namespace_rwlock);
    504                         free(mp);
    505                         vfs_node_put(mr_node);
    506                         async_answer_0(rid, rc);
    507                         return;
    508                 }
    509                
    510                 vfs_node_t *mp_node = vfs_node_get(&mp_res);
    511                 if (!mp_node) {
    512                         fibril_rwlock_write_unlock(&namespace_rwlock);
    513                         free(mp);
    514                         vfs_node_put(mr_node);
    515                         async_answer_0(rid, ENOMEM);
    516                         return;
    517                 }
    518                
    519                 exch = vfs_exchange_grab(mp_node->fs_handle);
    520                 rc = async_req_2_0(exch, VFS_OUT_UNMOUNT,
    521                     mp_node->service_id, mp_node->index);
    522                 vfs_exchange_release(exch);
    523                
    524                 if (rc != EOK) {
    525                         fibril_rwlock_write_unlock(&namespace_rwlock);
    526                         free(mp);
    527                         vfs_node_put(mp_node);
    528                         vfs_node_put(mr_node);
    529                         async_answer_0(rid, rc);
    530                         return;
    531                 }
    532                
    533                 /* Drop the reference we got above. */
    534                 vfs_node_put(mp_node);
    535                 /* Drop the reference from when the file system was mounted. */
    536                 vfs_node_put(mp_node);
    537         }
    538        
    539         /*
    540          * All went well, the mounted file system was successfully unmounted.
    541          * The only thing left is to forget the unmounted root VFS node.
    542          */
    543         vfs_node_forget(mr_node);
    544         fibril_rwlock_write_unlock(&namespace_rwlock);
    545 
    546         fibril_mutex_lock(&mtab_list_lock);
    547 
    548         int found = 0;
    549 
    550         list_foreach(mtab_list, link, mtab_ent_t, mtab_ent) {
    551                 if (str_cmp(mtab_ent->mp, mp) == 0) {
    552                         list_remove(&mtab_ent->link);
    553                         mtab_size--;
    554                         free(mtab_ent);
    555                         found = 1;
    556                         break;
    557                 }
    558         }
    559         assert(found);
    560         fibril_mutex_unlock(&mtab_list_lock);
    561 
    562         free(mp);
    563 
    564         async_answer_0(rid, EOK);
    565 }
    566 
    567 void vfs_open(ipc_callid_t rid, ipc_call_t *request)
    568 {
    569         /*
    570          * The POSIX interface is open(path, oflag, mode).
    571          * We can receive oflags and mode along with the VFS_IN_OPEN call;
    572          * the path will need to arrive in another call.
    573          *
    574          * We also receive one private, non-POSIX set of flags called lflag
    575          * used to pass information to vfs_lookup_internal().
    576          */
    577         int lflag = IPC_GET_ARG1(*request);
    578         int oflag = IPC_GET_ARG2(*request);
    579         int mode = IPC_GET_ARG3(*request);
    580 
    581         /* Ignore mode for now. */
    582         (void) mode;
    583        
    584         /*
    585          * Make sure that we are called with exactly one of L_FILE and
    586          * L_DIRECTORY. Make sure that the user does not pass L_OPEN,
    587          * L_ROOT or L_MP.
    588          */
    589         if (((lflag & (L_FILE | L_DIRECTORY)) == 0) ||
    590             ((lflag & (L_FILE | L_DIRECTORY)) == (L_FILE | L_DIRECTORY)) ||
    591             (lflag & (L_OPEN | L_ROOT | L_MP))) {
    592                 async_answer_0(rid, EINVAL);
    593                 return;
    594         }
    595        
    596         if (oflag & O_CREAT)
    597                 lflag |= L_CREATE;
    598         if (oflag & O_EXCL)
    599                 lflag |= L_EXCLUSIVE;
    600        
    601         char *path;
    602         int rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL);
    603         if (rc != EOK) {
    604                 async_answer_0(rid, rc);
    605                 return;
    606         }
    607        
    608         /*
    609          * Avoid the race condition in which the file can be deleted before we
    610          * find/create-and-lock the VFS node corresponding to the looked-up
    611          * triplet.
    612          */
    613         if (lflag & L_CREATE)
    614                 fibril_rwlock_write_lock(&namespace_rwlock);
    615         else
    616                 fibril_rwlock_read_lock(&namespace_rwlock);
    617        
    618         /* The path is now populated and we can call vfs_lookup_internal(). */
    619         vfs_lookup_res_t lr;
    620         rc = vfs_lookup_internal(path, lflag | L_OPEN, &lr, NULL);
    621         if (rc != EOK) {
    622                 if (lflag & L_CREATE)
    623                         fibril_rwlock_write_unlock(&namespace_rwlock);
    624                 else
    625                         fibril_rwlock_read_unlock(&namespace_rwlock);
    626                 async_answer_0(rid, rc);
    627                 free(path);
    628                 return;
    629         }
    630        
    631         /* Path is no longer needed. */
    632         free(path);
    633        
    634         vfs_node_t *node = vfs_node_get(&lr);
    635         if (lflag & L_CREATE)
    636                 fibril_rwlock_write_unlock(&namespace_rwlock);
    637         else
    638                 fibril_rwlock_read_unlock(&namespace_rwlock);
    639 
    640         if (!node) {
    641                 async_answer_0(rid, ENOMEM);
    642                 return;
    643         }
    644        
    645         /* Truncate the file if requested and if necessary. */
    646         if (oflag & O_TRUNC) {
    647                 fibril_rwlock_write_lock(&node->contents_rwlock);
    648                 if (node->size) {
    649                         rc = vfs_truncate_internal(node->fs_handle,
    650                             node->service_id, node->index, 0);
    651                         if (rc) {
    652                                 fibril_rwlock_write_unlock(&node->contents_rwlock);
    653                                 vfs_node_put(node);
    654                                 async_answer_0(rid, rc);
    655                                 return;
    656                         }
    657                         node->size = 0;
    658                 }
    659                 fibril_rwlock_write_unlock(&node->contents_rwlock);
    660         }
    661        
    662         /*
    663          * Get ourselves a file descriptor and the corresponding vfs_file_t
    664          * structure.
    665          */
    666         int fd = vfs_fd_alloc((oflag & O_DESC) != 0);
    667         if (fd < 0) {
    668                 vfs_node_put(node);
    669                 async_answer_0(rid, fd);
    670                 return;
    671         }
    672         vfs_file_t *file = vfs_file_get(fd);
    673         assert(file);
    674         file->node = node;
    675         if (oflag & O_APPEND)
    676                 file->append = true;
    677        
    678         /*
    679          * The following increase in reference count is for the fact that the
    680          * file is being opened and that a file structure is pointing to it.
    681          * It is necessary so that the file will not disappear when
    682          * vfs_node_put() is called. The reference will be dropped by the
    683          * respective VFS_IN_CLOSE.
    684          */
    685         vfs_node_addref(node);
    686         vfs_node_put(node);
    687316        vfs_file_put(file);
    688        
    689         /* Success! Return the new file descriptor to the client. */
    690         async_answer_1(rid, EOK, fd);
    691 }
    692 
    693 void vfs_sync(ipc_callid_t rid, ipc_call_t *request)
    694 {
    695         int fd = IPC_GET_ARG1(*request);
    696        
    697         /* Lookup the file structure corresponding to the file descriptor. */
    698         vfs_file_t *file = vfs_file_get(fd);
    699         if (!file) {
    700                 async_answer_0(rid, ENOENT);
    701                 return;
    702         }
    703        
    704         /*
    705          * Lock the open file structure so that no other thread can manipulate
    706          * the same open file at a time.
    707          */
    708         fibril_mutex_lock(&file->lock);
    709         async_exch_t *fs_exch = vfs_exchange_grab(file->node->fs_handle);
    710        
    711         /* Make a VFS_OUT_SYMC request at the destination FS server. */
    712         aid_t msg;
    713         ipc_call_t answer;
    714         msg = async_send_2(fs_exch, VFS_OUT_SYNC, file->node->service_id,
    715             file->node->index, &answer);
    716        
    717         vfs_exchange_release(fs_exch);
    718        
    719         /* Wait for reply from the FS server. */
    720         sysarg_t rc;
    721         async_wait_for(msg, &rc);
    722        
    723         fibril_mutex_unlock(&file->lock);
    724        
    725         vfs_file_put(file);
    726         async_answer_0(rid, rc);
    727 }
    728 
    729 void vfs_close(ipc_callid_t rid, ipc_call_t *request)
    730 {
    731         int fd = IPC_GET_ARG1(*request);
    732         int ret = vfs_fd_free(fd);
    733         async_answer_0(rid, ret);
    734 }
    735 
    736 typedef int (* rdwr_ipc_cb_t)(async_exch_t *, vfs_file_t *, ipc_call_t *,
    737     bool, void *);
    738 
    739 static int rdwr_ipc_client(async_exch_t *exch, vfs_file_t *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,
    740324    ipc_call_t *answer, bool read, void *data)
    741325{
     
    754338                rc = async_data_read_forward_4_1(exch, VFS_OUT_READ,
    755339                    file->node->service_id, file->node->index,
    756                     LOWER32(file->pos), UPPER32(file->pos), answer);
     340                    LOWER32(pos), UPPER32(pos), answer);
    757341        } else {
    758342                rc = async_data_write_forward_4_1(exch, VFS_OUT_WRITE,
    759343                    file->node->service_id, file->node->index,
    760                     LOWER32(file->pos), UPPER32(file->pos), answer);
     344                    LOWER32(pos), UPPER32(pos), answer);
    761345        }
    762346
     
    765349}
    766350
    767 static int rdwr_ipc_internal(async_exch_t *exch, vfs_file_t *file,
     351static int rdwr_ipc_internal(async_exch_t *exch, vfs_file_t *file, aoff64_t pos,
    768352    ipc_call_t *answer, bool read, void *data)
    769353{
     
    774358       
    775359        aid_t msg = async_send_fast(exch, read ? VFS_OUT_READ : VFS_OUT_WRITE,
    776             file->node->service_id, file->node->index, LOWER32(file->pos),
    777             UPPER32(file->pos), answer);
     360            file->node->service_id, file->node->index, LOWER32(pos),
     361            UPPER32(pos), answer);
    778362        if (msg == 0)
    779363                return EINVAL;
     
    793377}
    794378
    795 static int vfs_rdwr(int fd, bool read, rdwr_ipc_cb_t ipc_cb, void *ipc_cb_data)
     379static int vfs_rdwr(int fd, aoff64_t pos, bool read, rdwr_ipc_cb_t ipc_cb,
     380    void *ipc_cb_data)
    796381{
    797382        /*
     
    808393        vfs_file_t *file = vfs_file_get(fd);
    809394        if (!file)
    810                 return ENOENT;
    811        
    812         /*
    813          * Lock the open file structure so that no other thread can manipulate
    814          * the same open file at a time.
    815          */
    816         fibril_mutex_lock(&file->lock);
     395                return EBADF;
     396       
     397        if ((read && !file->open_read) || (!read && !file->open_write)) {
     398                vfs_file_put(file);
     399                return EINVAL;
     400        }
    817401       
    818402        vfs_info_t *fs_info = fs_handle_to_info(file->node->fs_handle);
    819403        assert(fs_info);
     404       
     405        bool rlock = read ||
     406            (fs_info->concurrent_read_write && fs_info->write_retains_size);
    820407       
    821408        /*
     
    824411         * write implementation does not modify the file size.
    825412         */
    826         if ((read) ||
    827             ((fs_info->concurrent_read_write) && (fs_info->write_retains_size)))
     413        if (rlock)
    828414                fibril_rwlock_read_lock(&file->node->contents_rwlock);
    829415        else
     
    835421                 * while we are in readdir().
    836422                 */
    837                 assert(read);
     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               
    838436                fibril_rwlock_read_lock(&namespace_rwlock);
    839437        }
     
    842440       
    843441        if (!read && file->append)
    844                 file->pos = file->node->size;
     442                pos = file->node->size;
    845443       
    846444        /*
     
    848446         */
    849447        ipc_call_t answer;
    850         int rc = ipc_cb(fs_exch, file, &answer, read, ipc_cb_data);
     448        int rc = ipc_cb(fs_exch, file, pos, &answer, read, ipc_cb_data);
    851449       
    852450        vfs_exchange_release(fs_exch);
    853        
    854         size_t bytes = IPC_GET_ARG1(answer);
    855451       
    856452        if (file->node->type == VFS_NODE_DIRECTORY)
     
    858454       
    859455        /* Unlock the VFS node. */
    860         if ((read) ||
    861             ((fs_info->concurrent_read_write) && (fs_info->write_retains_size)))
     456        if (rlock) {
    862457                fibril_rwlock_read_unlock(&file->node->contents_rwlock);
    863         else {
     458        } else {
    864459                /* Update the cached version of node's size. */
    865                 if (rc == EOK)
     460                if (rc == EOK) {
    866461                        file->node->size = MERGE_LOUP32(IPC_GET_ARG2(answer),
    867462                            IPC_GET_ARG3(answer));
     463                }
    868464                fibril_rwlock_write_unlock(&file->node->contents_rwlock);
    869465        }
    870466       
    871         /* Update the position pointer and unlock the open file. */
     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);
    872593        if (rc == EOK)
    873                 file->pos += bytes;
    874         fibril_mutex_unlock(&file->lock);
    875         vfs_file_put(file);     
    876 
     594                file->node->size = size;
     595       
     596        fibril_rwlock_write_unlock(&file->node->contents_rwlock);
     597        vfs_file_put(file);
    877598        return rc;
    878599}
    879        
    880 static void vfs_rdwr_client(ipc_callid_t rid, ipc_call_t *request, bool read)
    881 {
    882         size_t bytes = 0;       
    883         int rc = vfs_rdwr(IPC_GET_ARG1(*request), read, rdwr_ipc_client,
    884             &bytes);
    885         async_answer_1(rid, rc, bytes);
    886 }
    887 
    888 int vfs_rdwr_internal(int fd, bool read, rdwr_io_chunk_t *chunk)
    889 {
    890         return vfs_rdwr(fd, read, rdwr_ipc_internal, chunk);
    891 }
    892 
    893 void vfs_read(ipc_callid_t rid, ipc_call_t *request)
    894 {
    895         vfs_rdwr_client(rid, request, true);
    896 }
    897 
    898 void vfs_write(ipc_callid_t rid, ipc_call_t *request)
    899 {
    900         vfs_rdwr_client(rid, request, false);
    901 }
    902 
    903 void vfs_seek(ipc_callid_t rid, ipc_call_t *request)
    904 {
    905         int fd = (int) IPC_GET_ARG1(*request);
    906         off64_t off = (off64_t) MERGE_LOUP32(IPC_GET_ARG2(*request),
    907             IPC_GET_ARG3(*request));
    908         int whence = (int) IPC_GET_ARG4(*request);
    909        
    910         /* Lookup the file structure corresponding to the file descriptor. */
     600
     601int vfs_op_stat(int fd)
     602{
    911603        vfs_file_t *file = vfs_file_get(fd);
    912         if (!file) {
    913                 async_answer_0(rid, ENOENT);
    914                 return;
    915         }
    916        
    917         fibril_mutex_lock(&file->lock);
    918        
    919         off64_t newoff;
    920         switch (whence) {
    921         case SEEK_SET:
    922                 if (off >= 0) {
    923                         file->pos = (aoff64_t) off;
    924                         fibril_mutex_unlock(&file->lock);
    925                         vfs_file_put(file);
    926                         async_answer_1(rid, EOK, off);
    927                         return;
    928                 }
    929                 break;
    930         case SEEK_CUR:
    931                 if ((off >= 0) && (file->pos + off < file->pos)) {
    932                         fibril_mutex_unlock(&file->lock);
    933                         vfs_file_put(file);
    934                         async_answer_0(rid, EOVERFLOW);
    935                         return;
    936                 }
    937                
    938                 if ((off < 0) && (file->pos < (aoff64_t) -off)) {
    939                         fibril_mutex_unlock(&file->lock);
    940                         vfs_file_put(file);
    941                         async_answer_0(rid, EOVERFLOW);
    942                         return;
    943                 }
    944                
    945                 file->pos += off;
    946                 newoff = (file->pos > OFF64_MAX) ? OFF64_MAX : file->pos;
    947                
    948                 fibril_mutex_unlock(&file->lock);
    949                 vfs_file_put(file);
    950                 async_answer_2(rid, EOK, LOWER32(newoff),
    951                     UPPER32(newoff));
    952                 return;
    953         case SEEK_END:
    954                 fibril_rwlock_read_lock(&file->node->contents_rwlock);
    955                 aoff64_t size = file->node->size;
    956                
    957                 if ((off >= 0) && (size + off < size)) {
    958                         fibril_rwlock_read_unlock(&file->node->contents_rwlock);
    959                         fibril_mutex_unlock(&file->lock);
    960                         vfs_file_put(file);
    961                         async_answer_0(rid, EOVERFLOW);
    962                         return;
    963                 }
    964                
    965                 if ((off < 0) && (size < (aoff64_t) -off)) {
    966                         fibril_rwlock_read_unlock(&file->node->contents_rwlock);
    967                         fibril_mutex_unlock(&file->lock);
    968                         vfs_file_put(file);
    969                         async_answer_0(rid, EOVERFLOW);
    970                         return;
    971                 }
    972                
    973                 file->pos = size + off;
    974                 newoff = (file->pos > OFF64_MAX) ?  OFF64_MAX : file->pos;
    975                
    976                 fibril_rwlock_read_unlock(&file->node->contents_rwlock);
    977                 fibril_mutex_unlock(&file->lock);
    978                 vfs_file_put(file);
    979                 async_answer_2(rid, EOK, LOWER32(newoff), UPPER32(newoff));
    980                 return;
    981         }
    982        
    983         fibril_mutex_unlock(&file->lock);
     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       
    984614        vfs_file_put(file);
    985         async_answer_0(rid, EINVAL);
    986 }
    987 
    988 int vfs_truncate_internal(fs_handle_t fs_handle, service_id_t service_id,
     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,
    989659    fs_index_t index, aoff64_t size)
    990660{
     
    998668}
    999669
    1000 void vfs_truncate(ipc_callid_t rid, ipc_call_t *request)
    1001 {
    1002         int fd = IPC_GET_ARG1(*request);
    1003         aoff64_t size = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG2(*request),
    1004             IPC_GET_ARG3(*request));
    1005         int rc;
    1006 
    1007         vfs_file_t *file = vfs_file_get(fd);
    1008         if (!file) {
    1009                 async_answer_0(rid, ENOENT);
    1010                 return;
    1011         }
    1012         fibril_mutex_lock(&file->lock);
    1013 
    1014         fibril_rwlock_write_lock(&file->node->contents_rwlock);
    1015         rc = vfs_truncate_internal(file->node->fs_handle,
    1016             file->node->service_id, file->node->index, size);
    1017         if (rc == EOK)
    1018                 file->node->size = size;
    1019         fibril_rwlock_write_unlock(&file->node->contents_rwlock);
    1020 
    1021         fibril_mutex_unlock(&file->lock);
    1022         vfs_file_put(file);
    1023         async_answer_0(rid, (sysarg_t)rc);
    1024 }
    1025 
    1026 void vfs_fstat(ipc_callid_t rid, ipc_call_t *request)
    1027 {
    1028         int fd = IPC_GET_ARG1(*request);
    1029         sysarg_t rc;
    1030 
    1031         vfs_file_t *file = vfs_file_get(fd);
    1032         if (!file) {
    1033                 async_answer_0(rid, ENOENT);
    1034                 return;
    1035         }
    1036 
    1037         ipc_callid_t callid;
    1038         if (!async_data_read_receive(&callid, NULL)) {
    1039                 vfs_file_put(file);
    1040                 async_answer_0(callid, EINVAL);
    1041                 async_answer_0(rid, EINVAL);
    1042                 return;
    1043         }
    1044 
    1045         fibril_mutex_lock(&file->lock);
    1046 
    1047         async_exch_t *exch = vfs_exchange_grab(file->node->fs_handle);
    1048        
    1049         aid_t msg;
    1050         msg = async_send_3(exch, VFS_OUT_STAT, file->node->service_id,
    1051             file->node->index, true, NULL);
    1052         async_forward_fast(callid, exch, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
    1053        
     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);
    1054781        vfs_exchange_release(exch);
    1055782       
    1056         async_wait_for(msg, &rc);
    1057        
    1058         fibril_mutex_unlock(&file->lock);
    1059         vfs_file_put(file);
    1060         async_answer_0(rid, rc);
    1061 }
    1062 
    1063 void vfs_stat(ipc_callid_t rid, ipc_call_t *request)
    1064 {
    1065         char *path;
    1066         int rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL);
    1067783        if (rc != EOK) {
    1068                 async_answer_0(rid, rc);
    1069                 return;
    1070         }
    1071        
    1072         ipc_callid_t callid;
    1073         if (!async_data_read_receive(&callid, NULL)) {
    1074                 free(path);
    1075                 async_answer_0(callid, EINVAL);
    1076                 async_answer_0(rid, EINVAL);
    1077                 return;
    1078         }
    1079 
     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       
    1080846        vfs_lookup_res_t lr;
    1081         fibril_rwlock_read_lock(&namespace_rwlock);
    1082         rc = vfs_lookup_internal(path, L_NONE, &lr, NULL);
    1083         free(path);
     847        int rc = vfs_lookup_internal(parent->node, path,
     848            walk_lookup_flags(flags), &lr);
    1084849        if (rc != EOK) {
    1085850                fibril_rwlock_read_unlock(&namespace_rwlock);
    1086                 async_answer_0(callid, rc);
    1087                 async_answer_0(rid, rc);
    1088                 return;
    1089         }
     851                vfs_file_put(parent);
     852                return rc;
     853        }
     854       
    1090855        vfs_node_t *node = vfs_node_get(&lr);
    1091856        if (!node) {
    1092857                fibril_rwlock_read_unlock(&namespace_rwlock);
    1093                 async_answer_0(callid, ENOMEM);
    1094                 async_answer_0(rid, ENOMEM);
    1095                 return;
    1096         }
    1097 
     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       
    1098879        fibril_rwlock_read_unlock(&namespace_rwlock);
    1099880
    1100         async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
    1101        
    1102         aid_t msg;
    1103         msg = async_send_3(exch, VFS_OUT_STAT, node->service_id,
    1104             node->index, false, NULL);
    1105         async_forward_fast(callid, exch, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
    1106        
    1107         vfs_exchange_release(exch);
    1108        
    1109         sysarg_t rv;
    1110         async_wait_for(msg, &rv);
    1111 
    1112         async_answer_0(rid, rv);
    1113 
    1114         vfs_node_put(node);
    1115 }
    1116 
    1117 void vfs_mkdir(ipc_callid_t rid, ipc_call_t *request)
    1118 {
    1119         int mode = IPC_GET_ARG1(*request);
    1120        
    1121         char *path;
    1122         int rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL);
    1123         if (rc != EOK) {
    1124                 async_answer_0(rid, rc);
    1125                 return;
    1126         }
    1127        
    1128         /* Ignore mode for now. */
    1129         (void) mode;
    1130        
    1131         fibril_rwlock_write_lock(&namespace_rwlock);
    1132         int lflag = L_DIRECTORY | L_CREATE | L_EXCLUSIVE;
    1133         rc = vfs_lookup_internal(path, lflag, NULL, NULL);
    1134         fibril_rwlock_write_unlock(&namespace_rwlock);
    1135         free(path);
    1136         async_answer_0(rid, rc);
    1137 }
    1138 
    1139 void vfs_unlink(ipc_callid_t rid, ipc_call_t *request)
    1140 {
    1141         int lflag = IPC_GET_ARG1(*request);
    1142        
    1143         char *path;
    1144         int rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL);
    1145         if (rc != EOK) {
    1146                 async_answer_0(rid, rc);
    1147                 return;
    1148         }
    1149        
    1150         fibril_rwlock_write_lock(&namespace_rwlock);
    1151         lflag &= L_DIRECTORY;   /* sanitize lflag */
    1152         vfs_lookup_res_t lr;
    1153         rc = vfs_lookup_internal(path, lflag | L_UNLINK, &lr, NULL);
    1154         free(path);
    1155         if (rc != EOK) {
    1156                 fibril_rwlock_write_unlock(&namespace_rwlock);
    1157                 async_answer_0(rid, rc);
    1158                 return;
    1159         }
    1160 
    1161         /*
    1162          * The name has already been unlinked by vfs_lookup_internal().
    1163          * We have to get and put the VFS node to ensure that it is
    1164          * VFS_OUT_DESTROY'ed after the last reference to it is dropped.
    1165          */
    1166         vfs_node_t *node = vfs_node_get(&lr);
    1167         fibril_mutex_lock(&nodes_mutex);
    1168         node->lnkcnt--;
    1169         fibril_mutex_unlock(&nodes_mutex);
    1170         fibril_rwlock_write_unlock(&namespace_rwlock);
    1171         vfs_node_put(node);
    1172         async_answer_0(rid, EOK);
    1173 }
    1174 
    1175 void vfs_rename(ipc_callid_t rid, ipc_call_t *request)
    1176 {
    1177         /* Retrieve the old path. */
    1178         char *old;
    1179         int rc = async_data_write_accept((void **) &old, true, 0, 0, 0, NULL);
    1180         if (rc != EOK) {
    1181                 async_answer_0(rid, rc);
    1182                 return;
    1183         }
    1184        
    1185         /* Retrieve the new path. */
    1186         char *new;
    1187         rc = async_data_write_accept((void **) &new, true, 0, 0, 0, NULL);
    1188         if (rc != EOK) {
    1189                 free(old);
    1190                 async_answer_0(rid, rc);
    1191                 return;
    1192         }
    1193        
    1194         size_t olen;
    1195         size_t nlen;
    1196         char *oldc = canonify(old, &olen);
    1197         char *newc = canonify(new, &nlen);
    1198        
    1199         if ((!oldc) || (!newc)) {
    1200                 async_answer_0(rid, EINVAL);
    1201                 free(old);
    1202                 free(new);
    1203                 return;
    1204         }
    1205        
    1206         oldc[olen] = '\0';
    1207         newc[nlen] = '\0';
    1208        
    1209         if ((!str_lcmp(newc, oldc, str_length(oldc))) &&
    1210             ((newc[str_length(oldc)] == '/') ||
    1211             (str_length(oldc) == 1) ||
    1212             (str_length(oldc) == str_length(newc)))) {
    1213                 /*
    1214                  * oldc is a prefix of newc and either
    1215                  * - newc continues with a / where oldc ends, or
    1216                  * - oldc was / itself, or
    1217                  * - oldc and newc are equal.
    1218                  */
    1219                 async_answer_0(rid, EINVAL);
    1220                 free(old);
    1221                 free(new);
    1222                 return;
    1223         }
    1224        
    1225         vfs_lookup_res_t old_lr;
    1226         vfs_lookup_res_t new_lr;
    1227         vfs_lookup_res_t new_par_lr;
    1228         fibril_rwlock_write_lock(&namespace_rwlock);
    1229        
    1230         /* Lookup the node belonging to the old file name. */
    1231         rc = vfs_lookup_internal(oldc, L_NONE, &old_lr, NULL);
    1232         if (rc != EOK) {
    1233                 fibril_rwlock_write_unlock(&namespace_rwlock);
    1234                 async_answer_0(rid, rc);
    1235                 free(old);
    1236                 free(new);
    1237                 return;
    1238         }
    1239        
    1240         vfs_node_t *old_node = vfs_node_get(&old_lr);
    1241         if (!old_node) {
    1242                 fibril_rwlock_write_unlock(&namespace_rwlock);
    1243                 async_answer_0(rid, ENOMEM);
    1244                 free(old);
    1245                 free(new);
    1246                 return;
    1247         }
    1248        
    1249         /* Determine the path to the parent of the node with the new name. */
    1250         char *parentc = str_dup(newc);
    1251         if (!parentc) {
    1252                 fibril_rwlock_write_unlock(&namespace_rwlock);
    1253                 vfs_node_put(old_node);
    1254                 async_answer_0(rid, rc);
    1255                 free(old);
    1256                 free(new);
    1257                 return;
    1258         }
    1259        
    1260         char *lastsl = str_rchr(parentc + 1, '/');
    1261         if (lastsl)
    1262                 *lastsl = '\0';
    1263         else
    1264                 parentc[1] = '\0';
    1265        
    1266         /* Lookup parent of the new file name. */
    1267         rc = vfs_lookup_internal(parentc, L_NONE, &new_par_lr, NULL);
    1268         free(parentc);  /* not needed anymore */
    1269         if (rc != EOK) {
    1270                 fibril_rwlock_write_unlock(&namespace_rwlock);
    1271                 vfs_node_put(old_node);
    1272                 async_answer_0(rid, rc);
    1273                 free(old);
    1274                 free(new);
    1275                 return;
    1276         }
    1277        
    1278         /* Check whether linking to the same file system instance. */
    1279         if ((old_node->fs_handle != new_par_lr.triplet.fs_handle) ||
    1280             (old_node->service_id != new_par_lr.triplet.service_id)) {
    1281                 fibril_rwlock_write_unlock(&namespace_rwlock);
    1282                 vfs_node_put(old_node);
    1283                 async_answer_0(rid, EXDEV);     /* different file systems */
    1284                 free(old);
    1285                 free(new);
    1286                 return;
    1287         }
    1288        
    1289         /* Destroy the old link for the new name. */
    1290         vfs_node_t *new_node = NULL;
    1291         rc = vfs_lookup_internal(newc, L_UNLINK, &new_lr, NULL);
    1292        
    1293         switch (rc) {
    1294         case ENOENT:
    1295                 /* simply not in our way */
    1296                 break;
    1297         case EOK:
    1298                 new_node = vfs_node_get(&new_lr);
    1299                 if (!new_node) {
    1300                         fibril_rwlock_write_unlock(&namespace_rwlock);
    1301                         vfs_node_put(old_node);
    1302                         async_answer_0(rid, ENOMEM);
    1303                         free(old);
    1304                         free(new);
    1305                         return;
    1306                 }
    1307                 fibril_mutex_lock(&nodes_mutex);
    1308                 new_node->lnkcnt--;
    1309                 fibril_mutex_unlock(&nodes_mutex);
    1310                 break;
    1311         default:
    1312                 fibril_rwlock_write_unlock(&namespace_rwlock);
    1313                 vfs_node_put(old_node);
    1314                 async_answer_0(rid, ENOTEMPTY);
    1315                 free(old);
    1316                 free(new);
    1317                 return;
    1318         }
    1319        
    1320         /* Create the new link for the new name. */
    1321         rc = vfs_lookup_internal(newc, L_LINK, NULL, NULL, old_node->index);
    1322         if (rc != EOK) {
    1323                 fibril_rwlock_write_unlock(&namespace_rwlock);
    1324                 vfs_node_put(old_node);
    1325                 if (new_node)
    1326                         vfs_node_put(new_node);
    1327                 async_answer_0(rid, rc);
    1328                 free(old);
    1329                 free(new);
    1330                 return;
    1331         }
    1332        
    1333         fibril_mutex_lock(&nodes_mutex);
    1334         old_node->lnkcnt++;
    1335         fibril_mutex_unlock(&nodes_mutex);
    1336        
    1337         /* Destroy the link for the old name. */
    1338         rc = vfs_lookup_internal(oldc, L_UNLINK, NULL, NULL);
    1339         if (rc != EOK) {
    1340                 fibril_rwlock_write_unlock(&namespace_rwlock);
    1341                 vfs_node_put(old_node);
    1342                 if (new_node)
    1343                         vfs_node_put(new_node);
    1344                 async_answer_0(rid, rc);
    1345                 free(old);
    1346                 free(new);
    1347                 return;
    1348         }
    1349        
    1350         fibril_mutex_lock(&nodes_mutex);
    1351         old_node->lnkcnt--;
    1352         fibril_mutex_unlock(&nodes_mutex);
    1353         fibril_rwlock_write_unlock(&namespace_rwlock);
    1354         vfs_node_put(old_node);
    1355        
    1356         if (new_node)
    1357                 vfs_node_put(new_node);
    1358        
    1359         free(old);
    1360         free(new);
    1361         async_answer_0(rid, EOK);
    1362 }
    1363 
    1364 void vfs_dup(ipc_callid_t rid, ipc_call_t *request)
    1365 {
    1366         int oldfd = IPC_GET_ARG1(*request);
    1367         int newfd = IPC_GET_ARG2(*request);
    1368        
    1369         /* If the file descriptors are the same, do nothing. */
    1370         if (oldfd == newfd) {
    1371                 async_answer_1(rid, EOK, newfd);
    1372                 return;
    1373         }
    1374        
    1375         /* Lookup the file structure corresponding to oldfd. */
    1376         vfs_file_t *oldfile = vfs_file_get(oldfd);
    1377         if (!oldfile) {
    1378                 async_answer_0(rid, EBADF);
    1379                 return;
    1380         }
    1381        
    1382         /*
    1383          * Lock the open file structure so that no other thread can manipulate
    1384          * the same open file at a time.
    1385          */
    1386         fibril_mutex_lock(&oldfile->lock);
    1387        
    1388         /* Make sure newfd is closed. */
    1389         (void) vfs_fd_free(newfd);
    1390        
    1391         /* Assign the old file to newfd. */
    1392         int ret = vfs_fd_assign(oldfile, newfd);
    1393         fibril_mutex_unlock(&oldfile->lock);
    1394         vfs_file_put(oldfile);
    1395        
    1396         if (ret != EOK)
    1397                 async_answer_0(rid, ret);
    1398         else
    1399                 async_answer_1(rid, EOK, newfd);
    1400 }
    1401 
    1402 void vfs_wait_handle(ipc_callid_t rid, ipc_call_t *request)
    1403 {
    1404         int fd = vfs_wait_handle_internal();
    1405         async_answer_1(rid, EOK, fd);
    1406 }
    1407 
    1408 void vfs_get_mtab(ipc_callid_t rid, ipc_call_t *request)
    1409 {
    1410         ipc_callid_t callid;
    1411         ipc_call_t data;
    1412         sysarg_t rc = EOK;
    1413         size_t len;
    1414 
    1415         fibril_mutex_lock(&mtab_list_lock);
    1416 
    1417         /* Send to the caller the number of mounted filesystems */
    1418         callid = async_get_call(&data);
    1419         if (IPC_GET_IMETHOD(data) != VFS_IN_PING) {
    1420                 rc = ENOTSUP;
    1421                 async_answer_0(callid, rc);
    1422                 goto exit;
    1423         }
    1424         async_answer_1(callid, EOK, mtab_size);
    1425 
    1426         list_foreach(mtab_list, link, mtab_ent_t, mtab_ent) {
    1427                 rc = ENOTSUP;
    1428 
    1429                 if (!async_data_read_receive(&callid, &len)) {
    1430                         async_answer_0(callid, rc);
    1431                         goto exit;
    1432                 }
    1433 
    1434                 (void) async_data_read_finalize(callid, mtab_ent->mp,
    1435                     str_size(mtab_ent->mp));
    1436 
    1437                 if (!async_data_read_receive(&callid, &len)) {
    1438                         async_answer_0(callid, rc);
    1439                         goto exit;
    1440                 }
    1441 
    1442                 (void) async_data_read_finalize(callid, mtab_ent->opts,
    1443                     str_size(mtab_ent->opts));
    1444 
    1445                 if (!async_data_read_receive(&callid, &len)) {
    1446                         async_answer_0(callid, rc);
    1447                         goto exit;
    1448                 }
    1449 
    1450                 (void) async_data_read_finalize(callid, mtab_ent->fs_name,
    1451                     str_size(mtab_ent->fs_name));
    1452 
    1453                 callid = async_get_call(&data);
    1454 
    1455                 if (IPC_GET_IMETHOD(data) != VFS_IN_PING) {
    1456                         async_answer_0(callid, rc);
    1457                         goto exit;
    1458                 }
    1459 
    1460                 rc = EOK;
    1461                 async_answer_2(callid, rc, mtab_ent->instance,
    1462                     mtab_ent->service_id);
    1463         }
    1464 
    1465 exit:
    1466         fibril_mutex_unlock(&mtab_list_lock);
    1467         async_answer_0(rid, rc);
    1468 }
    1469 
    1470 void vfs_statfs(ipc_callid_t rid, ipc_call_t *request)
    1471 {
    1472         char *path;
    1473         int rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL);
    1474         if (rc != EOK) {
    1475                 async_answer_0(rid, rc);
    1476                 return;
    1477         }
    1478        
    1479         ipc_callid_t callid;
    1480         if (!async_data_read_receive(&callid, NULL)) {
    1481                 free(path);
    1482                 async_answer_0(callid, EINVAL);
    1483                 async_answer_0(rid, EINVAL);
    1484                 return;
    1485         }
    1486 
    1487         vfs_lookup_res_t lr;
    1488         fibril_rwlock_read_lock(&namespace_rwlock);
    1489         rc = vfs_lookup_internal(path, L_NONE, &lr, NULL);
    1490         free(path);
    1491         if (rc != EOK) {
    1492                 fibril_rwlock_read_unlock(&namespace_rwlock);
    1493                 async_answer_0(callid, rc);
    1494                 async_answer_0(rid, rc);
    1495                 return;
    1496         }
    1497         vfs_node_t *node = vfs_node_get(&lr);
    1498         if (!node) {
    1499                 fibril_rwlock_read_unlock(&namespace_rwlock);
    1500                 async_answer_0(callid, ENOMEM);
    1501                 async_answer_0(rid, ENOMEM);
    1502                 return;
    1503         }
    1504 
    1505         fibril_rwlock_read_unlock(&namespace_rwlock);
    1506 
    1507         async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
    1508        
    1509         aid_t msg;
    1510         msg = async_send_3(exch, VFS_OUT_STATFS, node->service_id,
    1511             node->index, false, NULL);
    1512         async_forward_fast(callid, exch, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
    1513        
    1514         vfs_exchange_release(exch);
    1515        
    1516         sysarg_t rv;
    1517         async_wait_for(msg, &rv);
    1518 
    1519         async_answer_0(rid, rv);
    1520 
    1521         vfs_node_put(node);
     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);
    1522888}
    1523889
  • uspace/srv/vfs/vfs_pager.c

    r39f892a9 r368ee04  
    5050        int rc;
    5151
    52         vfs_file_t *file = vfs_file_get(fd);
    53         if (!file) {
    54                 async_answer_0(rid, ENOENT);
    55                 return;
    56         }
    57 
    5852        page = as_area_create(AS_AREA_ANY, page_size,
    5953            AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE,
     
    6155
    6256        if (page == AS_MAP_FAILED) {
    63                 vfs_file_put(file);
    6457                async_answer_0(rid, ENOMEM);
    6558                return;
     
    7164        };
    7265
    73         fibril_mutex_lock(&file->lock);
    74         file->pos = offset;
    75         fibril_mutex_unlock(&file->lock);
    76 
    7766        size_t total = 0;
     67        aoff64_t pos = offset;
    7868        do {
    79                 rc = vfs_rdwr_internal(fd, true, &chunk);
     69                rc = vfs_rdwr_internal(fd, pos, true, &chunk);
    8070                if (rc != EOK)
    8171                        break;
     
    8373                        break;
    8474                total += chunk.size;
     75                pos += chunk.size;
    8576                chunk.buffer += chunk.size;
    8677                chunk.size = page_size - total;
    8778        } while (total < page_size);
    88 
    89         vfs_file_put(file);
    9079
    9180        async_answer_1(rid, rc, (sysarg_t) page);
  • uspace/srv/vfs/vfs_register.c

    r39f892a9 r368ee04  
    296296 *
    297297 */
    298 fs_handle_t fs_name_to_handle(unsigned int instance, char *name, bool lock)
     298fs_handle_t fs_name_to_handle(unsigned int instance, const char *name, bool lock)
    299299{
    300300        int handle = 0;
Note: See TracChangeset for help on using the changeset viewer.