Changeset e095644 in mainline


Ignore:
Timestamp:
2010-01-24T17:32:20Z (14 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
50fda24
Parents:
fea0ce6 (diff), ae75e2e3 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge partial support for the unmount feature.
VFS_OUT_UNMOUNT and VFS_OUT_UNMOUNTED not yet implemented by DEVFS, FAT and
TMPFS.

Location:
uspace
Files:
4 added
13 edited

Legend:

Unmodified
Added
Removed
  • uspace/app/bdsh/Makefile

    rfea0ce6 re095644  
    4848        cmds/modules/mv/mv.c \
    4949        cmds/modules/mount/mount.c \
     50        cmds/modules/unmount/unmount.c \
    5051        cmds/modules/kcon/kcon.c \
    5152        cmds/builtins/exit/exit.c \
  • uspace/app/bdsh/cmds/modules/module_aliases.h

    rfea0ce6 re095644  
    1414char *mod_aliases[] = {
    1515        "ren", "mv",
     16        "umount", "unmount",
    1617        NULL, NULL
    1718};
  • uspace/app/bdsh/cmds/modules/modules.h

    rfea0ce6 re095644  
    3131#include "mv/entry.h"
    3232#include "mount/entry.h"
     33#include "unmount/entry.h"
    3334#include "kcon/entry.h"
    3435
     
    5152#include "mv/mv_def.h"
    5253#include "mount/mount_def.h"
     54#include "unmount/unmount_def.h"
    5355#include "kcon/kcon_def.h"
    5456
  • uspace/lib/libc/generic/adt/hash_table.c

    rfea0ce6 re095644  
    193193}
    194194
     195/** Apply fucntion to all items in hash table.
     196 *
     197 * @param h             Hash table.
     198 * @param f             Function to be applied.
     199 * @param arg           Argument to be passed to the function.
     200 */
     201void
     202hash_table_apply(hash_table_t *h, void (*f)(link_t *, void *), void *arg)
     203{
     204        hash_index_t bucket;
     205        link_t *cur;
     206
     207        for (bucket = 0; bucket < h->entries; bucket++) {
     208                for (cur = h->entry[bucket].next; cur != &h->entry[bucket];
     209                    cur = cur->next) {
     210                        f(cur, arg);
     211                }
     212        }
     213}
     214
    195215/** @}
    196216 */
  • uspace/lib/libc/generic/vfs/vfs.c

    rfea0ce6 re095644  
    197197}
    198198
     199int unmount(const char *mp)
     200{
     201        ipcarg_t rc;
     202        ipcarg_t rc_orig;
     203        aid_t req;
     204        size_t mpa_size;
     205        char *mpa;
     206       
     207        mpa = absolutize(mp, &mpa_size);
     208        if (!mpa)
     209                return ENOMEM;
     210       
     211        futex_down(&vfs_phone_futex);
     212        async_serialize_start();
     213        vfs_connect();
     214       
     215        req = async_send_0(vfs_phone, VFS_IN_UNMOUNT, NULL);
     216        rc = async_data_write_start(vfs_phone, (void *) mpa, mpa_size);
     217        if (rc != EOK) {
     218                async_wait_for(req, &rc_orig);
     219                async_serialize_end();
     220                futex_up(&vfs_phone_futex);
     221                free(mpa);
     222                if (rc_orig == EOK)
     223                        return (int) rc;
     224                else
     225                        return (int) rc_orig;
     226        }
     227       
     228
     229        async_wait_for(req, &rc);
     230        async_serialize_end();
     231        futex_up(&vfs_phone_futex);
     232        free(mpa);
     233       
     234        return (int) rc;
     235}
     236
    199237static int open_internal(const char *abs, size_t abs_size, int lflag, int oflag)
    200238{
  • uspace/lib/libc/include/adt/hash_table.h

    rfea0ce6 re095644  
    8888extern void hash_table_remove(hash_table_t *, unsigned long [], hash_count_t);
    8989extern void hash_table_destroy(hash_table_t *);
     90extern void hash_table_apply(hash_table_t *, void (*)(link_t *, void *),
     91    void *);
    9092
    9193#endif
  • uspace/lib/libc/include/ipc/vfs.h

    rfea0ce6 re095644  
    8686        VFS_OUT_MOUNTED,
    8787        VFS_OUT_UNMOUNT,
     88        VFS_OUT_UNMOUNTED,
    8889        VFS_OUT_SYNC,
    8990        VFS_OUT_STAT,
     
    140141
    141142/**
    142  * L_OPEN is used to indicate that the lookup operation is a part of VFS_OPEN
     143 * L_OPEN is used to indicate that the lookup operation is a part of VFS_IN_OPEN
    143144 * call from the client. This means that the server might allocate some
    144145 * resources for the opened file. This flag cannot be passed directly by the
     
    147148#define L_OPEN  64
    148149
     150/**
     151 * L_NOCROSS_LAST_MP is used exclusively during the VFS_IN_UNMOUNT operation. It
     152 * tells the lookup routine not to cross the last mount point in the lookup
     153 * path.
     154 */
     155#define L_NOCROSS_LAST_MP       128
     156
    149157#endif
    150158
  • uspace/lib/libc/include/vfs/vfs.h

    rfea0ce6 re095644  
    5555extern int mount(const char *, const char *, const char *, const char *,
    5656    unsigned int);
     57extern int unmount(const char *);
    5758
    5859extern void __stdio_init(int filc, fdi_node_t *filv[]);
  • uspace/lib/libfs/libfs.c

    rfea0ce6 re095644  
    304304                on_error(rc, goto out_with_answer);
    305305               
    306                 if ((tmp) && (tmp->mp_data.mp_active)) {
     306                /*
     307                 * If the matching component is a mount point, there are two
     308                 * legitimate semantics of the lookup operation. The first is
     309                 * the commonly used one in which the lookup crosses each mount
     310                 * point into the mounted file system. The second semantics is
     311                 * used mostly during unmount() and differs from the first one
     312                 * only in that the last mount point in the looked up path,
     313                 * which is also its last component, is not crossed.
     314                 */
     315
     316                if ((tmp) && (tmp->mp_data.mp_active) &&
     317                    (!(lflag & L_NOCROSS_LAST_MP) || (next <= last))) {
    307318                        if (next > last)
    308319                                next = last = first;
  • uspace/srv/vfs/vfs.c

    rfea0ce6 re095644  
    8686                case VFS_IN_MOUNT:
    8787                        vfs_mount(callid, &call);
     88                        break;
     89                case VFS_IN_UNMOUNT:
     90                        vfs_unmount(callid, &call);
    8891                        break;
    8992                case VFS_IN_OPEN:
  • uspace/srv/vfs/vfs.h

    rfea0ce6 re095644  
    181181extern vfs_node_t *vfs_node_get(vfs_lookup_res_t *);
    182182extern void vfs_node_put(vfs_node_t *);
     183extern void vfs_node_forget(vfs_node_t *);
     184extern unsigned vfs_nodes_refcount_sum_get(fs_handle_t, dev_handle_t);
     185
    183186
    184187#define MAX_OPEN_FILES  128
     
    198201extern void vfs_register(ipc_callid_t, ipc_call_t *);
    199202extern void vfs_mount(ipc_callid_t, ipc_call_t *);
     203extern void vfs_unmount(ipc_callid_t, ipc_call_t *);
    200204extern void vfs_open(ipc_callid_t, ipc_call_t *);
    201205extern void vfs_open_node(ipc_callid_t, ipc_call_t *);
  • uspace/srv/vfs/vfs_node.c

    rfea0ce6 re095644  
    137137        if (free_vfs_node)
    138138                free(node);
     139}
     140
     141/** Forget node.
     142 *
     143 * This function will remove the node from the node hash table and deallocate
     144 * its memory, regardless of the node's reference count.
     145 *
     146 * @param node  Node to be forgotten.
     147 */
     148void vfs_node_forget(vfs_node_t *node)
     149{
     150        fibril_mutex_lock(&nodes_mutex);
     151        unsigned long key[] = {
     152                [KEY_FS_HANDLE] = node->fs_handle,
     153                [KEY_DEV_HANDLE] = node->dev_handle,
     154                [KEY_INDEX] = node->index
     155        };
     156        hash_table_remove(&nodes, key, 3);
     157        fibril_mutex_unlock(&nodes_mutex);
     158        free(node);
    139159}
    140160
     
    231251}
    232252
     253struct refcnt_data {
     254        /** Sum of all reference counts for this file system instance. */
     255        unsigned refcnt;
     256        fs_handle_t fs_handle;
     257        dev_handle_t dev_handle;
     258};
     259
     260static void refcnt_visitor(link_t *item, void *arg)
     261{
     262        vfs_node_t *node = hash_table_get_instance(item, vfs_node_t, nh_link);
     263        struct refcnt_data *rd = (void *) arg;
     264
     265        if ((node->fs_handle == rd->fs_handle) &&
     266            (node->dev_handle == rd->dev_handle))
     267                rd->refcnt += node->refcnt;
     268}
     269
     270unsigned
     271vfs_nodes_refcount_sum_get(fs_handle_t fs_handle, dev_handle_t dev_handle)
     272{
     273        struct refcnt_data rd = {
     274                .refcnt = 0,
     275                .fs_handle = fs_handle,
     276                .dev_handle = dev_handle
     277        };
     278
     279        fibril_mutex_lock(&nodes_mutex);
     280        hash_table_apply(&nodes, refcnt_visitor, &rd);
     281        fibril_mutex_unlock(&nodes_mutex);
     282
     283        return rd.refcnt;
     284}
     285
    233286/**
    234287 * @}
  • uspace/srv/vfs/vfs_ops.c

    rfea0ce6 re095644  
    429429}
    430430
     431void vfs_unmount(ipc_callid_t rid, ipc_call_t *request)
     432{
     433        int rc;
     434        char *mp;
     435        vfs_lookup_res_t mp_res;
     436        vfs_lookup_res_t mr_res;
     437        vfs_node_t *mp_node;
     438        vfs_node_t *mr_node;
     439        int phone;
     440
     441        /*
     442         * Receive the mount point path.
     443         */
     444        rc = async_data_string_receive(&mp, MAX_PATH_LEN);
     445        if (rc != EOK)
     446                ipc_answer_0(rid, rc);
     447
     448        /*
     449         * Taking the namespace lock will do two things for us. First, it will
     450         * prevent races with other lookup operations. Second, it will stop new
     451         * references to already existing VFS nodes and creation of new VFS
     452         * nodes. This is because new references are added as a result of some
     453         * lookup operation or at least of some operation which is protected by
     454         * the namespace lock.
     455         */
     456        fibril_rwlock_write_lock(&namespace_rwlock);
     457       
     458        /*
     459         * Lookup the mounted root and instantiate it.
     460         */
     461        rc = vfs_lookup_internal(mp, L_NONE, &mr_res, NULL);
     462        if (rc != EOK) {
     463                fibril_rwlock_write_unlock(&namespace_rwlock);
     464                free(mp);
     465                ipc_answer_0(rid, rc);
     466                return;
     467        }
     468        mr_node = vfs_node_get(&mr_res);
     469        if (!mr_node) {
     470                fibril_rwlock_write_unlock(&namespace_rwlock);
     471                free(mp);
     472                ipc_answer_0(rid, ENOMEM);
     473                return;
     474        }
     475
     476        /*
     477         * Count the total number of references for the mounted file system. We
     478         * are expecting at least two. One which we got above and one which we
     479         * got when the file system was mounted. If we find more, it means that
     480         * the file system cannot be gracefully unmounted at the moment because
     481         * someone is working with it.
     482         */
     483        if (vfs_nodes_refcount_sum_get(mr_node->fs_handle,
     484            mr_node->dev_handle) != 2) {
     485                fibril_rwlock_write_unlock(&namespace_rwlock);
     486                vfs_node_put(mr_node);
     487                free(mp);
     488                ipc_answer_0(rid, EBUSY);
     489                return;
     490        }
     491
     492        if (str_cmp(mp, "/") == 0) {
     493
     494                /*
     495                 * Unmounting the root file system.
     496                 *
     497                 * In this case, there is no mount point node and we send
     498                 * VFS_OUT_UNMOUNTED directly to the mounted file system.
     499                 */
     500
     501                free(mp);
     502                phone = vfs_grab_phone(mr_node->fs_handle);
     503                rc = async_req_1_0(phone, VFS_OUT_UNMOUNTED,
     504                    mr_node->dev_handle);
     505                vfs_release_phone(phone);
     506                if (rc != EOK) {
     507                        fibril_rwlock_write_unlock(&namespace_rwlock);
     508                        vfs_node_put(mr_node);
     509                        ipc_answer_0(rid, rc);
     510                        return;
     511                }
     512                rootfs.fs_handle = 0;
     513                rootfs.dev_handle = 0;
     514        } else {
     515
     516                /*
     517                 * Unmounting a non-root file system.
     518                 *
     519                 * We have a regular mount point node representing the parent
     520                 * file system, so we delegate the operation to it.
     521                 */
     522
     523                /*
     524                 * The L_NOCROSS_LAST_MP flag is essential if we really want to
     525                 * lookup the mount point and not the mounted root.
     526                 */
     527                rc = vfs_lookup_internal(mp, L_NOCROSS_LAST_MP, &mp_res, NULL);
     528                free(mp);
     529                if (rc != EOK) {
     530                        fibril_rwlock_write_unlock(&namespace_rwlock);
     531                        vfs_node_put(mr_node);
     532                        ipc_answer_0(rid, rc);
     533                        return;
     534                }
     535                vfs_node_t *mp_node = vfs_node_get(&mp_res);
     536                if (!mp_node) {
     537                        fibril_rwlock_write_unlock(&namespace_rwlock);
     538                        vfs_node_put(mr_node);
     539                        ipc_answer_0(rid, ENOMEM);
     540                        return;
     541                }
     542
     543                phone = vfs_grab_phone(mp_node->fs_handle);
     544                rc = async_req_2_0(phone, VFS_OUT_UNMOUNT, mp_node->fs_handle,
     545                    mp_node->dev_handle);
     546                vfs_release_phone(phone);
     547                if (rc != EOK) {
     548                        fibril_rwlock_write_unlock(&namespace_rwlock);
     549                        vfs_node_put(mp_node);
     550                        vfs_node_put(mr_node);
     551                        ipc_answer_0(rid, rc);
     552                        return;
     553                }
     554
     555                /* Drop the reference we got above. */
     556                vfs_node_put(mp_node);
     557                /* Drop the reference from when the file system was mounted. */
     558                vfs_node_put(mp_node);
     559        }
     560
     561
     562        /*
     563         * All went well, the mounted file system was successfully unmounted.
     564         * The only thing left is to forget the unmounted root VFS node.
     565         */
     566        vfs_node_forget(mr_node);
     567
     568        fibril_rwlock_write_unlock(&namespace_rwlock);
     569        ipc_answer_0(rid, EOK);
     570}
     571
    431572void vfs_open(ipc_callid_t rid, ipc_call_t *request)
    432573{
     
    454595        /*
    455596         * Make sure that we are called with exactly one of L_FILE and
    456          * L_DIRECTORY. Make sure that the user does not pass L_OPEN.
     597         * L_DIRECTORY. Make sure that the user does not pass L_OPEN or
     598         * L_NOCROSS_LAST_MP.
    457599         */
    458600        if (((lflag & (L_FILE | L_DIRECTORY)) == 0) ||
    459601            ((lflag & (L_FILE | L_DIRECTORY)) == (L_FILE | L_DIRECTORY)) ||
    460             ((lflag & L_OPEN) != 0)) {
     602            (lflag & L_OPEN) || (lflag & L_NOCROSS_LAST_MP)) {
    461603                ipc_answer_0(rid, EINVAL);
    462604                return;
Note: See TracChangeset for help on using the changeset viewer.