source: mainline/uspace/srv/vfs/vfs_file.c@ 221ab41a

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 221ab41a was 221ab41a, checked in by Jakub Jermar <jakub@…>, 14 years ago

Need to open remote node in vfs_pass_handle().

  • Property mode set to 100644
File size: 10.1 KB
RevLine 
[320c884]1/*
2 * Copyright (c) 2007 Jakub Jermar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup fs
30 * @{
31 */
32
33/**
34 * @file vfs_file.c
35 * @brief Various operations on files have their home in this file.
36 */
37
38#include <errno.h>
39#include <stdlib.h>
[19f857a]40#include <str.h>
[320c884]41#include <assert.h>
42#include <bool.h>
[26360f7]43#include <fibril.h>
[1e4cada]44#include <fibril_synch.h>
[27b76ca]45#include <adt/list.h>
[320c884]46#include "vfs.h"
47
[79ae36dd]48#define VFS_DATA ((vfs_client_data_t *) async_get_client_data())
[b75e929]49#define FILES (VFS_DATA->files)
50
51typedef struct {
52 fibril_mutex_t lock;
[27b76ca]53 fibril_condvar_t cv;
54 list_t passed_handles;
[b75e929]55 vfs_file_t **files;
56} vfs_client_data_t;
[320c884]57
[27b76ca]58typedef struct {
59 link_t link;
60 int handle;
61} vfs_boxed_handle_t;
62
[2bc13887]63static int _vfs_fd_free(vfs_client_data_t *, int);
64
[320c884]65/** Initialize the table of open files. */
[2bc13887]66static bool vfs_files_init(vfs_client_data_t *vfs_data)
[320c884]67{
[2bc13887]68 fibril_mutex_lock(&vfs_data->lock);
69 if (!vfs_data->files) {
70 vfs_data->files = malloc(MAX_OPEN_FILES * sizeof(vfs_file_t *));
71 if (!vfs_data->files) {
72 fibril_mutex_unlock(&vfs_data->lock);
[320c884]73 return false;
[b75e929]74 }
[2bc13887]75 memset(vfs_data->files, 0, MAX_OPEN_FILES * sizeof(vfs_file_t *));
[320c884]76 }
[2bc13887]77 fibril_mutex_unlock(&vfs_data->lock);
[320c884]78 return true;
79}
80
[f29a3a2]81/** Cleanup the table of open files. */
[2bc13887]82static void vfs_files_done(vfs_client_data_t *vfs_data)
[f29a3a2]83{
84 int i;
85
[2bc13887]86 if (!vfs_data->files)
[f29a3a2]87 return;
88
89 for (i = 0; i < MAX_OPEN_FILES; i++) {
[2bc13887]90 if (vfs_data->files[i])
91 (void) _vfs_fd_free(vfs_data, i);
[f29a3a2]92 }
93
[2bc13887]94 free(vfs_data->files);
[27b76ca]95
96 while (!list_empty(&vfs_data->passed_handles)) {
97 link_t *lnk;
98 vfs_boxed_handle_t *bh;
99
100 lnk = list_first(&vfs_data->passed_handles);
101 list_remove(lnk);
102
103 bh = list_get_instance(lnk, vfs_boxed_handle_t, link);
104 free(bh);
105 }
[b75e929]106}
107
108void *vfs_client_data_create(void)
109{
110 vfs_client_data_t *vfs_data;
111
112 vfs_data = malloc(sizeof(vfs_client_data_t));
113 if (vfs_data) {
114 fibril_mutex_initialize(&vfs_data->lock);
[27b76ca]115 fibril_condvar_initialize(&vfs_data->cv);
116 list_initialize(&vfs_data->passed_handles);
[b75e929]117 vfs_data->files = NULL;
118 }
119
120 return vfs_data;
121}
122
123void vfs_client_data_destroy(void *data)
124{
125 vfs_client_data_t *vfs_data = (vfs_client_data_t *) data;
126
[2bc13887]127 vfs_files_done(vfs_data);
[b75e929]128 free(vfs_data);
129}
130
[25bef0ff]131/** Close the file in the endpoint FS server. */
132static int vfs_file_close_remote(vfs_file_t *file)
133{
134 assert(!file->refcnt);
[79ae36dd]135
136 async_exch_t *exch = vfs_exchange_grab(file->node->fs_handle);
137
138 ipc_call_t answer;
139 aid_t msg = async_send_2(exch, VFS_OUT_CLOSE, file->node->devmap_handle,
[25bef0ff]140 file->node->index, &answer);
[79ae36dd]141
142 vfs_exchange_release(exch);
143
144 sysarg_t rc;
[25bef0ff]145 async_wait_for(msg, &rc);
[79ae36dd]146
[25bef0ff]147 return IPC_GET_ARG1(answer);
148}
149
[b75e929]150/** Increment reference count of VFS file structure.
151 *
152 * @param file File structure that will have reference count
153 * incremented.
154 */
[2bc13887]155static void vfs_file_addref(vfs_client_data_t *vfs_data, vfs_file_t *file)
[b75e929]156{
[2bc13887]157 assert(fibril_mutex_is_locked(&vfs_data->lock));
[b75e929]158
159 file->refcnt++;
160}
161
162/** Decrement reference count of VFS file structure.
163 *
164 * @param file File structure that will have reference count
165 * decremented.
166 */
[2bc13887]167static int vfs_file_delref(vfs_client_data_t *vfs_data, vfs_file_t *file)
[b75e929]168{
[25bef0ff]169 int rc = EOK;
170
[2bc13887]171 assert(fibril_mutex_is_locked(&vfs_data->lock));
[b75e929]172
173 if (file->refcnt-- == 1) {
174 /*
[25bef0ff]175 * Lost the last reference to a file, need to close it in the
176 * endpoint FS and drop our reference to the underlying VFS node.
[b75e929]177 */
[25bef0ff]178 rc = vfs_file_close_remote(file);
[b75e929]179 vfs_node_delref(file->node);
180 free(file);
181 }
[25bef0ff]182
183 return rc;
[f29a3a2]184}
185
[2bc13887]186static int _vfs_fd_alloc(vfs_client_data_t *vfs_data, bool desc)
[320c884]187{
[2bc13887]188 if (!vfs_files_init(vfs_data))
[ac23b9d3]189 return ENOMEM;
190
191 unsigned int i;
[2b88074b]192 if (desc)
[42fa698]193 i = MAX_OPEN_FILES - 1;
[2b88074b]194 else
195 i = 0;
196
[2bc13887]197 fibril_mutex_lock(&vfs_data->lock);
[2b88074b]198 while (true) {
[2bc13887]199 if (!vfs_data->files[i]) {
200 vfs_data->files[i] = (vfs_file_t *) malloc(sizeof(vfs_file_t));
201 if (!vfs_data->files[i]) {
202 fibril_mutex_unlock(&vfs_data->lock);
[320c884]203 return ENOMEM;
[b75e929]204 }
[ac23b9d3]205
[2bc13887]206 memset(vfs_data->files[i], 0, sizeof(vfs_file_t));
207 fibril_mutex_initialize(&vfs_data->files[i]->lock);
208 vfs_file_addref(vfs_data, vfs_data->files[i]);
209 fibril_mutex_unlock(&vfs_data->lock);
[ac23b9d3]210 return (int) i;
[320c884]211 }
[2b88074b]212
213 if (desc) {
214 if (i == 0)
215 break;
216
217 i--;
218 } else {
[d8f92868]219 if (i == MAX_OPEN_FILES - 1)
[2b88074b]220 break;
221
222 i++;
223 }
[320c884]224 }
[2bc13887]225 fibril_mutex_unlock(&vfs_data->lock);
[ac23b9d3]226
[320c884]227 return EMFILE;
228}
229
[2bc13887]230/** Allocate a file descriptor.
[320c884]231 *
[2bc13887]232 * @param desc If true, look for an available file descriptor
233 * in a descending order.
[b7f9087]234 *
[2bc13887]235 * @return First available file descriptor or a negative error
236 * code.
[320c884]237 */
[2bc13887]238int vfs_fd_alloc(bool desc)
239{
240 return _vfs_fd_alloc(VFS_DATA, desc);
241}
242
243static int _vfs_fd_free(vfs_client_data_t *vfs_data, int fd)
[320c884]244{
[25bef0ff]245 int rc;
246
[2bc13887]247 if (!vfs_files_init(vfs_data))
[ac23b9d3]248 return ENOMEM;
[b75e929]249
[2bc13887]250 fibril_mutex_lock(&vfs_data->lock);
251 if ((fd < 0) || (fd >= MAX_OPEN_FILES) || !vfs_data->files[fd]) {
252 fibril_mutex_unlock(&vfs_data->lock);
[b7f9087]253 return EBADF;
[b75e929]254 }
[ac23b9d3]255
[2bc13887]256 rc = vfs_file_delref(vfs_data, vfs_data->files[fd]);
257 vfs_data->files[fd] = NULL;
258 fibril_mutex_unlock(&vfs_data->lock);
[ac23b9d3]259
[25bef0ff]260 return rc;
[320c884]261}
262
[2bc13887]263/** Release file descriptor.
264 *
265 * @param fd File descriptor being released.
266 *
267 * @return EOK on success or EBADF if fd is an invalid file
268 * descriptor.
269 */
270int vfs_fd_free(int fd)
271{
272 return _vfs_fd_free(VFS_DATA, fd);
273}
274
[2b88074b]275/** Assign a file to a file descriptor.
276 *
277 * @param file File to assign.
278 * @param fd File descriptor to assign to.
279 *
280 * @return EOK on success or EINVAL if fd is an invalid or already
281 * used file descriptor.
282 *
283 */
284int vfs_fd_assign(vfs_file_t *file, int fd)
285{
[2bc13887]286 if (!vfs_files_init(VFS_DATA))
[2b88074b]287 return ENOMEM;
[b75e929]288
289 fibril_mutex_lock(&VFS_DATA->lock);
290 if ((fd < 0) || (fd >= MAX_OPEN_FILES) || (FILES[fd] != NULL)) {
291 fibril_mutex_unlock(&VFS_DATA->lock);
[2b88074b]292 return EINVAL;
[b75e929]293 }
[2b88074b]294
[b75e929]295 FILES[fd] = file;
[2bc13887]296 vfs_file_addref(VFS_DATA, FILES[fd]);
[b75e929]297 fibril_mutex_unlock(&VFS_DATA->lock);
[2b88074b]298
299 return EOK;
300}
301
[2bc13887]302static vfs_file_t *_vfs_file_get(vfs_client_data_t *vfs_data, int fd)
[320c884]303{
[2bc13887]304 if (!vfs_files_init(vfs_data))
[ac23b9d3]305 return NULL;
306
[2bc13887]307 fibril_mutex_lock(&vfs_data->lock);
[b75e929]308 if ((fd >= 0) && (fd < MAX_OPEN_FILES)) {
[2bc13887]309 vfs_file_t *file = vfs_data->files[fd];
[6639ae1]310 if (file != NULL) {
[2bc13887]311 vfs_file_addref(vfs_data, file);
312 fibril_mutex_unlock(&vfs_data->lock);
[6639ae1]313 return file;
314 }
[b75e929]315 }
[2bc13887]316 fibril_mutex_unlock(&vfs_data->lock);
[ac23b9d3]317
[ebd9392]318 return NULL;
[320c884]319}
320
[2bc13887]321/** Find VFS file structure for a given file descriptor.
322 *
323 * @param fd File descriptor.
324 *
325 * @return VFS file structure corresponding to fd.
326 */
327vfs_file_t *vfs_file_get(int fd)
328{
329 return _vfs_file_get(VFS_DATA, fd);
330}
331
332static void _vfs_file_put(vfs_client_data_t *vfs_data, vfs_file_t *file)
333{
334 fibril_mutex_lock(&vfs_data->lock);
335 vfs_file_delref(vfs_data, file);
336 fibril_mutex_unlock(&vfs_data->lock);
337}
338
[4fe94c66]339/** Stop using a file structure.
340 *
341 * @param file VFS file structure.
342 */
343void vfs_file_put(vfs_file_t *file)
344{
[2bc13887]345 _vfs_file_put(VFS_DATA, file);
346}
347
348void vfs_pass_handle(sysarg_t donor_hash, sysarg_t acceptor_hash, int donor_fd)
349{
350 vfs_client_data_t *donor_data = NULL;
351 vfs_client_data_t *acceptor_data = NULL;
352 vfs_file_t *donor_file = NULL;
353 vfs_file_t *acceptor_file = NULL;
[27b76ca]354 vfs_boxed_handle_t *bh;
[2bc13887]355 int acceptor_fd;
356
357 acceptor_data = async_get_client_data_by_hash(acceptor_hash);
358 if (!acceptor_data)
[27b76ca]359 return;
360
361 bh = malloc(sizeof(vfs_boxed_handle_t));
362 assert(bh);
363
364 link_initialize(&bh->link);
365 bh->handle = -1;
366
367 donor_data = async_get_client_data_by_hash(donor_hash);
368 if (!donor_data)
[2bc13887]369 goto out;
370
371 donor_file = _vfs_file_get(donor_data, donor_fd);
372 if (!donor_file)
373 goto out;
374
375 acceptor_fd = _vfs_fd_alloc(acceptor_data, false);
376 if (acceptor_fd < 0)
377 goto out;
378
[27b76ca]379 bh->handle = acceptor_fd;
380
[2bc13887]381 /*
382 * Add a new reference to the underlying VFS node.
383 */
384 vfs_node_addref(donor_file->node);
[221ab41a]385 (void) vfs_open_node_remote(donor_file->node);
[2bc13887]386
387 acceptor_file = _vfs_file_get(acceptor_data, acceptor_fd);
388 assert(acceptor_file);
389
390 /*
391 * Inherit attributes from the donor.
392 */
393 acceptor_file->node = donor_file->node;
394 acceptor_file->append = donor_file->append;
395 acceptor_file->pos = donor_file->pos;
396
397out:
[27b76ca]398 fibril_mutex_lock(&acceptor_data->lock);
399 list_append(&bh->link, &acceptor_data->passed_handles);
400 fibril_condvar_broadcast(&acceptor_data->cv);
401 fibril_mutex_unlock(&acceptor_data->lock);
402
[2bc13887]403 if (donor_data)
404 async_put_client_data_by_hash(donor_hash);
405 if (acceptor_data)
406 async_put_client_data_by_hash(acceptor_hash);
407 if (donor_file)
408 _vfs_file_put(donor_data, donor_file);
409 if (acceptor_file)
410 _vfs_file_put(acceptor_data, acceptor_file);
[27b76ca]411
412}
413
414int vfs_wait_handle_internal(void)
415{
416 vfs_client_data_t *vfs_data = VFS_DATA;
417 int fd;
418
419 fibril_mutex_lock(&vfs_data->lock);
420 while (list_empty(&vfs_data->passed_handles))
421 fibril_condvar_wait(&vfs_data->cv, &vfs_data->lock);
422 link_t *lnk = list_first(&vfs_data->passed_handles);
423 list_remove(lnk);
424 fibril_mutex_unlock(&vfs_data->lock);
425
426 vfs_boxed_handle_t *bh = list_get_instance(lnk, vfs_boxed_handle_t, link);
427 fd = bh->handle;
428 free(bh);
429
430 return fd;
[4fe94c66]431}
432
[320c884]433/**
434 * @}
[ac23b9d3]435 */
Note: See TracBrowser for help on using the repository browser.