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

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

Add vfs_pass_handle().

  • Property mode set to 100644
File size: 8.8 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 <bool.h>
43#include <fibril.h>
44#include <fibril_synch.h>
45#include "vfs.h"
46
47#define VFS_DATA ((vfs_client_data_t *) async_get_client_data())
48#define FILES (VFS_DATA->files)
49
50typedef struct {
51 fibril_mutex_t lock;
52 vfs_file_t **files;
53} vfs_client_data_t;
54
55static int _vfs_fd_free(vfs_client_data_t *, int);
56
57/** Initialize the table of open files. */
58static bool vfs_files_init(vfs_client_data_t *vfs_data)
59{
60 fibril_mutex_lock(&vfs_data->lock);
61 if (!vfs_data->files) {
62 vfs_data->files = malloc(MAX_OPEN_FILES * sizeof(vfs_file_t *));
63 if (!vfs_data->files) {
64 fibril_mutex_unlock(&vfs_data->lock);
65 return false;
66 }
67 memset(vfs_data->files, 0, MAX_OPEN_FILES * sizeof(vfs_file_t *));
68 }
69 fibril_mutex_unlock(&vfs_data->lock);
70 return true;
71}
72
73/** Cleanup the table of open files. */
74static void vfs_files_done(vfs_client_data_t *vfs_data)
75{
76 int i;
77
78 if (!vfs_data->files)
79 return;
80
81 for (i = 0; i < MAX_OPEN_FILES; i++) {
82 if (vfs_data->files[i])
83 (void) _vfs_fd_free(vfs_data, i);
84 }
85
86 free(vfs_data->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(vfs_data);
107 free(vfs_data);
108}
109
110/** Close the file in the endpoint FS server. */
111static int vfs_file_close_remote(vfs_file_t *file)
112{
113 assert(!file->refcnt);
114
115 async_exch_t *exch = vfs_exchange_grab(file->node->fs_handle);
116
117 ipc_call_t answer;
118 aid_t msg = async_send_2(exch, VFS_OUT_CLOSE, file->node->devmap_handle,
119 file->node->index, &answer);
120
121 vfs_exchange_release(exch);
122
123 sysarg_t rc;
124 async_wait_for(msg, &rc);
125
126 return IPC_GET_ARG1(answer);
127}
128
129/** Increment reference count of VFS file structure.
130 *
131 * @param file File structure that will have reference count
132 * incremented.
133 */
134static void vfs_file_addref(vfs_client_data_t *vfs_data, vfs_file_t *file)
135{
136 assert(fibril_mutex_is_locked(&vfs_data->lock));
137
138 file->refcnt++;
139}
140
141/** Decrement reference count of VFS file structure.
142 *
143 * @param file File structure that will have reference count
144 * decremented.
145 */
146static int vfs_file_delref(vfs_client_data_t *vfs_data, vfs_file_t *file)
147{
148 int rc = EOK;
149
150 assert(fibril_mutex_is_locked(&vfs_data->lock));
151
152 if (file->refcnt-- == 1) {
153 /*
154 * Lost the last reference to a file, need to close it in the
155 * endpoint FS and drop our reference to the underlying VFS node.
156 */
157 rc = vfs_file_close_remote(file);
158 vfs_node_delref(file->node);
159 free(file);
160 }
161
162 return rc;
163}
164
165static int _vfs_fd_alloc(vfs_client_data_t *vfs_data, bool desc)
166{
167 if (!vfs_files_init(vfs_data))
168 return ENOMEM;
169
170 unsigned int i;
171 if (desc)
172 i = MAX_OPEN_FILES - 1;
173 else
174 i = 0;
175
176 fibril_mutex_lock(&vfs_data->lock);
177 while (true) {
178 if (!vfs_data->files[i]) {
179 vfs_data->files[i] = (vfs_file_t *) malloc(sizeof(vfs_file_t));
180 if (!vfs_data->files[i]) {
181 fibril_mutex_unlock(&vfs_data->lock);
182 return ENOMEM;
183 }
184
185 memset(vfs_data->files[i], 0, sizeof(vfs_file_t));
186 fibril_mutex_initialize(&vfs_data->files[i]->lock);
187 vfs_file_addref(vfs_data, vfs_data->files[i]);
188 fibril_mutex_unlock(&vfs_data->lock);
189 return (int) i;
190 }
191
192 if (desc) {
193 if (i == 0)
194 break;
195
196 i--;
197 } else {
198 if (i == MAX_OPEN_FILES - 1)
199 break;
200
201 i++;
202 }
203 }
204 fibril_mutex_unlock(&vfs_data->lock);
205
206 return EMFILE;
207}
208
209/** Allocate a file descriptor.
210 *
211 * @param desc If true, look for an available file descriptor
212 * in a descending order.
213 *
214 * @return First available file descriptor or a negative error
215 * code.
216 */
217int vfs_fd_alloc(bool desc)
218{
219 return _vfs_fd_alloc(VFS_DATA, desc);
220}
221
222static int _vfs_fd_free(vfs_client_data_t *vfs_data, int fd)
223{
224 int rc;
225
226 if (!vfs_files_init(vfs_data))
227 return ENOMEM;
228
229 fibril_mutex_lock(&vfs_data->lock);
230 if ((fd < 0) || (fd >= MAX_OPEN_FILES) || !vfs_data->files[fd]) {
231 fibril_mutex_unlock(&vfs_data->lock);
232 return EBADF;
233 }
234
235 rc = vfs_file_delref(vfs_data, vfs_data->files[fd]);
236 vfs_data->files[fd] = NULL;
237 fibril_mutex_unlock(&vfs_data->lock);
238
239 return rc;
240}
241
242/** Release file descriptor.
243 *
244 * @param fd File descriptor being released.
245 *
246 * @return EOK on success or EBADF if fd is an invalid file
247 * descriptor.
248 */
249int vfs_fd_free(int fd)
250{
251 return _vfs_fd_free(VFS_DATA, fd);
252}
253
254/** Assign a file to a file descriptor.
255 *
256 * @param file File to assign.
257 * @param fd File descriptor to assign to.
258 *
259 * @return EOK on success or EINVAL if fd is an invalid or already
260 * used file descriptor.
261 *
262 */
263int vfs_fd_assign(vfs_file_t *file, int fd)
264{
265 if (!vfs_files_init(VFS_DATA))
266 return ENOMEM;
267
268 fibril_mutex_lock(&VFS_DATA->lock);
269 if ((fd < 0) || (fd >= MAX_OPEN_FILES) || (FILES[fd] != NULL)) {
270 fibril_mutex_unlock(&VFS_DATA->lock);
271 return EINVAL;
272 }
273
274 FILES[fd] = file;
275 vfs_file_addref(VFS_DATA, FILES[fd]);
276 fibril_mutex_unlock(&VFS_DATA->lock);
277
278 return EOK;
279}
280
281static vfs_file_t *_vfs_file_get(vfs_client_data_t *vfs_data, int fd)
282{
283 if (!vfs_files_init(vfs_data))
284 return NULL;
285
286 fibril_mutex_lock(&vfs_data->lock);
287 if ((fd >= 0) && (fd < MAX_OPEN_FILES)) {
288 vfs_file_t *file = vfs_data->files[fd];
289 if (file != NULL) {
290 vfs_file_addref(vfs_data, file);
291 fibril_mutex_unlock(&vfs_data->lock);
292 return file;
293 }
294 }
295 fibril_mutex_unlock(&vfs_data->lock);
296
297 return NULL;
298}
299
300/** Find VFS file structure for a given file descriptor.
301 *
302 * @param fd File descriptor.
303 *
304 * @return VFS file structure corresponding to fd.
305 */
306vfs_file_t *vfs_file_get(int fd)
307{
308 return _vfs_file_get(VFS_DATA, fd);
309}
310
311static void _vfs_file_put(vfs_client_data_t *vfs_data, vfs_file_t *file)
312{
313 fibril_mutex_lock(&vfs_data->lock);
314 vfs_file_delref(vfs_data, file);
315 fibril_mutex_unlock(&vfs_data->lock);
316}
317
318/** Stop using a file structure.
319 *
320 * @param file VFS file structure.
321 */
322void vfs_file_put(vfs_file_t *file)
323{
324 _vfs_file_put(VFS_DATA, file);
325}
326
327void vfs_pass_handle(sysarg_t donor_hash, sysarg_t acceptor_hash, int donor_fd)
328{
329 vfs_client_data_t *donor_data = NULL;
330 vfs_client_data_t *acceptor_data = NULL;
331 vfs_file_t *donor_file = NULL;
332 vfs_file_t *acceptor_file = NULL;
333 int acceptor_fd;
334
335 donor_data = async_get_client_data_by_hash(donor_hash);
336 if (!donor_data)
337 return;
338 acceptor_data = async_get_client_data_by_hash(acceptor_hash);
339 if (!acceptor_data)
340 goto out;
341
342 donor_file = _vfs_file_get(donor_data, donor_fd);
343 if (!donor_file)
344 goto out;
345
346 acceptor_fd = _vfs_fd_alloc(acceptor_data, false);
347 if (acceptor_fd < 0)
348 goto out;
349
350 /*
351 * Add a new reference to the underlying VFS node.
352 */
353 vfs_node_addref(donor_file->node);
354
355 acceptor_file = _vfs_file_get(acceptor_data, acceptor_fd);
356 assert(acceptor_file);
357
358 /*
359 * Inherit attributes from the donor.
360 */
361 acceptor_file->node = donor_file->node;
362 acceptor_file->append = donor_file->append;
363 acceptor_file->pos = donor_file->pos;
364
365out:
366 if (donor_data)
367 async_put_client_data_by_hash(donor_hash);
368 if (acceptor_data)
369 async_put_client_data_by_hash(acceptor_hash);
370 if (donor_file)
371 _vfs_file_put(donor_data, donor_file);
372 if (acceptor_file)
373 _vfs_file_put(acceptor_data, acceptor_file);
374}
375
376/**
377 * @}
378 */
Note: See TracBrowser for help on using the repository browser.