source: mainline/uspace/srv/vfs/vfs_file.c@ a737667e

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

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

Original commit messages:

1944: Jiri Zarevucky 2013-08-06 Replace legacy file descriptor presetting with inbox.
1943: Jiri Zarevucky 2013-08-06 Do not preserve open state when passing file descriptor to another task. Allow receiver to specify, whether the descriptor is low or high.
1942: Jiri Zarevucky 2013-08-06 C style.
1941: Jiri Zarevucky 2013-08-06 Make loader accept file reference instead of a pathname.

Modifications:

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