source: mainline/uspace/srv/vfs/vfs_file.c@ 86ffa27f

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 86ffa27f was 15f3c3f, checked in by Jiri Svoboda <jiri@…>, 14 years ago

Rename devmap to loc, devfs to locfs.

  • Property mode set to 100644
File size: 6.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
55/** Initialize the table of open files. */
56static 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);
63 return false;
64 }
65 memset(FILES, 0, MAX_OPEN_FILES * sizeof(vfs_file_t *));
66 }
67 fibril_mutex_unlock(&VFS_DATA->lock);
68 return true;
69}
70
71/** Cleanup the table of open files. */
72static void vfs_files_done(void)
73{
74 int i;
75
76 if (!FILES)
77 return;
78
79 for (i = 0; i < MAX_OPEN_FILES; i++) {
80 if (FILES[i]) {
81 (void) vfs_fd_free(i);
82 }
83 }
84
85 free(FILES);
86}
87
88void *vfs_client_data_create(void)
89{
90 vfs_client_data_t *vfs_data;
91
92 vfs_data = malloc(sizeof(vfs_client_data_t));
93 if (vfs_data) {
94 fibril_mutex_initialize(&vfs_data->lock);
95 vfs_data->files = NULL;
96 }
97
98 return vfs_data;
99}
100
101void vfs_client_data_destroy(void *data)
102{
103 vfs_client_data_t *vfs_data = (vfs_client_data_t *) data;
104
105 vfs_files_done();
106 free(vfs_data);
107}
108
109/** Close the file in the endpoint FS server. */
110static int vfs_file_close_remote(vfs_file_t *file)
111{
112 assert(!file->refcnt);
113
114 async_exch_t *exch = vfs_exchange_grab(file->node->fs_handle);
115
116 ipc_call_t answer;
117 aid_t msg = async_send_2(exch, VFS_OUT_CLOSE, file->node->service_id,
118 file->node->index, &answer);
119
120 vfs_exchange_release(exch);
121
122 sysarg_t rc;
123 async_wait_for(msg, &rc);
124
125 return IPC_GET_ARG1(answer);
126}
127
128/** Increment reference count of VFS file structure.
129 *
130 * @param file File structure that will have reference count
131 * incremented.
132 */
133static void vfs_file_addref(vfs_file_t *file)
134{
135 assert(fibril_mutex_is_locked(&VFS_DATA->lock));
136
137 file->refcnt++;
138}
139
140/** Decrement reference count of VFS file structure.
141 *
142 * @param file File structure that will have reference count
143 * decremented.
144 */
145static int vfs_file_delref(vfs_file_t *file)
146{
147 int rc = EOK;
148
149 assert(fibril_mutex_is_locked(&VFS_DATA->lock));
150
151 if (file->refcnt-- == 1) {
152 /*
153 * Lost the last reference to a file, need to close it in the
154 * endpoint FS and drop our reference to the underlying VFS node.
155 */
156 rc = vfs_file_close_remote(file);
157 vfs_node_delref(file->node);
158 free(file);
159 }
160
161 return rc;
162}
163
164
165/** Allocate a file descriptor.
166 *
167 * @param desc If true, look for an available file descriptor
168 * in a descending order.
169 *
170 * @return First available file descriptor or a negative error
171 * code.
172 */
173int vfs_fd_alloc(bool desc)
174{
175 if (!vfs_files_init())
176 return ENOMEM;
177
178 unsigned int i;
179 if (desc)
180 i = MAX_OPEN_FILES - 1;
181 else
182 i = 0;
183
184 fibril_mutex_lock(&VFS_DATA->lock);
185 while (true) {
186 if (!FILES[i]) {
187 FILES[i] = (vfs_file_t *) malloc(sizeof(vfs_file_t));
188 if (!FILES[i]) {
189 fibril_mutex_unlock(&VFS_DATA->lock);
190 return ENOMEM;
191 }
192
193 memset(FILES[i], 0, sizeof(vfs_file_t));
194 fibril_mutex_initialize(&FILES[i]->lock);
195 vfs_file_addref(FILES[i]);
196 fibril_mutex_unlock(&VFS_DATA->lock);
197 return (int) i;
198 }
199
200 if (desc) {
201 if (i == 0)
202 break;
203
204 i--;
205 } else {
206 if (i == MAX_OPEN_FILES - 1)
207 break;
208
209 i++;
210 }
211 }
212 fibril_mutex_unlock(&VFS_DATA->lock);
213
214 return EMFILE;
215}
216
217/** Release file descriptor.
218 *
219 * @param fd File descriptor being released.
220 *
221 * @return EOK on success or EBADF if fd is an invalid file
222 * descriptor.
223 */
224int vfs_fd_free(int fd)
225{
226 int rc;
227
228 if (!vfs_files_init())
229 return ENOMEM;
230
231 fibril_mutex_lock(&VFS_DATA->lock);
232 if ((fd < 0) || (fd >= MAX_OPEN_FILES) || (FILES[fd] == NULL)) {
233 fibril_mutex_unlock(&VFS_DATA->lock);
234 return EBADF;
235 }
236
237 rc = vfs_file_delref(FILES[fd]);
238 FILES[fd] = NULL;
239 fibril_mutex_unlock(&VFS_DATA->lock);
240
241 return rc;
242}
243
244/** Assign a file to a file descriptor.
245 *
246 * @param file File to assign.
247 * @param fd File descriptor to assign to.
248 *
249 * @return EOK on success or EINVAL if fd is an invalid or already
250 * used file descriptor.
251 *
252 */
253int vfs_fd_assign(vfs_file_t *file, int fd)
254{
255 if (!vfs_files_init())
256 return ENOMEM;
257
258 fibril_mutex_lock(&VFS_DATA->lock);
259 if ((fd < 0) || (fd >= MAX_OPEN_FILES) || (FILES[fd] != NULL)) {
260 fibril_mutex_unlock(&VFS_DATA->lock);
261 return EINVAL;
262 }
263
264 FILES[fd] = file;
265 vfs_file_addref(FILES[fd]);
266 fibril_mutex_unlock(&VFS_DATA->lock);
267
268 return EOK;
269}
270
271/** Find VFS file structure for a given file descriptor.
272 *
273 * @param fd File descriptor.
274 *
275 * @return VFS file structure corresponding to fd.
276 */
277vfs_file_t *vfs_file_get(int fd)
278{
279 if (!vfs_files_init())
280 return NULL;
281
282 fibril_mutex_lock(&VFS_DATA->lock);
283 if ((fd >= 0) && (fd < MAX_OPEN_FILES)) {
284 vfs_file_t *file = FILES[fd];
285 if (file != NULL) {
286 vfs_file_addref(file);
287 fibril_mutex_unlock(&VFS_DATA->lock);
288 return file;
289 }
290 }
291 fibril_mutex_unlock(&VFS_DATA->lock);
292
293 return NULL;
294}
295
296/** Stop using a file structure.
297 *
298 * @param file VFS file structure.
299 */
300void vfs_file_put(vfs_file_t *file)
301{
302 fibril_mutex_lock(&VFS_DATA->lock);
303 vfs_file_delref(file);
304 fibril_mutex_unlock(&VFS_DATA->lock);
305}
306
307/**
308 * @}
309 */
Note: See TracBrowser for help on using the repository browser.