source: mainline/uspace/srv/vfs/vfs.c@ d2d0baf

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

VFS work.

The VFS_REGISTER is now fully implemented by both vfs and fat servers. Thanks to
the debugging dprintf()'s, I was able to fix little errors here and there to
make them actually work.

Modified vfs and fat service makefiles so that the two are not built as drivers
and can therefore print to standard output. Added many debugging dprintf()'s.

Change the amd64 boot configuration to load vfs and fat.

  • Property mode set to 100644
File size: 9.3 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.c
35 * @brief VFS multiplexer for HelenOS.
36 */
37
38#include <ipc/ipc.h>
39#include <ipc/services.h>
40#include <async.h>
41#include <errno.h>
42#include <stdio.h>
43#include <stdlib.h>
44#include <string.h>
45#include <ctype.h>
46#include <bool.h>
47#include <futex.h>
48#include <libadt/list.h>
49#include "vfs.h"
50
51
52#define dprintf(...) printf(__VA_ARGS__)
53
54atomic_t fs_head_futex = FUTEX_INITIALIZER;
55link_t fs_head;
56
57/** Verify the VFS info structure.
58 *
59 * @param info Info structure to be verified.
60 *
61 * @return Non-zero if the info structure is sane, zero otherwise.
62 */
63static bool vfs_info_sane(vfs_info_t *info)
64{
65 int i;
66
67 /*
68 * Check if the name is non-empty and is composed solely of ASCII
69 * characters [a-z]+[a-z0-9_-]*.
70 */
71 if (!islower(info->name[0])) {
72 dprintf("The name doesn't start with a lowercase character.\n");
73 return false;
74 }
75 for (i = 1; i < FS_NAME_MAXLEN; i++) {
76 if (!(islower(info->name[i]) || isdigit(info->name[i])) &&
77 (info->name[i] != '-') && (info->name[i] != '_')) {
78 if (info->name[i] == '\0') {
79 break;
80 } else {
81 dprintf("The name contains illegal "
82 "characters.\n");
83 return false;
84 }
85 }
86 }
87
88
89 /*
90 * Check if the FS implements mandatory VFS operations.
91 */
92 if (info->ops[IPC_METHOD_TO_VFS_OP(VFS_REGISTER)] != VFS_OP_DEFINED) {
93 dprintf("Operation VFS_REGISTER not defined by the client.\n");
94 return false;
95 }
96 if (info->ops[IPC_METHOD_TO_VFS_OP(VFS_MOUNT)] != VFS_OP_DEFINED) {
97 dprintf("Operation VFS_MOUNT not defined by the client.\n");
98 return false;
99 }
100 if (info->ops[IPC_METHOD_TO_VFS_OP(VFS_UNMOUNT)] != VFS_OP_DEFINED) {
101 dprintf("Operation VFS_UNMOUNT not defined by the client.\n");
102 return false;
103 }
104 if (info->ops[IPC_METHOD_TO_VFS_OP(VFS_LOOKUP)] != VFS_OP_DEFINED) {
105 dprintf("Operation VFS_LOOKUP not defined by the client.\n");
106 return false;
107 }
108 if (info->ops[IPC_METHOD_TO_VFS_OP(VFS_OPEN)] != VFS_OP_DEFINED) {
109 dprintf("Operation VFS_OPEN not defined by the client.\n");
110 return false;
111 }
112 if (info->ops[IPC_METHOD_TO_VFS_OP(VFS_CLOSE)] != VFS_OP_DEFINED) {
113 dprintf("Operation VFS_CLOSE not defined by the client.\n");
114 return false;
115 }
116 if (info->ops[IPC_METHOD_TO_VFS_OP(VFS_READ)] != VFS_OP_DEFINED) {
117 dprintf("Operation VFS_READ not defined by the client.\n");
118 return false;
119 }
120
121 /*
122 * Check if each operation is either not defined, defined or default.
123 */
124 for (i = VFS_FIRST; i < VFS_LAST; i++) {
125 if ((info->ops[IPC_METHOD_TO_VFS_OP(i)] != VFS_OP_NULL) &&
126 (info->ops[IPC_METHOD_TO_VFS_OP(i)] != VFS_OP_DEFAULT) &&
127 (info->ops[IPC_METHOD_TO_VFS_OP(i)] != VFS_OP_DEFINED)) {
128 dprintf("Operation info not understood.\n");
129 return false;
130 }
131 }
132 return true;
133}
134
135/** VFS_REGISTER protocol function.
136 *
137 * @param rid Hash of the call with the request.
138 * @param request Call structure with the request.
139 */
140static void vfs_register(ipc_callid_t rid, ipc_call_t *request)
141{
142 ipc_callid_t callid;
143 ipc_call_t call;
144 int rc;
145 size_t size;
146
147 dprintf("Processing VFS_REGISTER request received from %p.\n",
148 request->in_phone_hash);
149
150 /*
151 * The first call has to be IPC_M_DATA_SEND in which we receive the
152 * VFS info structure from the client FS.
153 */
154 if (!ipc_data_receive(&callid, &call, NULL, &size)) {
155 /*
156 * The client doesn't obey the same protocol as we do.
157 */
158 dprintf("Receiving of VFS info failed.\n");
159 ipc_answer_fast(callid, EINVAL, 0, 0);
160 ipc_answer_fast(rid, EINVAL, 0, 0);
161 return;
162 }
163
164 dprintf("VFS info received, size = %d\n", size);
165
166 /*
167 * We know the size of the VFS info structure. See if the client
168 * understands this easy concept too.
169 */
170 if (size != sizeof(vfs_info_t)) {
171 /*
172 * The client is sending us something, which cannot be
173 * the info structure.
174 */
175 dprintf("Received VFS info has bad size.\n");
176 ipc_answer_fast(callid, EINVAL, 0, 0);
177 ipc_answer_fast(rid, EINVAL, 0, 0);
178 return;
179 }
180 fs_info_t *fs_info;
181
182 /*
183 * Allocate and initialize a buffer for the fs_info structure.
184 */
185 fs_info = (fs_info_t *) malloc(sizeof(fs_info_t));
186 if (!fs_info) {
187 dprintf("Could not allocate memory for FS info.\n");
188 ipc_answer_fast(callid, ENOMEM, 0, 0);
189 ipc_answer_fast(rid, ENOMEM, 0, 0);
190 return;
191 }
192 link_initialize(&fs_info->fs_link);
193
194 rc = ipc_data_deliver(callid, &call, &fs_info->vfs_info, size);
195 if (rc != EOK) {
196 dprintf("Failed to deliver the VFS info into our AS, rc=%d.\n",
197 rc);
198 free(fs_info);
199 ipc_answer_fast(callid, rc, 0, 0);
200 ipc_answer_fast(rid, rc, 0, 0);
201 return;
202 }
203
204 dprintf("VFS info delivered.\n");
205
206 if (!vfs_info_sane(&fs_info->vfs_info)) {
207 free(fs_info);
208 ipc_answer_fast(callid, EINVAL, 0, 0);
209 ipc_answer_fast(rid, EINVAL, 0, 0);
210 return;
211 }
212
213 futex_down(&fs_head_futex);
214
215 /*
216 * Check for duplicit registrations.
217 */
218 link_t *cur;
219 for (cur = fs_head.next; cur != &fs_head; cur = cur->next) {
220 fs_info_t *fi = list_get_instance(cur, fs_info_t,
221 fs_link);
222 /* TODO: replace strcmp with strncmp once we have it */
223 if (strcmp(fs_info->vfs_info.name, fi->vfs_info.name) == 0) {
224 /*
225 * We already register a fs like this.
226 */
227 dprintf("FS is already registered.\n");
228 futex_up(&fs_head_futex);
229 free(fs_info);
230 ipc_answer_fast(callid, EEXISTS, 0, 0);
231 ipc_answer_fast(rid, EEXISTS, 0, 0);
232 return;
233 }
234 }
235
236 /*
237 * Add fs_info to the list of registered FS's.
238 */
239 dprintf("Adding FS into the registered list.\n");
240 list_append(&fs_info->fs_link, &fs_head);
241
242 /*
243 * ACK receiving a properly formatted, non-duplicit vfs_info.
244 */
245 ipc_answer_fast(callid, EOK, 0, 0);
246
247 /*
248 * Now we want the client to send us the IPC_M_CONNECT_TO_ME call so
249 * that a callback connection is created and we have a phone through
250 * which to forward VFS requests to it.
251 */
252 callid = async_get_call(&call);
253 if (IPC_GET_METHOD(call) != IPC_M_CONNECT_TO_ME) {
254 dprintf("Unexpected call, method = %d\n", IPC_GET_METHOD(call));
255 list_remove(&fs_info->fs_link);
256 futex_up(&fs_head_futex);
257 free(fs_info);
258 ipc_answer_fast(callid, EINVAL, 0, 0);
259 ipc_answer_fast(rid, EINVAL, 0, 0);
260 return;
261 }
262 fs_info->phone = IPC_GET_ARG3(call);
263 ipc_answer_fast(callid, EOK, 0, 0);
264
265 dprintf("Callback connection to FS created.\n");
266
267 futex_up(&fs_head_futex);
268
269 /*
270 * That was it. The FS has been registered.
271 */
272 ipc_answer_fast(rid, EOK, 0, 0);
273 dprintf("\"%s\" filesystem successfully registered.\n",
274 fs_info->vfs_info.name);
275}
276
277static void vfs_connection(ipc_callid_t iid, ipc_call_t *icall)
278{
279 bool keep_on_going = 1;
280
281 printf("Connection opened from %p\n", icall->in_phone_hash);
282
283 /*
284 * The connection was opened via the IPC_CONNECT_ME_TO call.
285 * This call needs to be answered.
286 */
287 ipc_answer_fast(iid, EOK, 0, 0);
288
289 /*
290 * Here we enter the main connection fibril loop.
291 * The logic behind this loop and the protocol is that we'd like to keep
292 * each connection open for a while before we close it. The benefit of
293 * this is that the client doesn't have to establish a new connection
294 * upon each request. On the other hand, the client must be ready to
295 * re-establish a connection if we hang it up due to reaching of maximum
296 * number of requests per connection or due to the client timing out.
297 */
298
299 while (keep_on_going) {
300 ipc_callid_t callid;
301 ipc_call_t call;
302
303 callid = async_get_call(&call);
304
305 printf("Received call, method=%d\n", IPC_GET_METHOD(call));
306
307 switch (IPC_GET_METHOD(call)) {
308 case IPC_M_PHONE_HUNGUP:
309 keep_on_going = false;
310 break;
311 case VFS_REGISTER:
312 vfs_register(callid, &call);
313 keep_on_going = false;
314 break;
315 case VFS_MOUNT:
316 case VFS_UNMOUNT:
317 case VFS_OPEN:
318 case VFS_CREATE:
319 case VFS_CLOSE:
320 case VFS_READ:
321 case VFS_WRITE:
322 case VFS_SEEK:
323 default:
324 ipc_answer_fast(callid, ENOTSUP, 0, 0);
325 break;
326 }
327 }
328
329 /* TODO: cleanup after the client */
330
331}
332
333int main(int argc, char **argv)
334{
335 ipcarg_t phonead;
336
337 printf("VFS: HelenOS VFS server\n");
338
339 list_initialize(&fs_head);
340 async_set_client_connection(vfs_connection);
341 ipc_connect_to_me(PHONE_NS, SERVICE_VFS, 0, &phonead);
342 async_manager();
343 return 0;
344}
345
346/**
347 * @}
348 */
Note: See TracBrowser for help on using the repository browser.