Ignore:
File:
1 edited

Legend:

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

    rb4cbef1 r2b88074b  
    4444#include <string.h>
    4545#include <bool.h>
    46 #include <fibril_synch.h>
     46#include <fibril_sync.h>
    4747#include <adt/list.h>
    4848#include <unistd.h>
     
    9292                }
    9393               
    94                 rc = vfs_lookup_internal(mp, L_MP, &mp_res, NULL);
     94                rc = vfs_lookup_internal(mp, L_DIRECTORY, &mp_res, NULL);
    9595                if (rc != EOK) {
    9696                        /* The lookup failed for some reason. */
     
    266266       
    267267        /* We want the client to send us the mount point. */
    268         char *mp;
    269         int rc = async_string_receive(&mp, MAX_PATH_LEN, NULL);
    270         if (rc != EOK) {
    271                 ipc_answer_0(rid, rc);
    272                 return;
    273         }
     268        ipc_callid_t callid;
     269        size_t size;
     270        if (!async_data_write_receive(&callid, &size)) {
     271                ipc_answer_0(callid, EINVAL);
     272                ipc_answer_0(rid, EINVAL);
     273                return;
     274        }
     275       
     276        /* Check whether size is reasonable wrt. the mount point. */
     277        if ((size < 1) || (size > MAX_PATH_LEN)) {
     278                ipc_answer_0(callid, EINVAL);
     279                ipc_answer_0(rid, EINVAL);
     280                return;
     281        }
     282       
     283        /* Allocate buffer for the mount point data being received. */
     284        char *mp = malloc(size + 1);
     285        if (!mp) {
     286                ipc_answer_0(callid, ENOMEM);
     287                ipc_answer_0(rid, ENOMEM);
     288                return;
     289        }
     290       
     291        /* Deliver the mount point. */
     292        ipcarg_t retval = async_data_write_finalize(callid, mp, size);
     293        if (retval != EOK) {
     294                ipc_answer_0(rid, retval);
     295                free(mp);
     296                return;
     297        }
     298        mp[size] = '\0';
    274299       
    275300        /* Now we expect to receive the mount options. */
    276         char *opts;
    277         rc = async_string_receive(&opts, MAX_MNTOPTS_LEN, NULL);
    278         if (rc != EOK) {
     301        if (!async_data_write_receive(&callid, &size)) {
     302                ipc_answer_0(callid, EINVAL);
     303                ipc_answer_0(rid, EINVAL);
    279304                free(mp);
    280                 ipc_answer_0(rid, rc);
    281                 return;
    282         }
     305                return;
     306        }
     307
     308        /* Check the offered options size. */
     309        if (size > MAX_MNTOPTS_LEN) {
     310                ipc_answer_0(callid, EINVAL);
     311                ipc_answer_0(rid, EINVAL);
     312                free(mp);
     313                return;
     314        }
     315
     316        /* Allocate buffer for the mount options. */
     317        char *opts = (char *) malloc(size + 1);
     318        if (!opts) {
     319                ipc_answer_0(callid, ENOMEM);
     320                ipc_answer_0(rid, ENOMEM);
     321                free(mp);
     322                return;
     323        }
     324
     325        /* Deliver the mount options. */
     326        retval = async_data_write_finalize(callid, opts, size);
     327        if (retval != EOK) {
     328                ipc_answer_0(rid, retval);
     329                free(mp);
     330                free(opts);
     331                return;
     332        }
     333        opts[size] = '\0';
    283334       
    284335        /*
     
    286337         * system.
    287338         */
    288         char *fs_name;
    289         rc = async_string_receive(&fs_name, FS_NAME_MAXLEN, NULL);
    290         if (rc != EOK) {
     339        if (!async_data_write_receive(&callid, &size)) {
     340                ipc_answer_0(callid, EINVAL);
     341                ipc_answer_0(rid, EINVAL);
    291342                free(mp);
    292343                free(opts);
    293                 ipc_answer_0(rid, rc);
    294                 return;
    295         }
    296        
     344                return;
     345        }
     346       
     347        /*
     348         * Don't receive more than is necessary for storing a full file system
     349         * name.
     350         */
     351        if ((size < 1) || (size > FS_NAME_MAXLEN)) {
     352                ipc_answer_0(callid, EINVAL);
     353                ipc_answer_0(rid, EINVAL);
     354                free(mp);
     355                free(opts);
     356                return;
     357        }
     358       
     359        /*
     360         * Allocate buffer for file system name.
     361         */
     362        char *fs_name = (char *) malloc(size + 1);
     363        if (fs_name == NULL) {
     364                ipc_answer_0(callid, ENOMEM);
     365                ipc_answer_0(rid, ENOMEM);
     366                free(mp);
     367                free(opts);
     368                return;
     369        }
     370       
     371        /* Deliver the file system name. */
     372        retval = async_data_write_finalize(callid, fs_name, size);
     373        if (retval != EOK) {
     374                ipc_answer_0(rid, retval);
     375                free(mp);
     376                free(opts);
     377                free(fs_name);
     378                return;
     379        }
     380        fs_name[size] = '\0';
     381
    297382        /*
    298383         * Wait for IPC_M_PING so that we can return an error if we don't know
     
    300385         */
    301386        ipc_call_t data;
    302         ipc_callid_t callid = async_get_call(&data);
     387        callid = async_get_call(&data);
    303388        if (IPC_GET_METHOD(data) != IPC_M_PING) {
    304389                ipc_answer_0(callid, ENOTSUP);
     
    344429}
    345430
    346 void vfs_unmount(ipc_callid_t rid, ipc_call_t *request)
    347 {
    348         int rc;
    349         char *mp;
    350         vfs_lookup_res_t mp_res;
    351         vfs_lookup_res_t mr_res;
    352         vfs_node_t *mp_node;
    353         vfs_node_t *mr_node;
    354         int phone;
    355 
    356         /*
    357          * Receive the mount point path.
    358          */
    359         rc = async_string_receive(&mp, MAX_PATH_LEN, NULL);
    360         if (rc != EOK)
    361                 ipc_answer_0(rid, rc);
    362 
    363         /*
    364          * Taking the namespace lock will do two things for us. First, it will
    365          * prevent races with other lookup operations. Second, it will stop new
    366          * references to already existing VFS nodes and creation of new VFS
    367          * nodes. This is because new references are added as a result of some
    368          * lookup operation or at least of some operation which is protected by
    369          * the namespace lock.
    370          */
    371         fibril_rwlock_write_lock(&namespace_rwlock);
    372        
    373         /*
    374          * Lookup the mounted root and instantiate it.
    375          */
    376         rc = vfs_lookup_internal(mp, L_ROOT, &mr_res, NULL);
    377         if (rc != EOK) {
    378                 fibril_rwlock_write_unlock(&namespace_rwlock);
    379                 free(mp);
    380                 ipc_answer_0(rid, rc);
    381                 return;
    382         }
    383         mr_node = vfs_node_get(&mr_res);
    384         if (!mr_node) {
    385                 fibril_rwlock_write_unlock(&namespace_rwlock);
    386                 free(mp);
    387                 ipc_answer_0(rid, ENOMEM);
    388                 return;
    389         }
    390 
    391         /*
    392          * Count the total number of references for the mounted file system. We
    393          * are expecting at least two. One which we got above and one which we
    394          * got when the file system was mounted. If we find more, it means that
    395          * the file system cannot be gracefully unmounted at the moment because
    396          * someone is working with it.
    397          */
    398         if (vfs_nodes_refcount_sum_get(mr_node->fs_handle,
    399             mr_node->dev_handle) != 2) {
    400                 fibril_rwlock_write_unlock(&namespace_rwlock);
    401                 vfs_node_put(mr_node);
    402                 free(mp);
    403                 ipc_answer_0(rid, EBUSY);
    404                 return;
    405         }
    406 
    407         if (str_cmp(mp, "/") == 0) {
    408 
    409                 /*
    410                  * Unmounting the root file system.
    411                  *
    412                  * In this case, there is no mount point node and we send
    413                  * VFS_OUT_UNMOUNTED directly to the mounted file system.
    414                  */
    415 
    416                 free(mp);
    417                 phone = vfs_grab_phone(mr_node->fs_handle);
    418                 rc = async_req_1_0(phone, VFS_OUT_UNMOUNTED,
    419                     mr_node->dev_handle);
    420                 vfs_release_phone(phone);
    421                 if (rc != EOK) {
    422                         fibril_rwlock_write_unlock(&namespace_rwlock);
    423                         vfs_node_put(mr_node);
    424                         ipc_answer_0(rid, rc);
    425                         return;
    426                 }
    427                 rootfs.fs_handle = 0;
    428                 rootfs.dev_handle = 0;
    429         } else {
    430 
    431                 /*
    432                  * Unmounting a non-root file system.
    433                  *
    434                  * We have a regular mount point node representing the parent
    435                  * file system, so we delegate the operation to it.
    436                  */
    437 
    438                 rc = vfs_lookup_internal(mp, L_MP, &mp_res, NULL);
    439                 free(mp);
    440                 if (rc != EOK) {
    441                         fibril_rwlock_write_unlock(&namespace_rwlock);
    442                         vfs_node_put(mr_node);
    443                         ipc_answer_0(rid, rc);
    444                         return;
    445                 }
    446                 vfs_node_t *mp_node = vfs_node_get(&mp_res);
    447                 if (!mp_node) {
    448                         fibril_rwlock_write_unlock(&namespace_rwlock);
    449                         vfs_node_put(mr_node);
    450                         ipc_answer_0(rid, ENOMEM);
    451                         return;
    452                 }
    453 
    454                 phone = vfs_grab_phone(mp_node->fs_handle);
    455                 rc = async_req_2_0(phone, VFS_OUT_UNMOUNT, mp_node->dev_handle,
    456                     mp_node->index);
    457                 vfs_release_phone(phone);
    458                 if (rc != EOK) {
    459                         fibril_rwlock_write_unlock(&namespace_rwlock);
    460                         vfs_node_put(mp_node);
    461                         vfs_node_put(mr_node);
    462                         ipc_answer_0(rid, rc);
    463                         return;
    464                 }
    465 
    466                 /* Drop the reference we got above. */
    467                 vfs_node_put(mp_node);
    468                 /* Drop the reference from when the file system was mounted. */
    469                 vfs_node_put(mp_node);
    470         }
    471 
    472 
    473         /*
    474          * All went well, the mounted file system was successfully unmounted.
    475          * The only thing left is to forget the unmounted root VFS node.
    476          */
    477         vfs_node_forget(mr_node);
    478 
    479         fibril_rwlock_write_unlock(&namespace_rwlock);
    480         ipc_answer_0(rid, EOK);
    481 }
    482 
    483431void vfs_open(ipc_callid_t rid, ipc_call_t *request)
    484432{
     
    506454        /*
    507455         * Make sure that we are called with exactly one of L_FILE and
    508          * L_DIRECTORY. Make sure that the user does not pass L_OPEN,
    509          * L_ROOT or L_MP.
     456         * L_DIRECTORY. Make sure that the user does not pass L_OPEN.
    510457         */
    511458        if (((lflag & (L_FILE | L_DIRECTORY)) == 0) ||
    512459            ((lflag & (L_FILE | L_DIRECTORY)) == (L_FILE | L_DIRECTORY)) ||
    513             (lflag & (L_OPEN | L_ROOT | L_MP))) {
     460            ((lflag & L_OPEN) != 0)) {
    514461                ipc_answer_0(rid, EINVAL);
    515462                return;
     
    521468                lflag |= L_EXCLUSIVE;
    522469       
    523         char *path;
    524         int rc = async_string_receive(&path, 0, NULL);
    525         if (rc != EOK) {
    526                 ipc_answer_0(rid, rc);
    527                 return;
    528         }
     470        ipc_callid_t callid;
     471        if (!async_data_write_receive(&callid, &len)) {
     472                ipc_answer_0(callid, EINVAL);
     473                ipc_answer_0(rid, EINVAL);
     474                return;
     475        }
     476       
     477        char *path = malloc(len + 1);
     478        if (!path) {
     479                ipc_answer_0(callid, ENOMEM);
     480                ipc_answer_0(rid, ENOMEM);
     481                return;
     482        }
     483       
     484        int rc;
     485        if ((rc = async_data_write_finalize(callid, path, len))) {
     486                ipc_answer_0(rid, rc);
     487                free(path);
     488                return;
     489        }
     490        path[len] = '\0';
    529491       
    530492        /*
     
    717679}
    718680
    719 int vfs_close_internal(vfs_file_t *file)
     681static int vfs_close_internal(vfs_file_t *file)
    720682{
    721683        /*
     
    794756       
    795757        /*
     758         * Now we need to receive a call with client's
     759         * IPC_M_DATA_READ/IPC_M_DATA_WRITE request.
     760         */
     761        ipc_callid_t callid;
     762        int res;
     763        if (read)
     764                res = async_data_read_receive(&callid, NULL);
     765        else
     766                res = async_data_write_receive(&callid, NULL);
     767        if (!res) {
     768                ipc_answer_0(callid, EINVAL);
     769                ipc_answer_0(rid, EINVAL);
     770                return;
     771        }
     772       
     773        /*
    796774         * Lock the open file structure so that no other thread can manipulate
    797775         * the same open file at a time.
     
    817795        }
    818796       
    819         int fs_phone = vfs_grab_phone(file->node->fs_handle);
    820        
    821         /*
    822          * Make a VFS_READ/VFS_WRITE request at the destination FS server
    823          * and forward the IPC_M_DATA_READ/IPC_M_DATA_WRITE request to the
     797        int fs_phone = vfs_grab_phone(file->node->fs_handle);   
     798       
     799        /* Make a VFS_READ/VFS_WRITE request at the destination FS server. */
     800        aid_t msg;
     801        ipc_call_t answer;
     802        if (!read && file->append)
     803                file->pos = file->node->size;
     804        msg = async_send_3(fs_phone, read ? VFS_OUT_READ : VFS_OUT_WRITE,
     805            file->node->dev_handle, file->node->index, file->pos, &answer);
     806       
     807        /*
     808         * Forward the IPC_M_DATA_READ/IPC_M_DATA_WRITE request to the
    824809         * destination FS server. The call will be routed as if sent by
    825810         * ourselves. Note that call arguments are immutable in this case so we
    826811         * don't have to bother.
    827812         */
     813        ipc_forward_fast(callid, fs_phone, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
     814
     815        /* Wait for reply from the FS server. */
    828816        ipcarg_t rc;
    829         ipc_call_t answer;
    830         if (read) {
    831                 if (file->append)
    832                         file->pos = file->node->size;
    833                
    834                 rc = async_data_read_forward_3_1(fs_phone, VFS_OUT_READ,
    835                     file->node->dev_handle, file->node->index, file->pos,
    836                     &answer);
    837         } else {
    838                 rc = async_data_forward_3_1(fs_phone, VFS_OUT_WRITE,
    839                     file->node->dev_handle, file->node->index, file->pos,
    840                     &answer);
    841         }
     817        async_wait_for(msg, &rc);
    842818       
    843819        vfs_release_phone(fs_phone);
    844820       
    845821        size_t bytes = IPC_GET_ARG1(answer);
    846        
     822
    847823        if (file->node->type == VFS_NODE_DIRECTORY)
    848824                fibril_rwlock_read_unlock(&namespace_rwlock);
     
    924900                }
    925901                newpos = size + off;
    926                 file->pos = newpos;
    927902                fibril_mutex_unlock(&file->lock);
    928903                ipc_answer_1(rid, EOK, newpos);
     
    1006981void vfs_stat(ipc_callid_t rid, ipc_call_t *request)
    1007982{
    1008         char *path;
    1009         int rc = async_string_receive(&path, 0, NULL);
    1010         if (rc != EOK) {
    1011                 ipc_answer_0(rid, rc);
    1012                 return;
    1013         }
    1014        
     983        size_t len;
    1015984        ipc_callid_t callid;
     985
     986        if (!async_data_write_receive(&callid, &len)) {
     987                ipc_answer_0(callid, EINVAL);
     988                ipc_answer_0(rid, EINVAL);
     989                return;
     990        }
     991        char *path = malloc(len + 1);
     992        if (!path) {
     993                ipc_answer_0(callid, ENOMEM);
     994                ipc_answer_0(rid, ENOMEM);
     995                return;
     996        }
     997        int rc;
     998        if ((rc = async_data_write_finalize(callid, path, len))) {
     999                ipc_answer_0(rid, rc);
     1000                free(path);
     1001                return;
     1002        }
     1003        path[len] = '\0';
     1004
    10161005        if (!async_data_read_receive(&callid, NULL)) {
    10171006                free(path);
     
    10591048{
    10601049        int mode = IPC_GET_ARG1(*request);
    1061        
    1062         char *path;
    1063         int rc = async_string_receive(&path, 0, NULL);
    1064         if (rc != EOK) {
    1065                 ipc_answer_0(rid, rc);
    1066                 return;
    1067         }
    1068        
     1050
     1051        size_t len;
     1052        ipc_callid_t callid;
     1053
     1054        if (!async_data_write_receive(&callid, &len)) {
     1055                ipc_answer_0(callid, EINVAL);
     1056                ipc_answer_0(rid, EINVAL);
     1057                return;
     1058        }
     1059        char *path = malloc(len + 1);
     1060        if (!path) {
     1061                ipc_answer_0(callid, ENOMEM);
     1062                ipc_answer_0(rid, ENOMEM);
     1063                return;
     1064        }
     1065        int rc;
     1066        if ((rc = async_data_write_finalize(callid, path, len))) {
     1067                ipc_answer_0(rid, rc);
     1068                free(path);
     1069                return;
     1070        }
     1071        path[len] = '\0';
     1072
    10691073        /* Ignore mode for now. */
    10701074        (void) mode;
     
    10811085{
    10821086        int lflag = IPC_GET_ARG1(*request);
    1083        
    1084         char *path;
    1085         int rc = async_string_receive(&path, 0, NULL);
    1086         if (rc != EOK) {
    1087                 ipc_answer_0(rid, rc);
    1088                 return;
    1089         }
     1087
     1088        size_t len;
     1089        ipc_callid_t callid;
     1090
     1091        if (!async_data_write_receive(&callid, &len)) {
     1092                ipc_answer_0(callid, EINVAL);
     1093                ipc_answer_0(rid, EINVAL);
     1094                return;
     1095        }
     1096        char *path = malloc(len + 1);
     1097        if (!path) {
     1098                ipc_answer_0(callid, ENOMEM);
     1099                ipc_answer_0(rid, ENOMEM);
     1100                return;
     1101        }
     1102        int rc;
     1103        if ((rc = async_data_write_finalize(callid, path, len))) {
     1104                ipc_answer_0(rid, rc);
     1105                free(path);
     1106                return;
     1107        }
     1108        path[len] = '\0';
    10901109       
    10911110        fibril_rwlock_write_lock(&namespace_rwlock);
     
    11161135void vfs_rename(ipc_callid_t rid, ipc_call_t *request)
    11171136{
     1137        size_t olen, nlen;
     1138        ipc_callid_t callid;
     1139        int rc;
     1140
    11181141        /* Retrieve the old path. */
    1119         char *old;
    1120         int rc = async_string_receive(&old, 0, NULL);
    1121         if (rc != EOK) {
    1122                 ipc_answer_0(rid, rc);
    1123                 return;
    1124         }
     1142        if (!async_data_write_receive(&callid, &olen)) {
     1143                ipc_answer_0(callid, EINVAL);
     1144                ipc_answer_0(rid, EINVAL);
     1145                return;
     1146        }
     1147        char *old = malloc(olen + 1);
     1148        if (!old) {
     1149                ipc_answer_0(callid, ENOMEM);
     1150                ipc_answer_0(rid, ENOMEM);
     1151                return;
     1152        }
     1153        if ((rc = async_data_write_finalize(callid, old, olen))) {
     1154                ipc_answer_0(rid, rc);
     1155                free(old);
     1156                return;
     1157        }
     1158        old[olen] = '\0';
    11251159       
    11261160        /* Retrieve the new path. */
    1127         char *new;
    1128         rc = async_string_receive(&new, 0, NULL);
    1129         if (rc != EOK) {
     1161        if (!async_data_write_receive(&callid, &nlen)) {
     1162                ipc_answer_0(callid, EINVAL);
     1163                ipc_answer_0(rid, EINVAL);
    11301164                free(old);
    1131                 ipc_answer_0(rid, rc);
    1132                 return;
    1133         }
    1134        
    1135         size_t olen;
    1136         size_t nlen;
     1165                return;
     1166        }
     1167        char *new = malloc(nlen + 1);
     1168        if (!new) {
     1169                ipc_answer_0(callid, ENOMEM);
     1170                ipc_answer_0(rid, ENOMEM);
     1171                free(old);
     1172                return;
     1173        }
     1174        if ((rc = async_data_write_finalize(callid, new, nlen))) {
     1175                ipc_answer_0(rid, rc);
     1176                free(old);
     1177                free(new);
     1178                return;
     1179        }
     1180        new[nlen] = '\0';
     1181
    11371182        char *oldc = canonify(old, &olen);
    11381183        char *newc = canonify(new, &nlen);
    1139        
    1140         if ((!oldc) || (!newc)) {
     1184        if (!oldc || !newc) {
    11411185                ipc_answer_0(rid, EINVAL);
    11421186                free(old);
     
    11441188                return;
    11451189        }
    1146        
    11471190        oldc[olen] = '\0';
    11481191        newc[nlen] = '\0';
    1149        
    11501192        if ((!str_lcmp(newc, oldc, str_length(oldc))) &&
    11511193            ((newc[str_length(oldc)] == '/') ||
     
    11681210        vfs_lookup_res_t new_par_lr;
    11691211        fibril_rwlock_write_lock(&namespace_rwlock);
    1170        
    11711212        /* Lookup the node belonging to the old file name. */
    11721213        rc = vfs_lookup_internal(oldc, L_NONE, &old_lr, NULL);
     
    11781219                return;
    11791220        }
    1180        
    11811221        vfs_node_t *old_node = vfs_node_get(&old_lr);
    11821222        if (!old_node) {
     
    11871227                return;
    11881228        }
    1189        
    11901229        /* Determine the path to the parent of the node with the new name. */
    11911230        char *parentc = str_dup(newc);
     
    11971236                return;
    11981237        }
    1199        
    12001238        char *lastsl = str_rchr(parentc + 1, '/');
    12011239        if (lastsl)
     
    12031241        else
    12041242                parentc[1] = '\0';
    1205        
    12061243        /* Lookup parent of the new file name. */
    12071244        rc = vfs_lookup_internal(parentc, L_NONE, &new_par_lr, NULL);
     
    12141251                return;
    12151252        }
    1216        
    12171253        /* Check whether linking to the same file system instance. */
    12181254        if ((old_node->fs_handle != new_par_lr.triplet.fs_handle) ||
     
    12241260                return;
    12251261        }
    1226        
    12271262        /* Destroy the old link for the new name. */
    12281263        vfs_node_t *new_node = NULL;
    12291264        rc = vfs_lookup_internal(newc, L_UNLINK, &new_lr, NULL);
    1230        
    12311265        switch (rc) {
    12321266        case ENOENT:
     
    12531287                return;
    12541288        }
    1255        
    12561289        /* Create the new link for the new name. */
    12571290        rc = vfs_lookup_internal(newc, L_LINK, NULL, NULL, old_node->index);
     
    12651298                return;
    12661299        }
    1267        
    12681300        fibril_mutex_lock(&nodes_mutex);
    12691301        old_node->lnkcnt++;
    12701302        fibril_mutex_unlock(&nodes_mutex);
    1271        
    12721303        /* Destroy the link for the old name. */
    12731304        rc = vfs_lookup_internal(oldc, L_UNLINK, NULL, NULL);
     
    12821313                return;
    12831314        }
    1284        
    12851315        fibril_mutex_lock(&nodes_mutex);
    12861316        old_node->lnkcnt--;
     
    12881318        fibril_rwlock_write_unlock(&namespace_rwlock);
    12891319        vfs_node_put(old_node);
    1290        
    12911320        if (new_node)
    12921321                vfs_node_put(new_node);
    1293        
    12941322        free(old);
    12951323        free(new);
Note: See TracChangeset for help on using the changeset viewer.