source: mainline/uspace/srv/vfs/vfs_file.c@ 35e81e2

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

Merge from lp:~zarevucky-jiri/helenos/vfs-2.5/ revision 1946

Original commit messages:

1946: Jiri Zarevucky 2013-08-06 Relativize mount, add root handle to libc and remove root from VFS server. This wraps up the "relativization" phase.

Breakage:

  • Dynamic builds broken
  • Mount table lookups by name
  • Property mode set to 100644
File size: 10.4 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>
[3e6a98c5]42#include <stdbool.h>
[26360f7]43#include <fibril.h>
[1e4cada]44#include <fibril_synch.h>
[27b76ca]45#include <adt/list.h>
[e2ab36f1]46#include <task.h>
[320c884]47#include "vfs.h"
48
[79ae36dd]49#define VFS_DATA ((vfs_client_data_t *) async_get_client_data())
[b75e929]50#define FILES (VFS_DATA->files)
51
52typedef struct {
53 fibril_mutex_t lock;
[27b76ca]54 fibril_condvar_t cv;
55 list_t passed_handles;
[b75e929]56 vfs_file_t **files;
57} vfs_client_data_t;
[320c884]58
[27b76ca]59typedef struct {
60 link_t link;
[bb9ec2d]61 vfs_node_t *node;
62 int permissions;
[27b76ca]63} vfs_boxed_handle_t;
64
[2bc13887]65static int _vfs_fd_free(vfs_client_data_t *, int);
66
[320c884]67/** Initialize the table of open files. */
[2bc13887]68static bool vfs_files_init(vfs_client_data_t *vfs_data)
[320c884]69{
[2bc13887]70 fibril_mutex_lock(&vfs_data->lock);
71 if (!vfs_data->files) {
72 vfs_data->files = malloc(MAX_OPEN_FILES * sizeof(vfs_file_t *));
73 if (!vfs_data->files) {
74 fibril_mutex_unlock(&vfs_data->lock);
[320c884]75 return false;
[b75e929]76 }
[2bc13887]77 memset(vfs_data->files, 0, MAX_OPEN_FILES * sizeof(vfs_file_t *));
[320c884]78 }
[2bc13887]79 fibril_mutex_unlock(&vfs_data->lock);
[320c884]80 return true;
81}
82
[f29a3a2]83/** Cleanup the table of open files. */
[2bc13887]84static void vfs_files_done(vfs_client_data_t *vfs_data)
[f29a3a2]85{
86 int i;
87
[2bc13887]88 if (!vfs_data->files)
[f29a3a2]89 return;
90
91 for (i = 0; i < MAX_OPEN_FILES; i++) {
[2bc13887]92 if (vfs_data->files[i])
93 (void) _vfs_fd_free(vfs_data, i);
[f29a3a2]94 }
95
[2bc13887]96 free(vfs_data->files);
[27b76ca]97
98 while (!list_empty(&vfs_data->passed_handles)) {
99 link_t *lnk;
100 vfs_boxed_handle_t *bh;
101
102 lnk = list_first(&vfs_data->passed_handles);
103 list_remove(lnk);
104
105 bh = list_get_instance(lnk, vfs_boxed_handle_t, link);
106 free(bh);
107 }
[b75e929]108}
109
110void *vfs_client_data_create(void)
111{
112 vfs_client_data_t *vfs_data;
113
114 vfs_data = malloc(sizeof(vfs_client_data_t));
115 if (vfs_data) {
116 fibril_mutex_initialize(&vfs_data->lock);
[27b76ca]117 fibril_condvar_initialize(&vfs_data->cv);
118 list_initialize(&vfs_data->passed_handles);
[b75e929]119 vfs_data->files = NULL;
120 }
121
122 return vfs_data;
123}
124
125void vfs_client_data_destroy(void *data)
126{
127 vfs_client_data_t *vfs_data = (vfs_client_data_t *) data;
128
[2bc13887]129 vfs_files_done(vfs_data);
[b75e929]130 free(vfs_data);
131}
132
[25bef0ff]133/** Close the file in the endpoint FS server. */
134static int vfs_file_close_remote(vfs_file_t *file)
135{
136 assert(!file->refcnt);
[79ae36dd]137
138 async_exch_t *exch = vfs_exchange_grab(file->node->fs_handle);
139
140 ipc_call_t answer;
[15f3c3f]141 aid_t msg = async_send_2(exch, VFS_OUT_CLOSE, file->node->service_id,
[25bef0ff]142 file->node->index, &answer);
[79ae36dd]143
144 vfs_exchange_release(exch);
145
146 sysarg_t rc;
[25bef0ff]147 async_wait_for(msg, &rc);
[79ae36dd]148
[25bef0ff]149 return IPC_GET_ARG1(answer);
150}
151
[b75e929]152/** Increment reference count of VFS file structure.
153 *
154 * @param file File structure that will have reference count
155 * incremented.
156 */
[2bc13887]157static void vfs_file_addref(vfs_client_data_t *vfs_data, vfs_file_t *file)
[b75e929]158{
[2bc13887]159 assert(fibril_mutex_is_locked(&vfs_data->lock));
[b75e929]160
161 file->refcnt++;
162}
163
164/** Decrement reference count of VFS file structure.
165 *
166 * @param file File structure that will have reference count
167 * decremented.
168 */
[2bc13887]169static int vfs_file_delref(vfs_client_data_t *vfs_data, vfs_file_t *file)
[b75e929]170{
[25bef0ff]171 int rc = EOK;
172
[2bc13887]173 assert(fibril_mutex_is_locked(&vfs_data->lock));
[b75e929]174
175 if (file->refcnt-- == 1) {
176 /*
[25bef0ff]177 * Lost the last reference to a file, need to close it in the
178 * endpoint FS and drop our reference to the underlying VFS node.
[b75e929]179 */
[5126f80]180
181 if (file->node != NULL) {
182 if (file->open_read || file->open_write) {
183 rc = vfs_file_close_remote(file);
184 }
185 vfs_node_delref(file->node);
186 }
[b75e929]187 free(file);
188 }
[25bef0ff]189
190 return rc;
[f29a3a2]191}
192
[c577a9a]193static int _vfs_fd_alloc(vfs_client_data_t *vfs_data, vfs_file_t **file, bool desc)
[320c884]194{
[2bc13887]195 if (!vfs_files_init(vfs_data))
[ac23b9d3]196 return ENOMEM;
197
198 unsigned int i;
[2b88074b]199 if (desc)
[42fa698]200 i = MAX_OPEN_FILES - 1;
[2b88074b]201 else
202 i = 0;
203
[2bc13887]204 fibril_mutex_lock(&vfs_data->lock);
[2b88074b]205 while (true) {
[2bc13887]206 if (!vfs_data->files[i]) {
207 vfs_data->files[i] = (vfs_file_t *) malloc(sizeof(vfs_file_t));
208 if (!vfs_data->files[i]) {
209 fibril_mutex_unlock(&vfs_data->lock);
[320c884]210 return ENOMEM;
[b75e929]211 }
[ac23b9d3]212
[c577a9a]213
[2bc13887]214 memset(vfs_data->files[i], 0, sizeof(vfs_file_t));
[c577a9a]215
216 fibril_mutex_initialize(&vfs_data->files[i]->_lock);
217 fibril_mutex_lock(&vfs_data->files[i]->_lock);
[2bc13887]218 vfs_file_addref(vfs_data, vfs_data->files[i]);
[c577a9a]219
220 *file = vfs_data->files[i];
221 vfs_file_addref(vfs_data, *file);
222
[2bc13887]223 fibril_mutex_unlock(&vfs_data->lock);
[ac23b9d3]224 return (int) i;
[320c884]225 }
[2b88074b]226
227 if (desc) {
228 if (i == 0)
229 break;
230
231 i--;
232 } else {
[d8f92868]233 if (i == MAX_OPEN_FILES - 1)
[2b88074b]234 break;
235
236 i++;
237 }
[320c884]238 }
[2bc13887]239 fibril_mutex_unlock(&vfs_data->lock);
[ac23b9d3]240
[320c884]241 return EMFILE;
242}
243
[2bc13887]244/** Allocate a file descriptor.
[320c884]245 *
[c577a9a]246 * @param file Is set to point to the newly created file structure. Must be put afterwards.
[2bc13887]247 * @param desc If true, look for an available file descriptor
248 * in a descending order.
[b7f9087]249 *
[2bc13887]250 * @return First available file descriptor or a negative error
251 * code.
[320c884]252 */
[c577a9a]253int vfs_fd_alloc(vfs_file_t **file, bool desc)
[2bc13887]254{
[c577a9a]255 return _vfs_fd_alloc(VFS_DATA, file, desc);
[2bc13887]256}
257
258static int _vfs_fd_free(vfs_client_data_t *vfs_data, int fd)
[320c884]259{
[25bef0ff]260 int rc;
261
[2bc13887]262 if (!vfs_files_init(vfs_data))
[ac23b9d3]263 return ENOMEM;
[b75e929]264
[2bc13887]265 fibril_mutex_lock(&vfs_data->lock);
266 if ((fd < 0) || (fd >= MAX_OPEN_FILES) || !vfs_data->files[fd]) {
267 fibril_mutex_unlock(&vfs_data->lock);
[b7f9087]268 return EBADF;
[b75e929]269 }
[ac23b9d3]270
[2bc13887]271 rc = vfs_file_delref(vfs_data, vfs_data->files[fd]);
272 vfs_data->files[fd] = NULL;
273 fibril_mutex_unlock(&vfs_data->lock);
[ac23b9d3]274
[25bef0ff]275 return rc;
[320c884]276}
277
[2bc13887]278/** Release file descriptor.
279 *
280 * @param fd File descriptor being released.
281 *
282 * @return EOK on success or EBADF if fd is an invalid file
283 * descriptor.
284 */
285int vfs_fd_free(int fd)
286{
287 return _vfs_fd_free(VFS_DATA, fd);
288}
289
[2b88074b]290/** Assign a file to a file descriptor.
291 *
292 * @param file File to assign.
293 * @param fd File descriptor to assign to.
294 *
295 * @return EOK on success or EINVAL if fd is an invalid or already
296 * used file descriptor.
297 *
298 */
299int vfs_fd_assign(vfs_file_t *file, int fd)
300{
[2bc13887]301 if (!vfs_files_init(VFS_DATA))
[2b88074b]302 return ENOMEM;
[b75e929]303
304 fibril_mutex_lock(&VFS_DATA->lock);
305 if ((fd < 0) || (fd >= MAX_OPEN_FILES) || (FILES[fd] != NULL)) {
306 fibril_mutex_unlock(&VFS_DATA->lock);
[2b88074b]307 return EINVAL;
[b75e929]308 }
[2b88074b]309
[b75e929]310 FILES[fd] = file;
[2bc13887]311 vfs_file_addref(VFS_DATA, FILES[fd]);
[b75e929]312 fibril_mutex_unlock(&VFS_DATA->lock);
[2b88074b]313
314 return EOK;
315}
316
[5126f80]317static void _vfs_file_put(vfs_client_data_t *vfs_data, vfs_file_t *file)
318{
319 fibril_mutex_unlock(&file->_lock);
320
321 fibril_mutex_lock(&vfs_data->lock);
322 vfs_file_delref(vfs_data, file);
323 fibril_mutex_unlock(&vfs_data->lock);
324}
325
[2bc13887]326static vfs_file_t *_vfs_file_get(vfs_client_data_t *vfs_data, int fd)
[320c884]327{
[2bc13887]328 if (!vfs_files_init(vfs_data))
[ac23b9d3]329 return NULL;
330
[2bc13887]331 fibril_mutex_lock(&vfs_data->lock);
[b75e929]332 if ((fd >= 0) && (fd < MAX_OPEN_FILES)) {
[2bc13887]333 vfs_file_t *file = vfs_data->files[fd];
[6639ae1]334 if (file != NULL) {
[2bc13887]335 vfs_file_addref(vfs_data, file);
336 fibril_mutex_unlock(&vfs_data->lock);
[5126f80]337
[c577a9a]338 fibril_mutex_lock(&file->_lock);
[5126f80]339 if (file->node == NULL) {
340 _vfs_file_put(vfs_data, file);
341 return NULL;
342 }
343 assert(file != NULL);
344 assert(file->node != NULL);
[6639ae1]345 return file;
346 }
[b75e929]347 }
[2bc13887]348 fibril_mutex_unlock(&vfs_data->lock);
[ac23b9d3]349
[ebd9392]350 return NULL;
[320c884]351}
352
[2bc13887]353/** Find VFS file structure for a given file descriptor.
354 *
355 * @param fd File descriptor.
356 *
357 * @return VFS file structure corresponding to fd.
358 */
359vfs_file_t *vfs_file_get(int fd)
360{
361 return _vfs_file_get(VFS_DATA, fd);
362}
363
[4fe94c66]364/** Stop using a file structure.
365 *
366 * @param file VFS file structure.
367 */
368void vfs_file_put(vfs_file_t *file)
369{
[2bc13887]370 _vfs_file_put(VFS_DATA, file);
371}
372
[354b642]373void vfs_op_pass_handle(task_id_t donor_id, task_id_t acceptor_id, int donor_fd)
[2bc13887]374{
375 vfs_client_data_t *donor_data = NULL;
376 vfs_client_data_t *acceptor_data = NULL;
377 vfs_file_t *donor_file = NULL;
[27b76ca]378 vfs_boxed_handle_t *bh;
[2bc13887]379
[e2ab36f1]380 acceptor_data = async_get_client_data_by_id(acceptor_id);
[2bc13887]381 if (!acceptor_data)
[27b76ca]382 return;
383
384 bh = malloc(sizeof(vfs_boxed_handle_t));
385 assert(bh);
386
387 link_initialize(&bh->link);
[bb9ec2d]388 bh->node = NULL;
[27b76ca]389
[e2ab36f1]390 donor_data = async_get_client_data_by_id(donor_id);
[27b76ca]391 if (!donor_data)
[2bc13887]392 goto out;
393
394 donor_file = _vfs_file_get(donor_data, donor_fd);
395 if (!donor_file)
396 goto out;
397
398 /*
399 * Add a new reference to the underlying VFS node.
400 */
401 vfs_node_addref(donor_file->node);
[bb9ec2d]402 bh->node = donor_file->node;
403 bh->permissions = donor_file->permissions;
[354b642]404
[2bc13887]405out:
[27b76ca]406 fibril_mutex_lock(&acceptor_data->lock);
407 list_append(&bh->link, &acceptor_data->passed_handles);
408 fibril_condvar_broadcast(&acceptor_data->cv);
409 fibril_mutex_unlock(&acceptor_data->lock);
410
[2bc13887]411 if (donor_data)
[e2ab36f1]412 async_put_client_data_by_id(donor_id);
[2bc13887]413 if (acceptor_data)
[e2ab36f1]414 async_put_client_data_by_id(acceptor_id);
[2bc13887]415 if (donor_file)
416 _vfs_file_put(donor_data, donor_file);
[27b76ca]417}
418
[bb9ec2d]419int vfs_wait_handle_internal(bool high_fd)
[27b76ca]420{
421 vfs_client_data_t *vfs_data = VFS_DATA;
422
423 fibril_mutex_lock(&vfs_data->lock);
424 while (list_empty(&vfs_data->passed_handles))
425 fibril_condvar_wait(&vfs_data->cv, &vfs_data->lock);
426 link_t *lnk = list_first(&vfs_data->passed_handles);
427 list_remove(lnk);
428 fibril_mutex_unlock(&vfs_data->lock);
429
430 vfs_boxed_handle_t *bh = list_get_instance(lnk, vfs_boxed_handle_t, link);
431
[bb9ec2d]432 vfs_file_t *file;
433 int fd = _vfs_fd_alloc(vfs_data, &file, high_fd);
434 if (fd < 0) {
435 vfs_node_delref(bh->node);
436 free(bh);
437 return fd;
438 }
439
440 file->node = bh->node;
441 file->permissions = bh->permissions;
442 vfs_file_put(file);
443 free(bh);
[27b76ca]444 return fd;
[4fe94c66]445}
446
[320c884]447/**
448 * @}
[ac23b9d3]449 */
Note: See TracBrowser for help on using the repository browser.