vfs_register.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2008 Jakub Jermar
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  */
00028 
00038 #include <ipc/services.h>
00039 #include <async.h>
00040 #include <fibril.h>
00041 #include <fibril_synch.h>
00042 #include <errno.h>
00043 #include <stdio.h>
00044 #include <stdlib.h>
00045 #include <str.h>
00046 #include <ctype.h>
00047 #include <bool.h>
00048 #include <adt/list.h>
00049 #include <as.h>
00050 #include <assert.h>
00051 #include <atomic.h>
00052 #include "vfs.h"
00053 
00054 FIBRIL_CONDVAR_INITIALIZE(fs_head_cv);
00055 FIBRIL_MUTEX_INITIALIZE(fs_head_lock);
00056 LIST_INITIALIZE(fs_head);
00057 
00058 atomic_t fs_handle_next = {
00059         .count = 1
00060 };
00061 
00068 static bool vfs_info_sane(vfs_info_t *info)
00069 {
00070         int i;
00071 
00072         /*
00073          * Check if the name is non-empty and is composed solely of ASCII
00074          * characters [a-z]+[a-z0-9_-]*.
00075          */
00076         if (!islower(info->name[0])) {
00077                 dprintf("The name doesn't start with a lowercase character.\n");
00078                 return false;
00079         }
00080         for (i = 1; i < FS_NAME_MAXLEN; i++) {
00081                 if (!(islower(info->name[i]) || isdigit(info->name[i])) &&
00082                     (info->name[i] != '-') && (info->name[i] != '_')) {
00083                         if (info->name[i] == '\0') {
00084                                 break;
00085                         } else {
00086                                 dprintf("The name contains illegal "
00087                                     "characters.\n");
00088                                 return false;
00089                         }
00090                 }
00091         }
00092         /*
00093          * This check is not redundant. It ensures that the name is
00094          * NULL-terminated, even if FS_NAME_MAXLEN characters are used.
00095          */
00096         if (info->name[i] != '\0') {
00097                 dprintf("The name is not properly NULL-terminated.\n"); 
00098                 return false;
00099         }
00100         
00101         return true;
00102 }
00103 
00109 void vfs_register(ipc_callid_t rid, ipc_call_t *request)
00110 {
00111         int phone;
00112         
00113         dprintf("Processing VFS_REGISTER request received from %p.\n",
00114             request->in_phone_hash);
00115         
00116         vfs_info_t *vfs_info;
00117         int rc = async_data_write_accept((void **) &vfs_info, false,
00118             sizeof(vfs_info_t), sizeof(vfs_info_t), 0, NULL);
00119         
00120         if (rc != EOK) {
00121                 dprintf("Failed to deliver the VFS info into our AS, rc=%d.\n",
00122                     rc);
00123                 async_answer_0(rid, rc);
00124                 return;
00125         }
00126         
00127         /*
00128          * Allocate and initialize a buffer for the fs_info structure.
00129          */
00130         fs_info_t *fs_info = (fs_info_t *) malloc(sizeof(fs_info_t));
00131         if (!fs_info) {
00132                 dprintf("Could not allocate memory for FS info.\n");
00133                 async_answer_0(rid, ENOMEM);
00134                 return;
00135         }
00136         
00137         link_initialize(&fs_info->fs_link);
00138         fs_info->vfs_info = *vfs_info;
00139         free(vfs_info);
00140         
00141         dprintf("VFS info delivered.\n");
00142         
00143         if (!vfs_info_sane(&fs_info->vfs_info)) {
00144                 free(fs_info);
00145                 async_answer_0(rid, EINVAL);
00146                 return;
00147         }
00148         
00149         fibril_mutex_lock(&fs_head_lock);
00150         
00151         /*
00152          * Check for duplicit registrations.
00153          */
00154         if (fs_name_to_handle(fs_info->vfs_info.name, false)) {
00155                 /*
00156                  * We already register a fs like this.
00157                  */
00158                 dprintf("FS is already registered.\n");
00159                 fibril_mutex_unlock(&fs_head_lock);
00160                 free(fs_info);
00161                 async_answer_0(rid, EEXISTS);
00162                 return;
00163         }
00164         
00165         /*
00166          * Add fs_info to the list of registered FS's.
00167          */
00168         dprintf("Inserting FS into the list of registered file systems.\n");
00169         list_append(&fs_info->fs_link, &fs_head);
00170         
00171         /*
00172          * Now we want the client to send us the IPC_M_CONNECT_TO_ME call so
00173          * that a callback connection is created and we have a phone through
00174          * which to forward VFS requests to it.
00175          */
00176         ipc_call_t call;
00177         ipc_callid_t callid = async_get_call(&call);
00178         if (IPC_GET_IMETHOD(call) != IPC_M_CONNECT_TO_ME) {
00179                 dprintf("Unexpected call, method = %d\n", IPC_GET_IMETHOD(call));
00180                 list_remove(&fs_info->fs_link);
00181                 fibril_mutex_unlock(&fs_head_lock);
00182                 free(fs_info);
00183                 async_answer_0(callid, EINVAL);
00184                 async_answer_0(rid, EINVAL);
00185                 return;
00186         }
00187         
00188         phone = IPC_GET_ARG5(call);
00189         async_session_create(&fs_info->session, phone, 0);
00190         async_answer_0(callid, EOK);
00191         
00192         dprintf("Callback connection to FS created.\n");
00193         
00194         /*
00195          * The client will want us to send him the address space area with PLB.
00196          */
00197         
00198         size_t size;
00199         if (!async_share_in_receive(&callid, &size)) {
00200                 dprintf("Unexpected call, method = %d\n", IPC_GET_IMETHOD(call));
00201                 list_remove(&fs_info->fs_link);
00202                 fibril_mutex_unlock(&fs_head_lock);
00203                 async_session_destroy(&fs_info->session);
00204                 async_hangup(phone);
00205                 free(fs_info);
00206                 async_answer_0(callid, EINVAL);
00207                 async_answer_0(rid, EINVAL);
00208                 return;
00209         }
00210         
00211         /*
00212          * We can only send the client address space area PLB_SIZE bytes long.
00213          */
00214         if (size != PLB_SIZE) {
00215                 dprintf("Client suggests wrong size of PFB, size = %d\n", size);
00216                 list_remove(&fs_info->fs_link);
00217                 fibril_mutex_unlock(&fs_head_lock);
00218                 async_session_destroy(&fs_info->session);
00219                 async_hangup(phone);
00220                 free(fs_info);
00221                 async_answer_0(callid, EINVAL);
00222                 async_answer_0(rid, EINVAL);
00223                 return;
00224         }
00225         
00226         /*
00227          * Commit to read-only sharing the PLB with the client.
00228          */
00229         (void) async_share_in_finalize(callid, plb,
00230             AS_AREA_READ | AS_AREA_CACHEABLE);
00231         
00232         dprintf("Sharing PLB.\n");
00233         
00234         /*
00235          * That was it. The FS has been registered.
00236          * In reply to the VFS_REGISTER request, we assign the client file
00237          * system a global file system handle.
00238          */
00239         fs_info->fs_handle = (fs_handle_t) atomic_postinc(&fs_handle_next);
00240         async_answer_1(rid, EOK, (sysarg_t) fs_info->fs_handle);
00241         
00242         fibril_condvar_broadcast(&fs_head_cv);
00243         fibril_mutex_unlock(&fs_head_lock);
00244         
00245         dprintf("\"%.*s\" filesystem successfully registered, handle=%d.\n",
00246             FS_NAME_MAXLEN, fs_info->vfs_info.name, fs_info->fs_handle);
00247 }
00248 
00256 int vfs_grab_phone(fs_handle_t handle)
00257 {
00258         link_t *cur;
00259         fs_info_t *fs;
00260         int phone;
00261 
00262         /*
00263          * For now, we don't try to be very clever and very fast.  We simply
00264          * lookup the phone in the fs_head list and duplicate it.  The duplicate
00265          * phone will be returned to the client and the client will use it for
00266          * communication.  In the future, we should cache the connections so
00267          * that they do not have to be reestablished over and over again.
00268          */
00269         fibril_mutex_lock(&fs_head_lock);
00270         for (cur = fs_head.next; cur != &fs_head; cur = cur->next) {
00271                 fs = list_get_instance(cur, fs_info_t, fs_link);
00272                 if (fs->fs_handle == handle) {
00273                         fibril_mutex_unlock(&fs_head_lock);
00274                         phone = async_exchange_begin(&fs->session);
00275 
00276                         assert(phone > 0);
00277                         return phone;
00278                 }
00279         }
00280         fibril_mutex_unlock(&fs_head_lock);
00281         return 0;
00282 }
00283 
00288 void vfs_release_phone(fs_handle_t handle, int phone)
00289 {
00290         link_t *cur;
00291         fs_info_t *fs;
00292 
00293         fibril_mutex_lock(&fs_head_lock);
00294         for (cur = fs_head.next; cur != &fs_head; cur = cur->next) {
00295                 fs = list_get_instance(cur, fs_info_t, fs_link);
00296                 if (fs->fs_handle == handle) {
00297                         fibril_mutex_unlock(&fs_head_lock);
00298                         async_exchange_end(&fs->session, phone);
00299                         return;
00300                 }
00301         }
00302         /* should not really get here */
00303         abort();
00304         fibril_mutex_unlock(&fs_head_lock);
00305 }
00306 
00315 fs_handle_t fs_name_to_handle(char *name, bool lock)
00316 {
00317         int handle = 0;
00318         
00319         if (lock)
00320                 fibril_mutex_lock(&fs_head_lock);
00321         link_t *cur;
00322         for (cur = fs_head.next; cur != &fs_head; cur = cur->next) {
00323                 fs_info_t *fs = list_get_instance(cur, fs_info_t, fs_link);
00324                 if (str_cmp(fs->vfs_info.name, name) == 0) { 
00325                         handle = fs->fs_handle;
00326                         break;
00327                 }
00328         }
00329         if (lock)
00330                 fibril_mutex_unlock(&fs_head_lock);
00331         return handle;
00332 }
00333 
00339 vfs_info_t *fs_handle_to_info(fs_handle_t handle)
00340 {
00341         vfs_info_t *info = NULL;
00342         link_t *cur;
00343 
00344         fibril_mutex_lock(&fs_head_lock);
00345         for (cur = fs_head.next; cur != &fs_head; cur = cur->next) {
00346                 fs_info_t *fs = list_get_instance(cur, fs_info_t, fs_link);
00347                 if (fs->fs_handle == handle) { 
00348                         info = &fs->vfs_info;
00349                         break;
00350                 }
00351         }
00352         fibril_mutex_unlock(&fs_head_lock);
00353 
00354         return info;
00355 }
00356 

Generated on Thu Jun 2 07:45:50 2011 for HelenOS/USB by  doxygen 1.4.7