Changeset 5bcd5b7 in mainline


Ignore:
Timestamp:
2013-07-29T14:36:57Z (11 years ago)
Author:
Jiri Zarevucky <zarevucky.jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
4636a60
Parents:
677745a
Message:

Add support for server-side mounts.

Location:
uspace
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/c/include/ipc/vfs.h

    r677745a r5bcd5b7  
    9595        VFS_OUT_UNMOUNTED,
    9696        VFS_OUT_GET_SIZE,
     97        VFS_OUT_IS_EMPTY,
    9798        VFS_OUT_SYNC,
    9899        VFS_OUT_STAT,
  • uspace/lib/fs/libfs.c

    r677745a r5bcd5b7  
    259259}
    260260
     261static void vfs_out_is_empty(ipc_callid_t rid, ipc_call_t *req)
     262{
     263        service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
     264        fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
     265        int rc;
     266
     267        fs_node_t *node = NULL;
     268        rc = libfs_ops->node_get(&node, service_id, index);
     269        if (rc != EOK) {
     270                async_answer_0(rid, rc);
     271        }
     272        if (node == NULL) {
     273                async_answer_0(rid, EINVAL);
     274        }
     275       
     276        bool children = false;
     277        rc = libfs_ops->has_children(&children, node);
     278        libfs_ops->node_put(node);
     279       
     280        if (rc != EOK) {
     281                async_answer_0(rid, rc);
     282        }
     283        async_answer_0(rid, children ? ENOTEMPTY : EOK);
     284}
     285
    261286static void vfs_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
    262287{
     
    322347                case VFS_OUT_GET_SIZE:
    323348                        vfs_out_get_size(callid, &call);
     349                        break;
     350                case VFS_OUT_IS_EMPTY:
     351                        vfs_out_is_empty(callid, &call);
    324352                        break;
    325353                default:
  • uspace/srv/vfs/vfs.h

    r677745a r5bcd5b7  
    100100 * which may be associated with it.
    101101 */
    102 typedef struct {
     102typedef struct _vfs_node {
    103103        VFS_TRIPLET;            /**< Identity of the node. */
    104104
     
    119119         */
    120120        fibril_rwlock_t contents_rwlock;
     121       
     122        struct _vfs_node *mount;
    121123} vfs_node_t;
    122124
     
    176178extern vfs_info_t *fs_handle_to_info(fs_handle_t);
    177179
    178 extern int vfs_lookup_internal(vfs_triplet_t *, char *, int, vfs_lookup_res_t *);
    179 extern int vfs_link_internal(vfs_triplet_t *, char *, vfs_triplet_t *);
     180extern int vfs_lookup_internal(vfs_node_t *, char *, int, vfs_lookup_res_t *);
     181extern int vfs_link_internal(vfs_node_t *, char *, vfs_triplet_t *);
    180182
    181183extern bool vfs_nodes_init(void);
    182184extern vfs_node_t *vfs_node_get(vfs_lookup_res_t *);
     185extern vfs_node_t *vfs_node_peek(vfs_lookup_res_t *result);
    183186extern void vfs_node_put(vfs_node_t *);
    184187extern void vfs_node_forget(vfs_node_t *);
    185188extern unsigned vfs_nodes_refcount_sum_get(fs_handle_t, service_id_t);
    186189
    187 int64_t vfs_node_get_size(vfs_node_t *node);
     190extern int64_t vfs_node_get_size(vfs_node_t *node);
     191extern bool vfs_node_has_children(vfs_node_t *node);
    188192
    189193#define MAX_OPEN_FILES  128
  • uspace/srv/vfs/vfs_lookup.c

    r677745a r5bcd5b7  
    153153}
    154154
    155 int vfs_link_internal(vfs_triplet_t *base, char *path, vfs_triplet_t *child)
     155int vfs_link_internal(vfs_node_t *base, char *path, vfs_triplet_t *child)
    156156{
    157157        assert(base != NULL);
     
    173173        path = npath;
    174174       
     175        vfs_triplet_t *triplet;
     176       
    175177        char *slash = _strrchr(path, '/');
    176178        if (slash && slash != path) {
     
    187189                        goto out;
    188190                }
    189                 base = &res.triplet;
     191                triplet = &res.triplet;
    190192               
    191193                *slash = '/';
    192194        } else {
     195                if (base->mount != NULL) {
     196                        rc = EINVAL;
     197                        goto out;
     198                }
     199               
    193200                memcpy(component, path + 1, str_size(path));
    194         }
    195        
    196         if (base->fs_handle != child->fs_handle || base->service_id != child->service_id) {
     201                triplet = (vfs_triplet_t *) base;
     202        }
     203       
     204        if (triplet->fs_handle != child->fs_handle || triplet->service_id != child->service_id) {
    197205                rc = EXDEV;
    198206                goto out;
    199207        }
    200208       
    201         async_exch_t *exch = vfs_exchange_grab(base->fs_handle);
    202         aid_t req = async_send_3(exch, VFS_OUT_LINK, base->service_id, base->index, child->index, NULL);
     209        async_exch_t *exch = vfs_exchange_grab(triplet->fs_handle);
     210        aid_t req = async_send_3(exch, VFS_OUT_LINK, triplet->service_id, triplet->index, child->index, NULL);
    203211       
    204212        rc = async_data_write_start(exch, component, str_size(component) + 1);
     
    215223}
    216224
     225static int out_lookup(vfs_triplet_t *base, unsigned *pfirst, unsigned *plen,
     226        int lflag, vfs_lookup_res_t *result)
     227{
     228        assert(base);
     229        assert(result);
     230       
     231        sysarg_t rc;
     232        ipc_call_t answer;
     233        async_exch_t *exch = vfs_exchange_grab(base->fs_handle);
     234        aid_t req = async_send_5(exch, VFS_OUT_LOOKUP, (sysarg_t) *pfirst, (sysarg_t) *plen,
     235            (sysarg_t) base->service_id, (sysarg_t) base->index, (sysarg_t) lflag, &answer);
     236        async_wait_for(req, &rc);
     237        vfs_exchange_release(exch);
     238       
     239        if ((int) rc < 0) {
     240                return (int) rc;
     241        }
     242       
     243        unsigned last = *pfirst + *plen;
     244        *pfirst = IPC_GET_ARG3(answer);
     245        *plen = last - *pfirst;
     246       
     247        result->triplet.fs_handle = (fs_handle_t) rc;
     248        result->triplet.service_id = (service_id_t) IPC_GET_ARG1(answer);
     249        result->triplet.index = (fs_index_t) IPC_GET_ARG2(answer);
     250        result->size = (int64_t)(int32_t) IPC_GET_ARG4(answer);
     251        result->type = IPC_GET_ARG5(answer);
     252        return EOK;
     253}
     254
    217255/** Perform a path lookup.
    218256 *
     
    227265 *
    228266 */
    229 int vfs_lookup_internal(vfs_triplet_t *base, char *path, int lflag, vfs_lookup_res_t *result)
     267int vfs_lookup_internal(vfs_node_t *base, char *path, int lflag, vfs_lookup_res_t *result)
    230268{
    231269        assert(base != NULL);
    232270        assert(path != NULL);
    233271       
    234         sysarg_t rc;
    235        
    236         if (!base->fs_handle) {
    237                 rc = ENOENT;
    238                 goto out;
    239         }
    240        
    241272        size_t len;
     273        int rc;
    242274        char *npath = canonify(path, &len);
    243275        if (!npath) {
     276                DPRINTF("vfs_lookup_internal() can't canonify path: %s\n", path);
    244277                rc = EINVAL;
    245                 goto out;
     278                return rc;
    246279        }
    247280        path = npath;
     
    254287        rc = plb_insert_entry(&entry, path, &first, len);
    255288        if (rc != EOK) {
    256                 goto out;
    257         }
    258        
    259         ipc_call_t answer;
    260         async_exch_t *exch = vfs_exchange_grab(base->fs_handle);
    261         aid_t req = async_send_5(exch, VFS_OUT_LOOKUP, (sysarg_t) first, (sysarg_t) len,
    262             (sysarg_t) base->service_id, (sysarg_t) base->index, (sysarg_t) lflag, &answer);
    263         async_wait_for(req, &rc);
    264         vfs_exchange_release(exch);
    265        
     289                DPRINTF("vfs_lookup_internal() can't insert entry into PLB: %d\n", rc);
     290                return rc;
     291        }
     292       
     293        size_t next = first;
     294        size_t nlen = len;
     295       
     296        vfs_lookup_res_t res;
     297       
     298        /* Resolve path as long as there are mount points to cross. */
     299        while (nlen > 0) {
     300                while (base->mount != NULL) {
     301                        if (lflag & L_DISABLE_MOUNTS) {
     302                                rc = EXDEV;
     303                                goto out;
     304                        }
     305                       
     306                        base = base->mount;
     307                }
     308               
     309                rc = out_lookup((vfs_triplet_t *) base, &next, &nlen, lflag, &res);
     310                if (rc != EOK) {
     311                        goto out;
     312                }
     313               
     314                if (nlen > 0) {
     315                        base = vfs_node_peek(&res);
     316                        if (base == NULL || base->mount == NULL) {
     317                                rc = ENOENT;
     318                                goto out;
     319                        }
     320                        if (lflag & L_DISABLE_MOUNTS) {
     321                                rc = EXDEV;
     322                                goto out;
     323                        }
     324                }
     325        }
     326       
     327        assert(nlen == 0);
     328        rc = EOK;
     329       
     330        if (result != NULL) {
     331                /* The found file may be a mount point. Try to cross it. */
     332                if (!(lflag & L_MP)) {
     333                        base = vfs_node_peek(&res);
     334                        if (base != NULL && base->mount != NULL) {
     335                                while (base->mount != NULL) {
     336                                        base = base->mount;
     337                                }
     338                               
     339                                result->triplet = *(vfs_triplet_t *)base;
     340                                result->type = base->type;
     341                                result->size = base->size;                             
     342                                goto out;
     343                        }
     344                }
     345
     346                __builtin_memcpy(result, &res, sizeof(vfs_lookup_res_t));
     347        }
     348       
     349out:
    266350        plb_clear_entry(&entry, first, len);
    267        
    268         if ((int) rc < 0) {
    269                 goto out;
    270         }
    271        
    272         unsigned last = IPC_GET_ARG3(answer);
    273         if (last != first + len) {
    274                 /* The path wasn't processed entirely. */
    275                 rc = ENOENT;
    276                 goto out;
    277         }
    278        
    279         if (!result) {
    280                 rc = EOK;
    281                 goto out;
    282         }
    283        
    284         result->triplet.fs_handle = (fs_handle_t) rc;
    285         result->triplet.service_id = (service_id_t) IPC_GET_ARG1(answer);
    286         result->triplet.index = (fs_index_t) IPC_GET_ARG2(answer);
    287         result->size = (int64_t)(int32_t) IPC_GET_ARG4(answer);
    288         result->type = IPC_GET_ARG5(answer);
    289         rc = EOK;
    290 
    291 out:
    292351        DPRINTF("vfs_lookup_internal() with path '%s' returns %d\n", path, rc);
    293352        return rc;
  • uspace/srv/vfs/vfs_node.c

    r677745a r5bcd5b7  
    196196}
    197197
     198vfs_node_t *vfs_node_peek(vfs_lookup_res_t *result)
     199{
     200        vfs_node_t *node = NULL;
     201
     202        fibril_mutex_lock(&nodes_mutex);
     203        ht_link_t *tmp = hash_table_find(&nodes, &result->triplet);
     204        if (tmp) {
     205                node = hash_table_get_inst(tmp, vfs_node_t, nh_link);
     206        }
     207        fibril_mutex_unlock(&nodes_mutex);
     208
     209        return node;
     210}
     211
    198212/** Return VFS node when no longer needed by the caller.
    199213 *
     
    317331}
    318332
     333bool vfs_node_has_children(vfs_node_t *node)
     334{
     335        async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
     336        int rc = async_req_2_0(exch, VFS_OUT_IS_EMPTY, node->service_id, node->index);
     337        vfs_exchange_release(exch);
     338        return rc == ENOTEMPTY;
     339}
     340
    319341/**
    320342 * @}
  • uspace/srv/vfs/vfs_ops.c

    r677745a r5bcd5b7  
    7070vfs_node_t *root = NULL;
    7171
     72#if 0
     73static int vfs_attach_internal(vfs_node_t *mpoint, vfs_node_t *mountee)
     74{
     75        assert(mpoint != NULL);
     76        assert(mountee != NULL);
     77       
     78        if (mpoint->mount != NULL) {
     79                return EBUSY;
     80        }
     81       
     82        if (mpoint->type != VFS_NODE_DIRECTORY) {
     83                return ENOTDIR;
     84        }
     85       
     86        if (vfs_node_has_children(mpoint)) {
     87                return ENOTEMPTY;
     88        }
     89       
     90        mpoint->mount = mountee;
     91        vfs_node_addref(mountee);
     92        /* Add reference to make sure the node is not freed. Removed in detach_internal(). */
     93        vfs_node_addref(mpoint);
     94        return EOK;
     95}
     96
     97static int vfs_detach_internal(vfs_node_t *mpoint)
     98{
     99        assert(mpoint != NULL);
     100       
     101        if (mpoint->mount == NULL) {
     102                return ENOENT;
     103        }
     104        vfs_node_put(mpoint->mount);
     105        mpoint->mount = NULL;
     106        vfs_node_put(mpoint);
     107}
     108#endif
     109
    72110static int vfs_mount_internal(ipc_callid_t rid, service_id_t service_id,
    73111    fs_handle_t fs_handle, char *mp, char *opts)
     
    153191        }
    154192       
    155         rc = vfs_lookup_internal((vfs_triplet_t *) root, mp, L_DIRECTORY, &mp_res);
     193        rc = vfs_lookup_internal(root, mp, L_DIRECTORY, &mp_res);
    156194        if (rc != EOK) {
    157195                /* The lookup failed. */
     
    424462         * Lookup the mounted root and instantiate it.
    425463         */
    426         rc = vfs_lookup_internal((vfs_triplet_t *) root, mp, 0, &mr_res);
     464        rc = vfs_lookup_internal(root, mp, 0, &mr_res);
    427465        if (rc != EOK) {
    428466                fibril_rwlock_write_unlock(&namespace_rwlock);
     
    487525                 */
    488526               
    489                 rc = vfs_lookup_internal((vfs_triplet_t *) root, mp, L_MP, &mp_res);
     527                rc = vfs_lookup_internal(root, mp, L_MP, &mp_res);
    490528                if (rc != EOK) {
    491529                        fibril_rwlock_write_unlock(&namespace_rwlock);
     
    627665       
    628666        vfs_lookup_res_t lr;
    629         rc = vfs_lookup_internal((vfs_triplet_t *) parent_node, path, walk_lookup_flags(flags), &lr);
     667        rc = vfs_lookup_internal(parent_node, path, walk_lookup_flags(flags), &lr);
    630668        free(path);
    631669
     
    10501088}
    10511089
     1090static void out_destroy(vfs_triplet_t *file)
     1091{
     1092        async_exch_t *exch = vfs_exchange_grab(file->fs_handle);
     1093        async_msg_2(exch, VFS_OUT_DESTROY,
     1094                (sysarg_t) file->service_id, (sysarg_t) file->index);
     1095        vfs_exchange_release(exch);
     1096}
     1097
    10521098void vfs_unlink2(ipc_callid_t rid, ipc_call_t *request)
    10531099{
     
    10891135               
    10901136                vfs_lookup_res_t lr;
    1091                 rc = vfs_lookup_internal((vfs_triplet_t *) parent_node, path, lflag, &lr);
     1137                rc = vfs_lookup_internal(parent_node, path, lflag, &lr);
    10921138                if (rc != EOK) {
    10931139                        goto exit;
     
    11041150       
    11051151        vfs_lookup_res_t lr;
    1106         rc = vfs_lookup_internal((vfs_triplet_t *) parent_node, path, lflag | L_UNLINK, &lr);
     1152        rc = vfs_lookup_internal(parent_node, path, lflag | L_UNLINK, &lr);
    11071153        if (rc != EOK) {
    11081154                goto exit;
    11091155        }
    11101156
    1111         /*
    1112          * The name has already been unlinked by vfs_lookup_internal().
    1113          * We have to get and put the VFS node to ensure that it is
    1114          * VFS_OUT_DESTROY'ed after the last reference to it is dropped.
    1115          */
    1116         vfs_node_put(vfs_node_get(&lr));
     1157        /* If the node is not held by anyone, try to destroy it. */
     1158        if (vfs_node_peek(&lr) == NULL) {
     1159                out_destroy(&lr.triplet);
     1160        }
    11171161
    11181162exit:
     
    11491193}
    11501194
    1151 static int vfs_rename_internal(vfs_triplet_t *base, char *old, char *new)
     1195static int vfs_rename_internal(vfs_node_t *base, char *old, char *new)
    11521196{
    11531197        assert(base != NULL);
     
    11821226                }
    11831227               
    1184                 base = &base_lr.triplet;
     1228                base = vfs_node_get(&base_lr);
    11851229                old[shared] = '/';
    11861230                old += shared;
    11871231                new += shared;
     1232        } else {
     1233                vfs_node_addref(base);
    11881234        }
    11891235       
     
    11931239                orig_unlinked = true;
    11941240        } else if (rc != ENOENT) {
     1241                vfs_node_put(base);
    11951242                fibril_rwlock_write_unlock(&namespace_rwlock);
    11961243                return rc;
     
    12021249                        vfs_link_internal(base, new, &new_lr_orig.triplet);
    12031250                }
     1251                vfs_node_put(base);
    12041252                fibril_rwlock_write_unlock(&namespace_rwlock);
    12051253                return rc;
     
    12121260                        vfs_link_internal(base, new, &new_lr_orig.triplet);
    12131261                }
     1262                vfs_node_put(base);
    12141263                fibril_rwlock_write_unlock(&namespace_rwlock);
    12151264                return rc;
    12161265        }
    12171266       
    1218         if (orig_unlinked) {
    1219                 vfs_node_put(vfs_node_get(&new_lr_orig));
    1220         }
    1221        
     1267        /* If the node is not held by anyone, try to destroy it. */
     1268        if (orig_unlinked && vfs_node_peek(&new_lr_orig) == NULL) {
     1269                out_destroy(&new_lr_orig.triplet);
     1270        }
     1271       
     1272        vfs_node_put(base);
    12221273        fibril_rwlock_write_unlock(&namespace_rwlock);
    12231274        return EOK;
     
    12721323        }
    12731324       
    1274         rc = vfs_rename_internal((vfs_triplet_t *) base_node, oldc, newc);
     1325        rc = vfs_rename_internal(base_node, oldc, newc);
    12751326
    12761327out:
Note: See TracChangeset for help on using the changeset viewer.