vfs_file.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2007 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 <errno.h>
00039 #include <stdlib.h>
00040 #include <str.h>
00041 #include <assert.h>
00042 #include <bool.h>
00043 #include <fibril.h>
00044 #include <fibril_synch.h>
00045 #include "vfs.h"
00046 
00047 #define VFS_DATA        ((vfs_client_data_t *) async_client_data_get())
00048 #define FILES           (VFS_DATA->files)
00049 
00050 typedef struct {
00051         fibril_mutex_t lock;
00052         vfs_file_t **files;
00053 } vfs_client_data_t;
00054 
00056 static bool vfs_files_init(void)
00057 {
00058         fibril_mutex_lock(&VFS_DATA->lock);
00059         if (!FILES) {
00060                 FILES = malloc(MAX_OPEN_FILES * sizeof(vfs_file_t *));
00061                 if (!FILES) {
00062                         fibril_mutex_unlock(&VFS_DATA->lock);
00063                         return false;
00064                 }
00065                 memset(FILES, 0, MAX_OPEN_FILES * sizeof(vfs_file_t *));
00066         }
00067         fibril_mutex_unlock(&VFS_DATA->lock);
00068         return true;
00069 }
00070 
00072 static void vfs_files_done(void)
00073 {
00074         int i;
00075 
00076         if (!FILES)
00077                 return;
00078 
00079         for (i = 0; i < MAX_OPEN_FILES; i++) {
00080                 if (FILES[i]) {
00081                         (void) vfs_fd_free(i);
00082                 }
00083         }
00084         
00085         free(FILES);
00086 }
00087 
00088 void *vfs_client_data_create(void)
00089 {
00090         vfs_client_data_t *vfs_data;
00091 
00092         vfs_data = malloc(sizeof(vfs_client_data_t));
00093         if (vfs_data) {
00094                 fibril_mutex_initialize(&vfs_data->lock);
00095                 vfs_data->files = NULL;
00096         }
00097         
00098         return vfs_data;
00099 }
00100 
00101 void vfs_client_data_destroy(void *data)
00102 {
00103         vfs_client_data_t *vfs_data = (vfs_client_data_t *) data;
00104 
00105         vfs_files_done();
00106         free(vfs_data);
00107 }
00108 
00110 static int vfs_file_close_remote(vfs_file_t *file)
00111 {
00112         ipc_call_t answer;
00113         aid_t msg;
00114         sysarg_t rc;
00115         int phone;
00116 
00117         assert(!file->refcnt);
00118 
00119         phone = vfs_grab_phone(file->node->fs_handle);
00120         msg = async_send_2(phone, VFS_OUT_CLOSE, file->node->devmap_handle,
00121             file->node->index, &answer);
00122         async_wait_for(msg, &rc);
00123         vfs_release_phone(file->node->fs_handle, phone);
00124 
00125         return IPC_GET_ARG1(answer);
00126 }
00127 
00128 
00134 static void vfs_file_addref(vfs_file_t *file)
00135 {
00136         assert(fibril_mutex_is_locked(&VFS_DATA->lock));
00137 
00138         file->refcnt++;
00139 }
00140 
00146 static int vfs_file_delref(vfs_file_t *file)
00147 {
00148         int rc = EOK;
00149 
00150         assert(fibril_mutex_is_locked(&VFS_DATA->lock));
00151 
00152         if (file->refcnt-- == 1) {
00153                 /*
00154                  * Lost the last reference to a file, need to close it in the
00155                  * endpoint FS and drop our reference to the underlying VFS node.
00156                  */
00157                 rc = vfs_file_close_remote(file);
00158                 vfs_node_delref(file->node);
00159                 free(file);
00160         }
00161 
00162         return rc;
00163 }
00164 
00165 
00174 int vfs_fd_alloc(bool desc)
00175 {
00176         if (!vfs_files_init())
00177                 return ENOMEM;
00178         
00179         unsigned int i;
00180         if (desc)
00181                 i = MAX_OPEN_FILES - 1;
00182         else
00183                 i = 0;
00184         
00185         fibril_mutex_lock(&VFS_DATA->lock);
00186         while (true) {
00187                 if (!FILES[i]) {
00188                         FILES[i] = (vfs_file_t *) malloc(sizeof(vfs_file_t));
00189                         if (!FILES[i]) {
00190                                 fibril_mutex_unlock(&VFS_DATA->lock);
00191                                 return ENOMEM;
00192                         }
00193                         
00194                         memset(FILES[i], 0, sizeof(vfs_file_t));
00195                         fibril_mutex_initialize(&FILES[i]->lock);
00196                         vfs_file_addref(FILES[i]);
00197                         fibril_mutex_unlock(&VFS_DATA->lock);
00198                         return (int) i;
00199                 }
00200                 
00201                 if (desc) {
00202                         if (i == 0)
00203                                 break;
00204                         
00205                         i--;
00206                 } else {
00207                         if (i == MAX_OPEN_FILES - 1)
00208                                 break;
00209                         
00210                         i++;
00211                 }
00212         }
00213         fibril_mutex_unlock(&VFS_DATA->lock);
00214         
00215         return EMFILE;
00216 }
00217 
00225 int vfs_fd_free(int fd)
00226 {
00227         int rc;
00228 
00229         if (!vfs_files_init())
00230                 return ENOMEM;
00231 
00232         fibril_mutex_lock(&VFS_DATA->lock);     
00233         if ((fd < 0) || (fd >= MAX_OPEN_FILES) || (FILES[fd] == NULL)) {
00234                 fibril_mutex_unlock(&VFS_DATA->lock);
00235                 return EBADF;
00236         }
00237         
00238         rc = vfs_file_delref(FILES[fd]);
00239         FILES[fd] = NULL;
00240         fibril_mutex_unlock(&VFS_DATA->lock);
00241         
00242         return rc;
00243 }
00244 
00254 int vfs_fd_assign(vfs_file_t *file, int fd)
00255 {
00256         if (!vfs_files_init())
00257                 return ENOMEM;
00258 
00259         fibril_mutex_lock(&VFS_DATA->lock);     
00260         if ((fd < 0) || (fd >= MAX_OPEN_FILES) || (FILES[fd] != NULL)) {
00261                 fibril_mutex_unlock(&VFS_DATA->lock);
00262                 return EINVAL;
00263         }
00264         
00265         FILES[fd] = file;
00266         vfs_file_addref(FILES[fd]);
00267         fibril_mutex_unlock(&VFS_DATA->lock);
00268         
00269         return EOK;
00270 }
00271 
00278 vfs_file_t *vfs_file_get(int fd)
00279 {
00280         if (!vfs_files_init())
00281                 return NULL;
00282         
00283         fibril_mutex_lock(&VFS_DATA->lock);
00284         if ((fd >= 0) && (fd < MAX_OPEN_FILES)) {
00285                 vfs_file_t *file = FILES[fd];
00286                 if (file != NULL) {
00287                         vfs_file_addref(file);
00288                         fibril_mutex_unlock(&VFS_DATA->lock);
00289                         return file;
00290                 }
00291         }
00292         fibril_mutex_unlock(&VFS_DATA->lock);
00293         
00294         return NULL;
00295 }
00296 
00301 void vfs_file_put(vfs_file_t *file)
00302 {
00303         fibril_mutex_lock(&VFS_DATA->lock);
00304         vfs_file_delref(file);
00305         fibril_mutex_unlock(&VFS_DATA->lock);
00306 }
00307 

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