Changeset 62da45a in mainline


Ignore:
Timestamp:
2008-01-18T18:02:24Z (16 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
5973fd0
Parents:
4cc2ddd
Message:

Small fix for VFS_TRUNCATE. Move lookup and registration code to separate
modules.

Location:
uspace/srv/vfs
Files:
2 added
2 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/vfs/Makefile

    r4cc2ddd r62da45a  
    11#
    22# Copyright (c) 2006 Martin Decky
    3 # Copyright (c) 2007 Jakub Jermar
     3# Copyright (c) 2008 Jakub Jermar
    44# All rights reserved.
    55#
     
    4545        vfs_node.c \
    4646        vfs_file.c \
    47         vfs_ops.c
     47        vfs_ops.c \
     48        vfs_lookup.c \
     49        vfs_register.c
    4850
    4951OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
  • uspace/srv/vfs/vfs_ops.c

    r4cc2ddd r62da45a  
    3737
    3838#include <ipc/ipc.h>
    39 #include <ipc/services.h>
    4039#include <async.h>
    41 #include <fibril.h>
    4240#include <errno.h>
    4341#include <stdio.h>
     
    5048#include <unistd.h>
    5149#include <ctype.h>
    52 #include <as.h>
    5350#include <assert.h>
    5451#include <atomic.h>
    5552#include "vfs.h"
    56 
    57 #define min(a, b)       ((a) < (b) ? (a) : (b))
    5853
    5954/**
     
    6257 */
    6358RWLOCK_INITIALIZE(namespace_rwlock);
    64 
    65 atomic_t plb_futex = FUTEX_INITIALIZER;
    66 link_t plb_head;        /**< PLB entry ring buffer. */
    67 uint8_t *plb = NULL;
    68 
    69 /** Perform a path lookup.
    70  *
    71  * @param path          Path to be resolved; it needn't be an ASCIIZ string.
    72  * @param len           Number of path characters pointed by path.
    73  * @param result        Empty structure where the lookup result will be stored.
    74  * @param altroot       If non-empty, will be used instead of rootfs as the root
    75  *                      of the whole VFS tree.
    76  *
    77  * @return              EOK on success or an error code from errno.h.
    78  */
    79 int vfs_lookup_internal(char *path, size_t len, vfs_lookup_res_t *result,
    80     vfs_pair_t *altroot)
    81 {
    82         vfs_pair_t *root;
    83 
    84         if (!len)
    85                 return EINVAL;
    86 
    87         if (altroot)
    88                 root = altroot;
    89         else
    90                 root = (vfs_pair_t *) &rootfs;
    91 
    92         if (!root->fs_handle)
    93                 return ENOENT;
    94        
    95         futex_down(&plb_futex);
    96 
    97         plb_entry_t entry;
    98         link_initialize(&entry.plb_link);
    99         entry.len = len;
    100 
    101         off_t first;    /* the first free index */
    102         off_t last;     /* the last free index */
    103 
    104         if (list_empty(&plb_head)) {
    105                 first = 0;
    106                 last = PLB_SIZE - 1;
    107         } else {
    108                 plb_entry_t *oldest = list_get_instance(plb_head.next,
    109                     plb_entry_t, plb_link);
    110                 plb_entry_t *newest = list_get_instance(plb_head.prev,
    111                     plb_entry_t, plb_link);
    112 
    113                 first = (newest->index + newest->len) % PLB_SIZE;
    114                 last = (oldest->index - 1) % PLB_SIZE;
    115         }
    116 
    117         if (first <= last) {
    118                 if ((last - first) + 1 < len) {
    119                         /*
    120                          * The buffer cannot absorb the path.
    121                          */
    122                         futex_up(&plb_futex);
    123                         return ELIMIT;
    124                 }
    125         } else {
    126                 if (PLB_SIZE - ((first - last) + 1) < len) {
    127                         /*
    128                          * The buffer cannot absorb the path.
    129                          */
    130                         futex_up(&plb_futex);
    131                         return ELIMIT;
    132                 }
    133         }
    134 
    135         /*
    136          * We know the first free index in PLB and we also know that there is
    137          * enough space in the buffer to hold our path.
    138          */
    139 
    140         entry.index = first;
    141         entry.len = len;
    142 
    143         /*
    144          * Claim PLB space by inserting the entry into the PLB entry ring
    145          * buffer.
    146          */
    147         list_append(&entry.plb_link, &plb_head);
    148        
    149         futex_up(&plb_futex);
    150 
    151         /*
    152          * Copy the path into PLB.
    153          */
    154         size_t cnt1 = min(len, (PLB_SIZE - first) + 1);
    155         size_t cnt2 = len - cnt1;
    156        
    157         memcpy(&plb[first], path, cnt1);
    158         memcpy(plb, &path[cnt1], cnt2);
    159 
    160         ipc_call_t answer;
    161         int phone = vfs_grab_phone(root->fs_handle);
    162         aid_t req = async_send_3(phone, VFS_LOOKUP, (ipcarg_t) first,
    163             (ipcarg_t) (first + len - 1) % PLB_SIZE,
    164             (ipcarg_t) root->dev_handle, &answer);
    165         vfs_release_phone(phone);
    166 
    167         ipcarg_t rc;
    168         async_wait_for(req, &rc);
    169 
    170         futex_down(&plb_futex);
    171         list_remove(&entry.plb_link);
    172         /*
    173          * Erasing the path from PLB will come handy for debugging purposes.
    174          */
    175         memset(&plb[first], 0, cnt1);
    176         memset(plb, 0, cnt2);
    177         futex_up(&plb_futex);
    178 
    179         if (rc == EOK) {
    180                 result->triplet.fs_handle = (int) IPC_GET_ARG1(answer);
    181                 result->triplet.dev_handle = (int) IPC_GET_ARG2(answer);
    182                 result->triplet.index = (int) IPC_GET_ARG3(answer);
    183                 result->size = (size_t) IPC_GET_ARG4(answer);
    184         }
    185 
    186         return rc;
    187 }
    18859
    18960atomic_t rootfs_futex = FUTEX_INITIALIZER;
     
    713584
    714585        futex_up(&file->lock);
    715 
    716         return rc;     
    717 }
    718 
    719 atomic_t fs_head_futex = FUTEX_INITIALIZER;
    720 link_t fs_head;
    721 
    722 atomic_t fs_handle_next = {
    723         .count = 1
    724 };
    725 
    726 /** Verify the VFS info structure.
    727  *
    728  * @param info          Info structure to be verified.
    729  *
    730  * @return              Non-zero if the info structure is sane, zero otherwise.
    731  */
    732 static bool vfs_info_sane(vfs_info_t *info)
    733 {
    734         int i;
    735 
    736         /*
    737          * Check if the name is non-empty and is composed solely of ASCII
    738          * characters [a-z]+[a-z0-9_-]*.
    739          */
    740         if (!islower(info->name[0])) {
    741                 dprintf("The name doesn't start with a lowercase character.\n");
    742                 return false;
    743         }
    744         for (i = 1; i < FS_NAME_MAXLEN; i++) {
    745                 if (!(islower(info->name[i]) || isdigit(info->name[i])) &&
    746                     (info->name[i] != '-') && (info->name[i] != '_')) {
    747                         if (info->name[i] == '\0') {
    748                                 break;
    749                         } else {
    750                                 dprintf("The name contains illegal "
    751                                     "characters.\n");
    752                                 return false;
    753                         }
    754                 }
    755         }
    756         /*
    757          * This check is not redundant. It ensures that the name is
    758          * NULL-terminated, even if FS_NAME_MAXLEN characters are used.
    759          */
    760         if (info->name[i] != '\0') {
    761                 dprintf("The name is not properly NULL-terminated.\n");
    762                 return false;
    763         }
    764        
    765 
    766         /*
    767          * Check if the FS implements mandatory VFS operations.
    768          */
    769         if (info->ops[IPC_METHOD_TO_VFS_OP(VFS_LOOKUP)] != VFS_OP_DEFINED) {
    770                 dprintf("Operation VFS_LOOKUP not defined by the client.\n");
    771                 return false;
    772         }
    773         if (info->ops[IPC_METHOD_TO_VFS_OP(VFS_OPEN)] != VFS_OP_DEFINED) {
    774                 dprintf("Operation VFS_OPEN not defined by the client.\n");
    775                 return false;
    776         }
    777         if (info->ops[IPC_METHOD_TO_VFS_OP(VFS_CLOSE)] != VFS_OP_DEFINED) {
    778                 dprintf("Operation VFS_CLOSE not defined by the client.\n");
    779                 return false;
    780         }
    781         if (info->ops[IPC_METHOD_TO_VFS_OP(VFS_READ)] != VFS_OP_DEFINED) {
    782                 dprintf("Operation VFS_READ not defined by the client.\n");
    783                 return false;
    784         }
    785        
    786         /*
    787          * Check if each operation is either not defined, defined or default.
    788          */
    789         for (i = VFS_FIRST; i < VFS_LAST_CLNT; i++) {
    790                 if ((info->ops[IPC_METHOD_TO_VFS_OP(i)] != VFS_OP_NULL) &&
    791                     (info->ops[IPC_METHOD_TO_VFS_OP(i)] != VFS_OP_DEFAULT) &&
    792                     (info->ops[IPC_METHOD_TO_VFS_OP(i)] != VFS_OP_DEFINED)) {
    793                         dprintf("Operation info not understood.\n");
    794                         return false;
    795                 }
    796         }
    797         return true;
    798 }
    799 
    800 /** VFS_REGISTER protocol function.
    801  *
    802  * @param rid           Hash of the call with the request.
    803  * @param request       Call structure with the request.
    804  */
    805 void vfs_register(ipc_callid_t rid, ipc_call_t *request)
    806 {
    807         ipc_callid_t callid;
    808         ipc_call_t call;
    809         int rc;
    810         size_t size;
    811 
    812         dprintf("Processing VFS_REGISTER request received from %p.\n",
    813             request->in_phone_hash);
    814 
    815         /*
    816          * The first call has to be IPC_M_DATA_SEND in which we receive the
    817          * VFS info structure from the client FS.
    818          */
    819         if (!ipc_data_write_receive(&callid, &size)) {
    820                 /*
    821                  * The client doesn't obey the same protocol as we do.
    822                  */
    823                 dprintf("Receiving of VFS info failed.\n");
    824                 ipc_answer_0(callid, EINVAL);
    825                 ipc_answer_0(rid, EINVAL);
    826                 return;
    827         }
    828        
    829         dprintf("VFS info received, size = %d\n", size);
    830        
    831         /*
    832          * We know the size of the VFS info structure. See if the client
    833          * understands this easy concept too.
    834          */
    835         if (size != sizeof(vfs_info_t)) {
    836                 /*
    837                  * The client is sending us something, which cannot be
    838                  * the info structure.
    839                  */
    840                 dprintf("Received VFS info has bad size.\n");
    841                 ipc_answer_0(callid, EINVAL);
    842                 ipc_answer_0(rid, EINVAL);
    843                 return;
    844         }
    845 
    846         /*
    847          * Allocate and initialize a buffer for the fs_info structure.
    848          */
    849         fs_info_t *fs_info;
    850         fs_info = (fs_info_t *) malloc(sizeof(fs_info_t));
    851         if (!fs_info) {
    852                 dprintf("Could not allocate memory for FS info.\n");
    853                 ipc_answer_0(callid, ENOMEM);
    854                 ipc_answer_0(rid, ENOMEM);
    855                 return;
    856         }
    857         link_initialize(&fs_info->fs_link);
    858         futex_initialize(&fs_info->phone_futex, 1);
    859                
    860         rc = ipc_data_write_finalize(callid, &fs_info->vfs_info, size);
    861         if (rc != EOK) {
    862                 dprintf("Failed to deliver the VFS info into our AS, rc=%d.\n",
    863                     rc);
    864                 free(fs_info);
    865                 ipc_answer_0(callid, rc);
    866                 ipc_answer_0(rid, rc);
    867                 return;
    868         }
    869 
    870         dprintf("VFS info delivered.\n");
    871                
    872         if (!vfs_info_sane(&fs_info->vfs_info)) {
    873                 free(fs_info);
    874                 ipc_answer_0(callid, EINVAL);
    875                 ipc_answer_0(rid, EINVAL);
    876                 return;
    877         }
    878                
    879         futex_down(&fs_head_futex);
    880 
    881         /*
    882          * Check for duplicit registrations.
    883          */
    884         if (fs_name_to_handle(fs_info->vfs_info.name, false)) {
    885                 /*
    886                  * We already register a fs like this.
    887                  */
    888                 dprintf("FS is already registered.\n");
    889                 futex_up(&fs_head_futex);
    890                 free(fs_info);
    891                 ipc_answer_0(callid, EEXISTS);
    892                 ipc_answer_0(rid, EEXISTS);
    893                 return;
    894         }
    895 
    896         /*
    897          * Add fs_info to the list of registered FS's.
    898          */
    899         dprintf("Inserting FS into the list of registered file systems.\n");
    900         list_append(&fs_info->fs_link, &fs_head);
    901 
    902         /*
    903          * Now we want the client to send us the IPC_M_CONNECT_TO_ME call so
    904          * that a callback connection is created and we have a phone through
    905          * which to forward VFS requests to it.
    906          */
    907         callid = async_get_call(&call);
    908         if (IPC_GET_METHOD(call) != IPC_M_CONNECT_TO_ME) {
    909                 dprintf("Unexpected call, method = %d\n", IPC_GET_METHOD(call));
    910                 list_remove(&fs_info->fs_link);
    911                 futex_up(&fs_head_futex);
    912                 free(fs_info);
    913                 ipc_answer_0(callid, EINVAL);
    914                 ipc_answer_0(rid, EINVAL);
    915                 return;
    916         }
    917         fs_info->phone = IPC_GET_ARG5(call);
    918         ipc_answer_0(callid, EOK);
    919 
    920         dprintf("Callback connection to FS created.\n");
    921 
    922         /*
    923          * The client will want us to send him the address space area with PLB.
    924          */
    925 
    926         if (!ipc_share_in_receive(&callid, &size)) {
    927                 dprintf("Unexpected call, method = %d\n", IPC_GET_METHOD(call));
    928                 list_remove(&fs_info->fs_link);
    929                 futex_up(&fs_head_futex);
    930                 ipc_hangup(fs_info->phone);
    931                 free(fs_info);
    932                 ipc_answer_0(callid, EINVAL);
    933                 ipc_answer_0(rid, EINVAL);
    934                 return;
    935         }
    936        
    937         /*
    938          * We can only send the client address space area PLB_SIZE bytes long.
    939          */
    940         if (size != PLB_SIZE) {
    941                 dprintf("Client suggests wrong size of PFB, size = %d\n", size);
    942                 list_remove(&fs_info->fs_link);
    943                 futex_up(&fs_head_futex);
    944                 ipc_hangup(fs_info->phone);
    945                 free(fs_info);
    946                 ipc_answer_0(callid, EINVAL);
    947                 ipc_answer_0(rid, EINVAL);
    948                 return;
    949         }
    950 
    951         /*
    952          * Commit to read-only sharing the PLB with the client.
    953          */
    954         (void) ipc_share_in_finalize(callid, plb,
    955             AS_AREA_READ | AS_AREA_CACHEABLE);
    956 
    957         dprintf("Sharing PLB.\n");
    958 
    959         /*
    960          * That was it. The FS has been registered.
    961          * In reply to the VFS_REGISTER request, we assign the client file
    962          * system a global file system handle.
    963          */
    964         fs_info->fs_handle = (int) atomic_postinc(&fs_handle_next);
    965         ipc_answer_1(rid, EOK, (ipcarg_t) fs_info->fs_handle);
    966        
    967         futex_up(&fs_head_futex);
    968        
    969         dprintf("\"%.*s\" filesystem successfully registered, handle=%d.\n",
    970             FS_NAME_MAXLEN, fs_info->vfs_info.name, fs_info->fs_handle);
    971 }
    972 
    973 /** For a given file system handle, implement policy for allocating a phone.
    974  *
    975  * @param handle        File system handle.
    976  *
    977  * @return              Phone over which a multi-call request can be safely
    978  *                      sent. Return 0 if no phone was found.
    979  */
    980 int vfs_grab_phone(int handle)
    981 {
    982         /*
    983          * For now, we don't try to be very clever and very fast.
    984          * We simply lookup the phone in the fs_head list. We currently don't
    985          * open any additional phones (even though that itself would be pretty
    986          * straightforward; housekeeping multiple open phones to a FS task would
    987          * be more demanding). Instead, we simply take the respective
    988          * phone_futex and keep it until vfs_release_phone().
    989          */
    990         futex_down(&fs_head_futex);
    991         link_t *cur;
    992         fs_info_t *fs;
    993         for (cur = fs_head.next; cur != &fs_head; cur = cur->next) {
    994                 fs = list_get_instance(cur, fs_info_t, fs_link);
    995                 if (fs->fs_handle == handle) {
    996                         futex_up(&fs_head_futex);
    997                         /*
    998                          * For now, take the futex unconditionally.
    999                          * Oh yeah, serialization rocks.
    1000                          * It will be up'ed in vfs_release_phone().
    1001                          */
    1002                         futex_down(&fs->phone_futex);
    1003                         /*
    1004                          * Avoid deadlock with other fibrils in the same thread
    1005                          * by disabling fibril preemption.
    1006                          */
    1007                         fibril_inc_sercount();
    1008                         return fs->phone;
    1009                 }
    1010         }
    1011         futex_up(&fs_head_futex);
    1012         return 0;
    1013 }
    1014 
    1015 /** Tell VFS that the phone is in use for any request.
    1016  *
    1017  * @param phone         Phone to FS task.
    1018  */
    1019 void vfs_release_phone(int phone)
    1020 {
    1021         bool found = false;
    1022 
    1023         /*
    1024          * Undo the fibril_inc_sercount() done in vfs_grab_phone().
    1025          */
    1026         fibril_dec_sercount();
    1027        
    1028         futex_down(&fs_head_futex);
    1029         link_t *cur;
    1030         for (cur = fs_head.next; cur != &fs_head; cur = cur->next) {
    1031                 fs_info_t *fs = list_get_instance(cur, fs_info_t, fs_link);
    1032                 if (fs->phone == phone) {
    1033                         found = true;
    1034                         futex_up(&fs_head_futex);
    1035                         futex_up(&fs->phone_futex);
    1036                         return;
    1037                 }
    1038         }
    1039         futex_up(&fs_head_futex);
    1040 
    1041         /*
    1042          * Not good to get here.
    1043          */
    1044         assert(found == true);
    1045 }
    1046 
    1047 /** Convert file system name to its handle.
    1048  *
    1049  * @param name          File system name.
    1050  * @param lock          If true, the function will down and up the
    1051  *                      fs_head_futex.
    1052  *
    1053  * @return              File system handle or zero if file system not found.
    1054  */
    1055 int fs_name_to_handle(char *name, bool lock)
    1056 {
    1057         int handle = 0;
    1058        
    1059         if (lock)
    1060                 futex_down(&fs_head_futex);
    1061         link_t *cur;
    1062         for (cur = fs_head.next; cur != &fs_head; cur = cur->next) {
    1063                 fs_info_t *fs = list_get_instance(cur, fs_info_t, fs_link);
    1064                 if (strncmp(fs->vfs_info.name, name,
    1065                     sizeof(fs->vfs_info.name)) == 0) {
    1066                         handle = fs->fs_handle;
    1067                         break;
    1068                 }
    1069         }
    1070         if (lock)
    1071                 futex_up(&fs_head_futex);
    1072         return handle;
     586        ipc_answer_0(rid, rc);
    1073587}
    1074588
Note: See TracChangeset for help on using the changeset viewer.