Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/vfs/vfs_ops.c

    rb1956e3 r51774cd  
    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
Note: See TracChangeset for help on using the changeset viewer.