source: mainline/uspace/srv/vfs/vfs_file.c@ 4fe94c66

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

Now when the table of open files is shared by multiple connections of
one client task, it became necessary to maintain the vfs_file_t
references obtained from vfs_file_get() explicitly.

  • Property mode set to 100644
File size: 6.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 <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_client_data_get())
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_close_internal(FILES[i]);
82 (void) vfs_fd_free(i);
83 }
84 }
85
86 free(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();
107 free(vfs_data);
108}
109
110/** Increment reference count of VFS file structure.
111 *
112 * @param file File structure that will have reference count
113 * incremented.
114 */
115static void vfs_file_addref(vfs_file_t *file)
116{
117 assert(fibril_mutex_is_locked(&VFS_DATA->lock));
118
119 file->refcnt++;
120}
121
122/** Decrement reference count of VFS file structure.
123 *
124 * @param file File structure that will have reference count
125 * decremented.
126 */
127static void vfs_file_delref(vfs_file_t *file)
128{
129 assert(fibril_mutex_is_locked(&VFS_DATA->lock));
130
131 if (file->refcnt-- == 1) {
132 /*
133 * Lost the last reference to a file, need to drop our reference
134 * to the underlying VFS node.
135 */
136 vfs_node_delref(file->node);
137 free(file);
138 }
139}
140
141
142/** Allocate a file descriptor.
143 *
144 * @param desc If true, look for an available file descriptor
145 * in a descending order.
146 *
147 * @return First available file descriptor or a negative error
148 * code.
149 */
150int vfs_fd_alloc(bool desc)
151{
152 if (!vfs_files_init())
153 return ENOMEM;
154
155 unsigned int i;
156 if (desc)
157 i = MAX_OPEN_FILES - 1;
158 else
159 i = 0;
160
161 fibril_mutex_lock(&VFS_DATA->lock);
162 while (true) {
163 if (!FILES[i]) {
164 FILES[i] = (vfs_file_t *) malloc(sizeof(vfs_file_t));
165 if (!FILES[i]) {
166 fibril_mutex_unlock(&VFS_DATA->lock);
167 return ENOMEM;
168 }
169
170 memset(FILES[i], 0, sizeof(vfs_file_t));
171 fibril_mutex_initialize(&FILES[i]->lock);
172 vfs_file_addref(FILES[i]);
173 fibril_mutex_unlock(&VFS_DATA->lock);
174 return (int) i;
175 }
176
177 if (desc) {
178 if (i == 0)
179 break;
180
181 i--;
182 } else {
183 if (i == MAX_OPEN_FILES - 1)
184 break;
185
186 i++;
187 }
188 }
189 fibril_mutex_unlock(&VFS_DATA->lock);
190
191 return EMFILE;
192}
193
194/** Release file descriptor.
195 *
196 * @param fd File descriptor being released.
197 *
198 * @return EOK on success or EBADF if fd is an invalid file
199 * descriptor.
200 */
201int vfs_fd_free(int fd)
202{
203 if (!vfs_files_init())
204 return ENOMEM;
205
206 fibril_mutex_lock(&VFS_DATA->lock);
207 if ((fd < 0) || (fd >= MAX_OPEN_FILES) || (FILES[fd] == NULL)) {
208 fibril_mutex_unlock(&VFS_DATA->lock);
209 return EBADF;
210 }
211
212 vfs_file_delref(FILES[fd]);
213 FILES[fd] = NULL;
214 fibril_mutex_unlock(&VFS_DATA->lock);
215
216 return EOK;
217}
218
219/** Assign a file to a file descriptor.
220 *
221 * @param file File to assign.
222 * @param fd File descriptor to assign to.
223 *
224 * @return EOK on success or EINVAL if fd is an invalid or already
225 * used file descriptor.
226 *
227 */
228int vfs_fd_assign(vfs_file_t *file, int fd)
229{
230 if (!vfs_files_init())
231 return ENOMEM;
232
233 fibril_mutex_lock(&VFS_DATA->lock);
234 if ((fd < 0) || (fd >= MAX_OPEN_FILES) || (FILES[fd] != NULL)) {
235 fibril_mutex_unlock(&VFS_DATA->lock);
236 return EINVAL;
237 }
238
239 FILES[fd] = file;
240 vfs_file_addref(FILES[fd]);
241 fibril_mutex_unlock(&VFS_DATA->lock);
242
243 return EOK;
244}
245
246/** Find VFS file structure for a given file descriptor.
247 *
248 * @param fd File descriptor.
249 *
250 * @return VFS file structure corresponding to fd.
251 */
252vfs_file_t *vfs_file_get(int fd)
253{
254 if (!vfs_files_init())
255 return NULL;
256
257 fibril_mutex_lock(&VFS_DATA->lock);
258 if ((fd >= 0) && (fd < MAX_OPEN_FILES)) {
259 vfs_file_t *file = FILES[fd];
260 vfs_file_addref(file);
261 fibril_mutex_unlock(&VFS_DATA->lock);
262 return file;
263 }
264 fibril_mutex_unlock(&VFS_DATA->lock);
265
266 return NULL;
267}
268
269/** Stop using a file structure.
270 *
271 * @param file VFS file structure.
272 */
273void vfs_file_put(vfs_file_t *file)
274{
275 fibril_mutex_lock(&VFS_DATA->lock);
276 vfs_file_delref(file);
277 fibril_mutex_unlock(&VFS_DATA->lock);
278}
279
280/**
281 * @}
282 */
Note: See TracBrowser for help on using the repository browser.