Ignore:
File:
1 edited

Legend:

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

    r553492be r4fe94c66  
    3838#include <errno.h>
    3939#include <stdlib.h>
    40 #include <string.h>
     40#include <str.h>
    4141#include <assert.h>
    4242#include <bool.h>
    4343#include <fibril.h>
    44 #include <fibril_sync.h>
     44#include <fibril_synch.h>
    4545#include "vfs.h"
    4646
    47 /**
    48  * This is a per-connection table of open files.
    49  * Our assumption is that each client opens only one connection and therefore
    50  * there is one table of open files per task. However, this may not be the case
    51  * and the client can open more connections to VFS. In that case, there will be
    52  * several tables and several file handle name spaces per task. Besides of this,
    53  * the functionality will stay unchanged. So unless the client knows what it is
    54  * doing, it should open one connection to VFS only.
    55  *
    56  * Allocation of the open files table is deferred until the client makes the
    57  * first VFS_OPEN operation.
    58  *
    59  * This resource being per-connection and, in the first place, per-fibril, we
    60  * don't need to protect it by a mutex.
    61  */
    62 fibril_local vfs_file_t **files = NULL;
     47#define VFS_DATA        ((vfs_client_data_t *) async_client_data_get())
     48#define FILES           (VFS_DATA->files)
     49
     50typedef struct {
     51        fibril_mutex_t lock;
     52        vfs_file_t **files;
     53} vfs_client_data_t;
    6354
    6455/** Initialize the table of open files. */
    65 bool vfs_files_init(void)
    66 {
    67         if (!files) {
    68                 files = malloc(MAX_OPEN_FILES * sizeof(vfs_file_t *));
    69                 if (!files)
     56static bool vfs_files_init(void)
     57{
     58        fibril_mutex_lock(&VFS_DATA->lock);
     59        if (!FILES) {
     60                FILES = malloc(MAX_OPEN_FILES * sizeof(vfs_file_t *));
     61                if (!FILES) {
     62                        fibril_mutex_unlock(&VFS_DATA->lock);
    7063                        return false;
    71                 memset(files, 0, MAX_OPEN_FILES * sizeof(vfs_file_t *));
    72         }
     64                }
     65                memset(FILES, 0, MAX_OPEN_FILES * sizeof(vfs_file_t *));
     66        }
     67        fibril_mutex_unlock(&VFS_DATA->lock);
    7368        return true;
    7469}
    7570
    76 /** Allocate a file descriptor.
    77  *
    78  * @return              First available file descriptor or a negative error
    79  *                      code.
    80  */
    81 int vfs_fd_alloc(void)
    82 {
    83         if (!vfs_files_init())
    84                 return ENOMEM;
    85        
    86         unsigned int i;
     71/** Cleanup the table of open files. */
     72static void vfs_files_done(void)
     73{
     74        int i;
     75
     76        if (!FILES)
     77                return;
     78
    8779        for (i = 0; i < MAX_OPEN_FILES; i++) {
    88                 if (!files[i]) {
    89                         files[i] = (vfs_file_t *) malloc(sizeof(vfs_file_t));
    90                         if (!files[i])
    91                                 return ENOMEM;
    92                        
    93                         memset(files[i], 0, sizeof(vfs_file_t));
    94                         fibril_mutex_initialize(&files[i]->lock);
    95                         vfs_file_addref(files[i]);
    96                         return (int) i;
    97                 }
    98         }
    99        
    100         return EMFILE;
    101 }
    102 
    103 /** Release file descriptor.
    104  *
    105  * @param fd            File descriptor being released.
    106  *
    107  * @return              EOK on success or EBADF if fd is an invalid file
    108  *                      descriptor.
    109  */
    110 int vfs_fd_free(int fd)
    111 {
    112         if (!vfs_files_init())
    113                 return ENOMEM;
    114        
    115         if ((fd < 0) || (fd >= MAX_OPEN_FILES) || (files[fd] == NULL))
    116                 return EBADF;
    117        
    118         vfs_file_delref(files[fd]);
    119         files[fd] = NULL;
    120        
    121         return EOK;
     80                if (FILES[i]) {
     81                        (void) vfs_close_internal(FILES[i]);
     82                        (void) vfs_fd_free(i);
     83                }
     84        }
     85       
     86        free(FILES);
     87}
     88
     89void *vfs_client_data_create(void)
     90{
     91        vfs_client_data_t *vfs_data;
     92
     93        vfs_data = malloc(sizeof(vfs_client_data_t));
     94        if (vfs_data) {
     95                fibril_mutex_initialize(&vfs_data->lock);
     96                vfs_data->files = NULL;
     97        }
     98       
     99        return vfs_data;
     100}
     101
     102void vfs_client_data_destroy(void *data)
     103{
     104        vfs_client_data_t *vfs_data = (vfs_client_data_t *) data;
     105
     106        vfs_files_done();
     107        free(vfs_data);
    122108}
    123109
     
    127113 *                      incremented.
    128114 */
    129 void vfs_file_addref(vfs_file_t *file)
    130 {
    131         /*
    132          * File structures are per-connection, so no-one, except the current
    133          * fibril, should have a reference to them. This is the reason we don't
    134          * do any synchronization here.
    135          */
     115static void vfs_file_addref(vfs_file_t *file)
     116{
     117        assert(fibril_mutex_is_locked(&VFS_DATA->lock));
     118
    136119        file->refcnt++;
    137120}
     
    142125 *                      decremented.
    143126 */
    144 void vfs_file_delref(vfs_file_t *file)
    145 {
     127static void vfs_file_delref(vfs_file_t *file)
     128{
     129        assert(fibril_mutex_is_locked(&VFS_DATA->lock));
     130
    146131        if (file->refcnt-- == 1) {
    147132                /*
     
    154139}
    155140
     141
     142/** Allocate a file descriptor.
     143 *
     144 * @param desc If true, look for an available file descriptor
     145 *             in a descending order.
     146 *
     147 * @return First available file descriptor or a negative error
     148 *         code.
     149 */
     150int vfs_fd_alloc(bool desc)
     151{
     152        if (!vfs_files_init())
     153                return ENOMEM;
     154       
     155        unsigned int i;
     156        if (desc)
     157                i = MAX_OPEN_FILES - 1;
     158        else
     159                i = 0;
     160       
     161        fibril_mutex_lock(&VFS_DATA->lock);
     162        while (true) {
     163                if (!FILES[i]) {
     164                        FILES[i] = (vfs_file_t *) malloc(sizeof(vfs_file_t));
     165                        if (!FILES[i]) {
     166                                fibril_mutex_unlock(&VFS_DATA->lock);
     167                                return ENOMEM;
     168                        }
     169                       
     170                        memset(FILES[i], 0, sizeof(vfs_file_t));
     171                        fibril_mutex_initialize(&FILES[i]->lock);
     172                        vfs_file_addref(FILES[i]);
     173                        fibril_mutex_unlock(&VFS_DATA->lock);
     174                        return (int) i;
     175                }
     176               
     177                if (desc) {
     178                        if (i == 0)
     179                                break;
     180                       
     181                        i--;
     182                } else {
     183                        if (i == MAX_OPEN_FILES - 1)
     184                                break;
     185                       
     186                        i++;
     187                }
     188        }
     189        fibril_mutex_unlock(&VFS_DATA->lock);
     190       
     191        return EMFILE;
     192}
     193
     194/** Release file descriptor.
     195 *
     196 * @param fd            File descriptor being released.
     197 *
     198 * @return              EOK on success or EBADF if fd is an invalid file
     199 *                      descriptor.
     200 */
     201int vfs_fd_free(int fd)
     202{
     203        if (!vfs_files_init())
     204                return ENOMEM;
     205
     206        fibril_mutex_lock(&VFS_DATA->lock);     
     207        if ((fd < 0) || (fd >= MAX_OPEN_FILES) || (FILES[fd] == NULL)) {
     208                fibril_mutex_unlock(&VFS_DATA->lock);
     209                return EBADF;
     210        }
     211       
     212        vfs_file_delref(FILES[fd]);
     213        FILES[fd] = NULL;
     214        fibril_mutex_unlock(&VFS_DATA->lock);
     215       
     216        return EOK;
     217}
     218
     219/** Assign a file to a file descriptor.
     220 *
     221 * @param file File to assign.
     222 * @param fd   File descriptor to assign to.
     223 *
     224 * @return EOK on success or EINVAL if fd is an invalid or already
     225 *         used file descriptor.
     226 *
     227 */
     228int vfs_fd_assign(vfs_file_t *file, int fd)
     229{
     230        if (!vfs_files_init())
     231                return ENOMEM;
     232
     233        fibril_mutex_lock(&VFS_DATA->lock);     
     234        if ((fd < 0) || (fd >= MAX_OPEN_FILES) || (FILES[fd] != NULL)) {
     235                fibril_mutex_unlock(&VFS_DATA->lock);
     236                return EINVAL;
     237        }
     238       
     239        FILES[fd] = file;
     240        vfs_file_addref(FILES[fd]);
     241        fibril_mutex_unlock(&VFS_DATA->lock);
     242       
     243        return EOK;
     244}
     245
    156246/** Find VFS file structure for a given file descriptor.
    157247 *
     
    165255                return NULL;
    166256       
    167         if ((fd >= 0) && (fd < MAX_OPEN_FILES))
    168                 return files[fd];
     257        fibril_mutex_lock(&VFS_DATA->lock);
     258        if ((fd >= 0) && (fd < MAX_OPEN_FILES)) {
     259                vfs_file_t *file = FILES[fd];
     260                vfs_file_addref(file);
     261                fibril_mutex_unlock(&VFS_DATA->lock);
     262                return file;
     263        }
     264        fibril_mutex_unlock(&VFS_DATA->lock);
    169265       
    170266        return NULL;
     267}
     268
     269/** Stop using a file structure.
     270 *
     271 * @param file          VFS file structure.
     272 */
     273void vfs_file_put(vfs_file_t *file)
     274{
     275        fibril_mutex_lock(&VFS_DATA->lock);
     276        vfs_file_delref(file);
     277        fibril_mutex_unlock(&VFS_DATA->lock);
    171278}
    172279
Note: See TracChangeset for help on using the changeset viewer.