Ignore:
File:
1 edited

Legend:

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

    r4fe94c66 re2ab36f1  
    4343#include <fibril.h>
    4444#include <fibril_synch.h>
     45#include <adt/list.h>
     46#include <task.h>
    4547#include "vfs.h"
    4648
    47 #define VFS_DATA        ((vfs_client_data_t *) async_client_data_get())
     49#define VFS_DATA        ((vfs_client_data_t *) async_get_client_data())
    4850#define FILES           (VFS_DATA->files)
    4951
    5052typedef struct {
    5153        fibril_mutex_t lock;
     54        fibril_condvar_t cv;
     55        list_t passed_handles;
    5256        vfs_file_t **files;
    5357} vfs_client_data_t;
    5458
     59typedef struct {
     60        link_t link;
     61        int handle;
     62} vfs_boxed_handle_t;
     63
     64static int _vfs_fd_free(vfs_client_data_t *, int);
     65
    5566/** Initialize the table of open files. */
    56 static 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);
     67static bool vfs_files_init(vfs_client_data_t *vfs_data)
     68{
     69        fibril_mutex_lock(&vfs_data->lock);
     70        if (!vfs_data->files) {
     71                vfs_data->files = malloc(MAX_OPEN_FILES * sizeof(vfs_file_t *));
     72                if (!vfs_data->files) {
     73                        fibril_mutex_unlock(&vfs_data->lock);
    6374                        return false;
    6475                }
    65                 memset(FILES, 0, MAX_OPEN_FILES * sizeof(vfs_file_t *));
    66         }
    67         fibril_mutex_unlock(&VFS_DATA->lock);
     76                memset(vfs_data->files, 0, MAX_OPEN_FILES * sizeof(vfs_file_t *));
     77        }
     78        fibril_mutex_unlock(&vfs_data->lock);
    6879        return true;
    6980}
    7081
    7182/** Cleanup the table of open files. */
    72 static void vfs_files_done(void)
     83static void vfs_files_done(vfs_client_data_t *vfs_data)
    7384{
    7485        int i;
    7586
    76         if (!FILES)
     87        if (!vfs_data->files)
    7788                return;
    7889
    7990        for (i = 0; i < MAX_OPEN_FILES; i++) {
    80                 if (FILES[i]) {
    81                         (void) vfs_close_internal(FILES[i]);
    82                         (void) vfs_fd_free(i);
    83                 }
    84         }
    85        
    86         free(FILES);
     91                if (vfs_data->files[i])
     92                        (void) _vfs_fd_free(vfs_data, i);
     93        }
     94       
     95        free(vfs_data->files);
     96
     97        while (!list_empty(&vfs_data->passed_handles)) {
     98                link_t *lnk;
     99                vfs_boxed_handle_t *bh;
     100               
     101                lnk = list_first(&vfs_data->passed_handles);
     102                list_remove(lnk);
     103
     104                bh = list_get_instance(lnk, vfs_boxed_handle_t, link);
     105                free(bh);
     106        }
    87107}
    88108
     
    94114        if (vfs_data) {
    95115                fibril_mutex_initialize(&vfs_data->lock);
     116                fibril_condvar_initialize(&vfs_data->cv);
     117                list_initialize(&vfs_data->passed_handles);
    96118                vfs_data->files = NULL;
    97119        }
     
    104126        vfs_client_data_t *vfs_data = (vfs_client_data_t *) data;
    105127
    106         vfs_files_done();
     128        vfs_files_done(vfs_data);
    107129        free(vfs_data);
     130}
     131
     132/** Close the file in the endpoint FS server. */
     133static int vfs_file_close_remote(vfs_file_t *file)
     134{
     135        assert(!file->refcnt);
     136       
     137        async_exch_t *exch = vfs_exchange_grab(file->node->fs_handle);
     138       
     139        ipc_call_t answer;
     140        aid_t msg = async_send_2(exch, VFS_OUT_CLOSE, file->node->service_id,
     141            file->node->index, &answer);
     142       
     143        vfs_exchange_release(exch);
     144       
     145        sysarg_t rc;
     146        async_wait_for(msg, &rc);
     147       
     148        return IPC_GET_ARG1(answer);
    108149}
    109150
     
    113154 *                      incremented.
    114155 */
    115 static void vfs_file_addref(vfs_file_t *file)
    116 {
    117         assert(fibril_mutex_is_locked(&VFS_DATA->lock));
     156static void vfs_file_addref(vfs_client_data_t *vfs_data, vfs_file_t *file)
     157{
     158        assert(fibril_mutex_is_locked(&vfs_data->lock));
    118159
    119160        file->refcnt++;
     
    125166 *                      decremented.
    126167 */
    127 static void vfs_file_delref(vfs_file_t *file)
    128 {
    129         assert(fibril_mutex_is_locked(&VFS_DATA->lock));
     168static int vfs_file_delref(vfs_client_data_t *vfs_data, vfs_file_t *file)
     169{
     170        int rc = EOK;
     171
     172        assert(fibril_mutex_is_locked(&vfs_data->lock));
    130173
    131174        if (file->refcnt-- == 1) {
    132175                /*
    133                  * Lost the last reference to a file, need to drop our reference
    134                  * to the underlying VFS node.
     176                 * Lost the last reference to a file, need to close it in the
     177                 * endpoint FS and drop our reference to the underlying VFS node.
    135178                 */
     179                rc = vfs_file_close_remote(file);
    136180                vfs_node_delref(file->node);
    137181                free(file);
    138182        }
    139 }
    140 
    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  */
    150 int vfs_fd_alloc(bool desc)
    151 {
    152         if (!vfs_files_init())
     183
     184        return rc;
     185}
     186
     187static int _vfs_fd_alloc(vfs_client_data_t *vfs_data, bool desc)
     188{
     189        if (!vfs_files_init(vfs_data))
    153190                return ENOMEM;
    154191       
     
    159196                i = 0;
    160197       
    161         fibril_mutex_lock(&VFS_DATA->lock);
     198        fibril_mutex_lock(&vfs_data->lock);
    162199        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);
     200                if (!vfs_data->files[i]) {
     201                        vfs_data->files[i] = (vfs_file_t *) malloc(sizeof(vfs_file_t));
     202                        if (!vfs_data->files[i]) {
     203                                fibril_mutex_unlock(&vfs_data->lock);
    167204                                return ENOMEM;
    168205                        }
    169206                       
    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);
     207                        memset(vfs_data->files[i], 0, sizeof(vfs_file_t));
     208                        fibril_mutex_initialize(&vfs_data->files[i]->lock);
     209                        vfs_file_addref(vfs_data, vfs_data->files[i]);
     210                        fibril_mutex_unlock(&vfs_data->lock);
    174211                        return (int) i;
    175212                }
     
    187224                }
    188225        }
    189         fibril_mutex_unlock(&VFS_DATA->lock);
     226        fibril_mutex_unlock(&vfs_data->lock);
    190227       
    191228        return EMFILE;
     229}
     230
     231/** Allocate a file descriptor.
     232 *
     233 * @param desc If true, look for an available file descriptor
     234 *             in a descending order.
     235 *
     236 * @return First available file descriptor or a negative error
     237 *         code.
     238 */
     239int vfs_fd_alloc(bool desc)
     240{
     241        return _vfs_fd_alloc(VFS_DATA, desc);
     242}
     243
     244static int _vfs_fd_free(vfs_client_data_t *vfs_data, int fd)
     245{
     246        int rc;
     247
     248        if (!vfs_files_init(vfs_data))
     249                return ENOMEM;
     250
     251        fibril_mutex_lock(&vfs_data->lock);     
     252        if ((fd < 0) || (fd >= MAX_OPEN_FILES) || !vfs_data->files[fd]) {
     253                fibril_mutex_unlock(&vfs_data->lock);
     254                return EBADF;
     255        }
     256       
     257        rc = vfs_file_delref(vfs_data, vfs_data->files[fd]);
     258        vfs_data->files[fd] = NULL;
     259        fibril_mutex_unlock(&vfs_data->lock);
     260       
     261        return rc;
    192262}
    193263
     
    201271int vfs_fd_free(int fd)
    202272{
    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;
     273        return _vfs_fd_free(VFS_DATA, fd);
    217274}
    218275
     
    228285int vfs_fd_assign(vfs_file_t *file, int fd)
    229286{
    230         if (!vfs_files_init())
     287        if (!vfs_files_init(VFS_DATA))
    231288                return ENOMEM;
    232289
     
    238295       
    239296        FILES[fd] = file;
    240         vfs_file_addref(FILES[fd]);
     297        vfs_file_addref(VFS_DATA, FILES[fd]);
    241298        fibril_mutex_unlock(&VFS_DATA->lock);
    242299       
     
    244301}
    245302
     303static vfs_file_t *_vfs_file_get(vfs_client_data_t *vfs_data, int fd)
     304{
     305        if (!vfs_files_init(vfs_data))
     306                return NULL;
     307       
     308        fibril_mutex_lock(&vfs_data->lock);
     309        if ((fd >= 0) && (fd < MAX_OPEN_FILES)) {
     310                vfs_file_t *file = vfs_data->files[fd];
     311                if (file != NULL) {
     312                        vfs_file_addref(vfs_data, file);
     313                        fibril_mutex_unlock(&vfs_data->lock);
     314                        return file;
     315                }
     316        }
     317        fibril_mutex_unlock(&vfs_data->lock);
     318       
     319        return NULL;
     320}
     321
    246322/** Find VFS file structure for a given file descriptor.
    247323 *
     
    252328vfs_file_t *vfs_file_get(int fd)
    253329{
    254         if (!vfs_files_init())
    255                 return NULL;
    256        
    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);
    265        
    266         return NULL;
     330        return _vfs_file_get(VFS_DATA, fd);
     331}
     332
     333static void _vfs_file_put(vfs_client_data_t *vfs_data, vfs_file_t *file)
     334{
     335        fibril_mutex_lock(&vfs_data->lock);
     336        vfs_file_delref(vfs_data, file);
     337        fibril_mutex_unlock(&vfs_data->lock);
    267338}
    268339
     
    273344void vfs_file_put(vfs_file_t *file)
    274345{
    275         fibril_mutex_lock(&VFS_DATA->lock);
    276         vfs_file_delref(file);
    277         fibril_mutex_unlock(&VFS_DATA->lock);
     346        _vfs_file_put(VFS_DATA, file);
     347}
     348
     349void vfs_pass_handle(task_id_t donor_id, task_id_t acceptor_id, int donor_fd)
     350{
     351        vfs_client_data_t *donor_data = NULL;
     352        vfs_client_data_t *acceptor_data = NULL;
     353        vfs_file_t *donor_file = NULL;
     354        vfs_file_t *acceptor_file = NULL;
     355        vfs_boxed_handle_t *bh;
     356        int acceptor_fd;
     357
     358        acceptor_data = async_get_client_data_by_id(acceptor_id);
     359        if (!acceptor_data)
     360                return;
     361
     362        bh = malloc(sizeof(vfs_boxed_handle_t));
     363        assert(bh);
     364
     365        link_initialize(&bh->link);
     366        bh->handle = -1;
     367
     368        donor_data = async_get_client_data_by_id(donor_id);
     369        if (!donor_data)
     370                goto out;
     371
     372        donor_file = _vfs_file_get(donor_data, donor_fd);
     373        if (!donor_file)
     374                goto out;
     375
     376        acceptor_fd = _vfs_fd_alloc(acceptor_data, false);
     377        if (acceptor_fd < 0)
     378                goto out;
     379
     380        bh->handle = acceptor_fd;
     381
     382        /*
     383         * Add a new reference to the underlying VFS node.
     384         */
     385        vfs_node_addref(donor_file->node);
     386        (void) vfs_open_node_remote(donor_file->node);
     387
     388        acceptor_file = _vfs_file_get(acceptor_data, acceptor_fd);
     389        assert(acceptor_file);
     390
     391        /*
     392         * Inherit attributes from the donor.
     393         */
     394        acceptor_file->node = donor_file->node;
     395        acceptor_file->append = donor_file->append;
     396        acceptor_file->pos = donor_file->pos;
     397
     398out:
     399        fibril_mutex_lock(&acceptor_data->lock);
     400        list_append(&bh->link, &acceptor_data->passed_handles);
     401        fibril_condvar_broadcast(&acceptor_data->cv);
     402        fibril_mutex_unlock(&acceptor_data->lock);
     403
     404        if (donor_data)
     405                async_put_client_data_by_id(donor_id);
     406        if (acceptor_data)
     407                async_put_client_data_by_id(acceptor_id);
     408        if (donor_file)
     409                _vfs_file_put(donor_data, donor_file);
     410        if (acceptor_file)
     411                _vfs_file_put(acceptor_data, acceptor_file);
     412
     413}
     414
     415int vfs_wait_handle_internal(void)
     416{
     417        vfs_client_data_t *vfs_data = VFS_DATA;
     418        int fd;
     419       
     420        fibril_mutex_lock(&vfs_data->lock);
     421        while (list_empty(&vfs_data->passed_handles))
     422                fibril_condvar_wait(&vfs_data->cv, &vfs_data->lock);
     423        link_t *lnk = list_first(&vfs_data->passed_handles);
     424        list_remove(lnk);
     425        fibril_mutex_unlock(&vfs_data->lock);
     426
     427        vfs_boxed_handle_t *bh = list_get_instance(lnk, vfs_boxed_handle_t, link);
     428        fd = bh->handle;
     429        free(bh);
     430
     431        return fd;
    278432}
    279433
Note: See TracChangeset for help on using the changeset viewer.