Changeset 8dc72b64 in mainline for uspace/srv/vfs/vfs_ops.c


Ignore:
Timestamp:
2009-03-02T17:37:19Z (16 years ago)
Author:
Martin Decky <martin@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
16da5f8e
Parents:
6519d6f
Message:

support for pending (blocking) mounts (waiting for the presence of the filesystem implementation)
the mount point and filesystem type arguments of VFS_MOUNT were swapped, the IPC_M_PING was eliminated
small cleanups

File:
1 edited

Legend:

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

    r6519d6f r8dc72b64  
    2929/** @addtogroup fs
    3030 * @{
    31  */ 
     31 */
    3232
    3333/**
    34  * @file        vfs_ops.c
    35  * @brief       Operations that VFS offers to its clients.
     34 * @file vfs_ops.c
     35 * @brief Operations that VFS offers to its clients.
    3636 */
    3737
     
    5656static int vfs_truncate_internal(fs_handle_t, dev_handle_t, fs_index_t, size_t);
    5757
     58/** Pending mount structure. */
     59typedef struct {
     60        link_t link;
     61        char *fs_name;            /**< File system name */
     62        char *mp;                 /**< Mount point */
     63        ipc_callid_t callid;      /**< Call ID waiting for the mount */
     64        ipc_callid_t rid;         /**< Request ID */
     65        dev_handle_t dev_handle;  /**< Device handle */
     66} pending_req_t;
     67
     68LIST_INITIALIZE(pending_req);
     69
    5870/**
    5971 * This rwlock prevents the race between a triplet-to-VFS-node resolution and a
     
    6880};
    6981
    70 void vfs_mount(ipc_callid_t rid, ipc_call_t *request)
    71 {
    72         dev_handle_t dev_handle;
     82static void vfs_mount_internal(ipc_callid_t rid, dev_handle_t dev_handle,
     83    fs_handle_t fs_handle, char *mp)
     84{
     85        /* Resolve the path to the mountpoint. */
     86        vfs_lookup_res_t mp_res;
    7387        vfs_node_t *mp_node = NULL;
    74         ipc_callid_t callid;
    75         ipc_call_t data;
    7688        int rc;
    7789        int phone;
    78         size_t size;
    79 
    80         /*
    81          * We expect the library to do the device-name to device-handle
    82          * translation for us, thus the device handle will arrive as ARG1
    83          * in the request.
    84          */
    85         dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
    86 
    87         /*
    88          * For now, don't make use of ARG2 and ARG3, but they can be used to
    89          * carry mount options in the future.
    90          */
    91 
    92         /*
    93          * Now, we expect the client to send us data with the name of the file
    94          * system.
    95          */
    96         if (!ipc_data_write_receive(&callid, &size)) {
    97                 ipc_answer_0(callid, EINVAL);
    98                 ipc_answer_0(rid, EINVAL);
    99                 return;
    100         }
    101 
    102         /*
    103          * Don't receive more than is necessary for storing a full file system
    104          * name.
    105          */
    106         if (size < 1 || size > FS_NAME_MAXLEN) {
    107                 ipc_answer_0(callid, EINVAL);
    108                 ipc_answer_0(rid, EINVAL);
    109                 return;
    110         }
    111 
    112         /* Deliver the file system name. */
    113         char fs_name[FS_NAME_MAXLEN + 1];
    114         (void) ipc_data_write_finalize(callid, fs_name, size);
    115         fs_name[size] = '\0';
    116        
    117         /*
    118          * Wait for IPC_M_PING so that we can return an error if we don't know
    119          * fs_name.
    120          */
    121         callid = async_get_call(&data);
    122         if (IPC_GET_METHOD(data) != IPC_M_PING) {
    123                 ipc_answer_0(callid, ENOTSUP);
    124                 ipc_answer_0(rid, ENOTSUP);
    125                 return;
    126         }
    127 
    128         /*
    129          * Check if we know a file system with the same name as is in fs_name.
    130          * This will also give us its file system handle.
    131          */
    132         fs_handle_t fs_handle = fs_name_to_handle(fs_name, true);
    133         if (!fs_handle) {
    134                 ipc_answer_0(callid, ENOENT);
    135                 ipc_answer_0(rid, ENOENT);
    136                 return;
    137         }
    138 
    139         /* Acknowledge that we know fs_name. */
    140         ipc_answer_0(callid, EOK);
    141 
    142         /* Now, we want the client to send us the mount point. */
    143         if (!ipc_data_write_receive(&callid, &size)) {
    144                 ipc_answer_0(callid, EINVAL);
    145                 ipc_answer_0(rid, EINVAL);
    146                 return;
    147         }
    148 
    149         /* Check whether size is reasonable wrt. the mount point. */
    150         if (size < 1 || size > MAX_PATH_LEN) {
    151                 ipc_answer_0(callid, EINVAL);
    152                 ipc_answer_0(rid, EINVAL);
    153                 return;
    154         }
    155         /* Allocate buffer for the mount point data being received. */
    156         char *buf;
    157         buf = malloc(size + 1);
    158         if (!buf) {
    159                 ipc_answer_0(callid, ENOMEM);
    160                 ipc_answer_0(rid, ENOMEM);
    161                 return;
    162         }
    163 
    164         /* Deliver the mount point. */
    165         (void) ipc_data_write_finalize(callid, buf, size);
    166         buf[size] = '\0';
    167 
    168         /* Resolve the path to the mountpoint. */
    169         vfs_lookup_res_t mp_res;
    17090        futex_down(&rootfs_futex);
    17191        if (rootfs.fs_handle) {
    17292                /* We already have the root FS. */
    17393                rwlock_write_lock(&namespace_rwlock);
    174                 if ((size == 1) && (buf[0] == '/')) {
     94                if ((strlen(mp) == 1) && (mp[0] == '/')) {
    17595                        /* Trying to mount root FS over root FS */
    17696                        rwlock_write_unlock(&namespace_rwlock);
    17797                        futex_up(&rootfs_futex);
    178                         free(buf);
    17998                        ipc_answer_0(rid, EBUSY);
    18099                        return;
    181100                }
    182                 rc = vfs_lookup_internal(buf, L_DIRECTORY, &mp_res, NULL);
     101               
     102                rc = vfs_lookup_internal(mp, L_DIRECTORY, &mp_res, NULL);
    183103                if (rc != EOK) {
    184104                        /* The lookup failed for some reason. */
    185105                        rwlock_write_unlock(&namespace_rwlock);
    186106                        futex_up(&rootfs_futex);
    187                         free(buf);
    188107                        ipc_answer_0(rid, rc);
    189108                        return;
    190109                }
     110               
    191111                mp_node = vfs_node_get(&mp_res);
    192112                if (!mp_node) {
    193113                        rwlock_write_unlock(&namespace_rwlock);
    194114                        futex_up(&rootfs_futex);
    195                         free(buf);
    196115                        ipc_answer_0(rid, ENOMEM);
    197116                        return;
    198117                }
     118               
    199119                /*
    200120                 * Now we hold a reference to mp_node.
     
    205125        } else {
    206126                /* We still don't have the root file system mounted. */
    207                 if ((size == 1) && (buf[0] == '/')) {
     127                if ((strlen(mp) == 1) && (mp[0] == '/')) {
    208128                        vfs_lookup_res_t mr_res;
    209129                        vfs_node_t *mr_node;
     
    211131                        ipcarg_t rsize;
    212132                        ipcarg_t rlnkcnt;
    213                
     133                       
    214134                        /*
    215135                         * For this simple, but important case,
    216136                         * we are almost done.
    217137                         */
    218                         free(buf);
    219138                       
    220139                        /* Tell the mountee that it is being mounted. */
     
    229148                                return;
    230149                        }
    231 
     150                       
    232151                        mr_res.triplet.fs_handle = fs_handle;
    233152                        mr_res.triplet.dev_handle = dev_handle;
     
    236155                        mr_res.lnkcnt = (unsigned) rlnkcnt;
    237156                        mr_res.type = VFS_NODE_DIRECTORY;
    238 
     157                       
    239158                        rootfs.fs_handle = fs_handle;
    240159                        rootfs.dev_handle = dev_handle;
    241160                        futex_up(&rootfs_futex);
    242 
     161                       
    243162                        /* Add reference to the mounted root. */
    244163                        mr_node = vfs_node_get(&mr_res);
    245164                        assert(mr_node);
    246 
     165                       
    247166                        ipc_answer_0(rid, rc);
    248167                        return;
     
    253172                         */
    254173                        futex_up(&rootfs_futex);
    255                         free(buf);
    256174                        ipc_answer_0(rid, ENOENT);
    257175                        return;
     
    260178        futex_up(&rootfs_futex);
    261179       
    262         free(buf);      /* The buffer is not needed anymore. */
    263        
    264180        /*
    265181         * At this point, we have all necessary pieces: file system and device
    266182         * handles, and we know the mount point VFS node.
    267183         */
    268 
     184       
    269185        phone = vfs_grab_phone(mp_res.triplet.fs_handle);
    270186        rc = async_req_4_0(phone, VFS_MOUNT,
     
    274190            (ipcarg_t) dev_handle);
    275191        vfs_release_phone(phone);
    276 
     192       
    277193        if (rc != EOK) {
    278194                /* Mount failed, drop reference to mp_node. */
     
    282198       
    283199        ipc_answer_0(rid, rc);
     200}
     201
     202/** Process pending mount requests */
     203void vfs_process_pending_mount()
     204{
     205        link_t *cur;
     206       
     207loop:
     208        for (cur = pending_req.next; cur != &pending_req; cur = cur->next) {
     209                pending_req_t *pr = list_get_instance(cur, pending_req_t, link);
     210               
     211                fs_handle_t fs_handle = fs_name_to_handle(pr->fs_name, true);
     212                if (!fs_handle)
     213                        continue;
     214               
     215                /* Acknowledge that we know fs_name. */
     216                ipc_answer_0(pr->callid, EOK);
     217               
     218                /* Do the mount */
     219                vfs_mount_internal(pr->rid, pr->dev_handle, fs_handle, pr->mp);
     220               
     221                free(pr->fs_name);
     222                free(pr->mp);
     223                list_remove(cur);
     224                free(pr);
     225                goto loop;
     226        }
     227}
     228
     229void vfs_mount(ipc_callid_t rid, ipc_call_t *request)
     230{
     231        /*
     232         * We expect the library to do the device-name to device-handle
     233         * translation for us, thus the device handle will arrive as ARG1
     234         * in the request.
     235         */
     236        dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request);
     237       
     238        /*
     239         * Mount flags are passed as ARG2.
     240         */
     241        unsigned int flags = (unsigned int) IPC_GET_ARG2(*request);
     242       
     243        /*
     244         * For now, don't make use of ARG3, but it can be used to
     245         * carry mount options in the future.
     246         */
     247       
     248        /* We want the client to send us the mount point. */
     249        ipc_callid_t callid;
     250        size_t size;
     251        if (!ipc_data_write_receive(&callid, &size)) {
     252                ipc_answer_0(callid, EINVAL);
     253                ipc_answer_0(rid, EINVAL);
     254                return;
     255        }
     256       
     257        /* Check whether size is reasonable wrt. the mount point. */
     258        if ((size < 1) || (size > MAX_PATH_LEN)) {
     259                ipc_answer_0(callid, EINVAL);
     260                ipc_answer_0(rid, EINVAL);
     261                return;
     262        }
     263       
     264        /* Allocate buffer for the mount point data being received. */
     265        char *mp = malloc(size + 1);
     266        if (!mp) {
     267                ipc_answer_0(callid, ENOMEM);
     268                ipc_answer_0(rid, ENOMEM);
     269                return;
     270        }
     271       
     272        /* Deliver the mount point. */
     273        ipcarg_t retval = ipc_data_write_finalize(callid, mp, size);
     274        if (retval != EOK) {
     275                ipc_answer_0(rid, EREFUSED);
     276                free(mp);
     277                return;
     278        }
     279        mp[size] = '\0';
     280       
     281        /*
     282         * Now, we expect the client to send us data with the name of the file
     283         * system.
     284         */
     285        if (!ipc_data_write_receive(&callid, &size)) {
     286                ipc_answer_0(callid, EINVAL);
     287                ipc_answer_0(rid, EINVAL);
     288                free(mp);
     289                return;
     290        }
     291       
     292        /*
     293         * Don't receive more than is necessary for storing a full file system
     294         * name.
     295         */
     296        if ((size < 1) || (size > FS_NAME_MAXLEN)) {
     297                ipc_answer_0(callid, EINVAL);
     298                ipc_answer_0(rid, EINVAL);
     299                free(mp);
     300                return;
     301        }
     302       
     303        /*
     304         * Allocate buffer for file system name.
     305         */
     306        char *fs_name = (char *) malloc(size + 1);
     307        if (fs_name == NULL) {
     308                ipc_answer_0(callid, ENOMEM);
     309                ipc_answer_0(rid, EREFUSED);
     310                free(mp);
     311                return;
     312        }
     313       
     314        /* Deliver the file system name. */
     315        retval = ipc_data_write_finalize(callid, fs_name, size);
     316        if (retval != EOK) {
     317                ipc_answer_0(rid, EREFUSED);
     318                free(mp);
     319                free(fs_name);
     320                return;
     321        }
     322        fs_name[size] = '\0';
     323       
     324        /*
     325         * Check if we know a file system with the same name as is in fs_name.
     326         * This will also give us its file system handle.
     327         */
     328        fs_handle_t fs_handle = fs_name_to_handle(fs_name, true);
     329        if (!fs_handle) {
     330                if (flags & IPC_FLAG_BLOCKING) {
     331                        /* Blocking mount, add to pending list */
     332                        pending_req_t *pr = (pending_req_t *) malloc(sizeof(pending_req_t));
     333                        if (!pr) {
     334                                ipc_answer_0(callid, ENOMEM);
     335                                ipc_answer_0(rid, ENOMEM);
     336                                free(mp);
     337                                free(fs_name);
     338                                return;
     339                        }
     340                       
     341                        pr->fs_name = fs_name;
     342                        pr->mp = mp;
     343                        pr->callid = callid;
     344                        pr->rid = rid;
     345                        pr->dev_handle = dev_handle;
     346                        list_append(&pr->link, &pending_req);
     347                        return;
     348                }
     349               
     350                ipc_answer_0(callid, ENOENT);
     351                ipc_answer_0(rid, ENOENT);
     352                free(mp);
     353                free(fs_name);
     354                return;
     355        }
     356       
     357        /* Acknowledge that we know fs_name. */
     358        ipc_answer_0(callid, EOK);
     359       
     360        /* Do the mount */
     361        vfs_mount_internal(rid, dev_handle, fs_handle, mp);
     362        free(mp);
     363        free(fs_name);
    284364}
    285365
Note: See TracChangeset for help on using the changeset viewer.