source: mainline/uspace/srv/vfs/vfs.c@ 2b20947

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

VFS work.
Delve deeper into VFS_REGISTER.

  • Property mode set to 100644
File size: 7.0 KB
RevLine 
[0f78e74]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
[c952465d]38#include <ipc/ipc.h>
39#include <ipc/services.h>
40#include <async.h>
41#include <errno.h>
[d79dcdb]42#include <stdlib.h>
[2b20947]43#include <string.h>
44#include <ctype.h>
[d79dcdb]45#include <bool.h>
[2b20947]46#include <futex.h>
47#include <libadt/list.h>
[c952465d]48#include "vfs.h"
49
[2b20947]50atomic_t fs_head_futex = FUTEX_INITIALIZER;
51link_t fs_head;
52
[d79dcdb]53/** Verify the VFS info structure.
54 *
55 * @param info Info structure to be verified.
56 *
57 * @return Non-zero if the info structure is sane, zero otherwise.
58 */
[2b20947]59static bool vfs_info_sane(vfs_info_t *info)
[d79dcdb]60{
[2b20947]61 int i;
62
63 /*
64 * Check if the name is non-empty and is composed solely of ASCII
65 * characters [a-z]+[a-z0-9_-]*.
66 */
67 if (!islower(info->name[0]))
68 return false;
69 for (i = 1; i < FS_NAME_MAXLEN; i++) {
70 if (!(islower(info->name[i]) || isdigit(info->name[i])) &&
71 (info->name[i] != '-') && (info->name[i] != '_')) {
72 if (info->name[i] == '\0')
73 break;
74 else
75 return false;
76 }
77 }
78
79
80 /*
81 * Check if the FS implements mandatory VFS operations.
82 */
83 if (info->ops[IPC_METHOD_TO_VFS_OP(VFS_REGISTER)] != VFS_OP_DEFINED)
84 return false;
85 if (info->ops[IPC_METHOD_TO_VFS_OP(VFS_MOUNT)] != VFS_OP_DEFINED)
86 return false;
87 if (info->ops[IPC_METHOD_TO_VFS_OP(VFS_UNMOUNT)] != VFS_OP_DEFINED)
88 return false;
89 if (info->ops[IPC_METHOD_TO_VFS_OP(VFS_OPEN)] != VFS_OP_DEFINED)
90 return false;
91 if (info->ops[IPC_METHOD_TO_VFS_OP(VFS_CLOSE)] != VFS_OP_DEFINED)
92 return false;
93 if (info->ops[IPC_METHOD_TO_VFS_OP(VFS_READ)] != VFS_OP_DEFINED)
94 return false;
95
96 /*
97 * Check if each operation is either not defined, defined or default.
98 */
99 for (i = VFS_FIRST; i < VFS_LAST; i++) {
100 if ((IPC_METHOD_TO_VFS_OP(i) != VFS_OP_NULL) &&
101 (IPC_METHOD_TO_VFS_OP(i) != VFS_OP_DEFAULT) &&
102 (IPC_METHOD_TO_VFS_OP(i) != VFS_OP_DEFINED))
103 return false;
104 }
105 return true;
[d79dcdb]106}
107
108/** VFS_REGISTER protocol function.
109 *
110 * @param rid Hash of the call with the request.
111 * @param request Call structure with the request.
112 */
113static void vfs_register(ipc_callid_t rid, ipc_call_t *request)
[b3f598e]114{
115 ipc_callid_t callid;
116 ipc_call_t call;
[d79dcdb]117 int rc;
118 size_t size;
[b3f598e]119
[d79dcdb]120 /*
121 * The first call has to be IPC_M_DATA_SEND in which we receive the
122 * VFS info structure from the client FS.
123 */
124 if (!ipc_data_send_accept(&callid, &call, NULL, &size)) {
[b3f598e]125 /*
126 * The client doesn't obey the same protocol as we do.
127 */
128 ipc_answer_fast(callid, EINVAL, 0, 0);
[d79dcdb]129 ipc_answer_fast(rid, EINVAL, 0, 0);
[b3f598e]130 return;
131 }
[d79dcdb]132
133 /*
[2b20947]134 * We know the size of the VFS info structure. See if the client
135 * understands this easy concept too.
[d79dcdb]136 */
137 if (size != sizeof(vfs_info_t)) {
138 /*
139 * The client is sending us something, which cannot be
140 * the info structure.
141 */
142 ipc_answer_fast(callid, EINVAL, 0, 0);
143 ipc_answer_fast(rid, EINVAL, 0, 0);
144 return;
145 }
[2b20947]146 fs_info_t *fs_info;
[d79dcdb]147
148 /*
[2b20947]149 * Allocate and initialize a buffer for the fs_info structure.
[d79dcdb]150 */
[2b20947]151 fs_info = (fs_info_t *) malloc(sizeof(fs_info_t));
152 if (!fs_info) {
[d79dcdb]153 ipc_answer_fast(callid, ENOMEM, 0, 0);
154 ipc_answer_fast(rid, ENOMEM, 0, 0);
155 return;
156 }
[2b20947]157 link_initialize(&fs_info->fs_link);
[d79dcdb]158
[2b20947]159 rc = ipc_data_send_answer(callid, &call, &fs_info->vfs_info, size);
[d79dcdb]160 if (!rc) {
[2b20947]161 free(fs_info);
[d79dcdb]162 ipc_answer_fast(callid, rc, 0, 0);
163 ipc_answer_fast(rid, rc, 0, 0);
164 return;
165 }
166
[2b20947]167 if (!vfs_info_sane(&fs_info->vfs_info)) {
168 free(fs_info);
[d79dcdb]169 ipc_answer_fast(callid, EINVAL, 0, 0);
170 ipc_answer_fast(rid, EINVAL, 0, 0);
171 return;
172 }
173
[2b20947]174 futex_down(&fs_head_futex);
175
176 /*
177 * Check for duplicit registrations.
178 */
179 link_t *cur;
180 for (cur = fs_head.next; cur != &fs_head; cur = cur->next) {
181 fs_info_t *fi = list_get_instance(cur, fs_info_t,
182 fs_link);
183 /* TODO: replace strcmp with strncmp once we have it */
184 if (strcmp(fs_info->vfs_info.name, fi->vfs_info.name) == 0) {
185 /*
186 * We already register a fs like this.
187 */
188 futex_up(&fs_head_futex);
189 free(fs_info);
190 ipc_answer_fast(callid, EEXISTS, 0, 0);
191 ipc_answer_fast(rid, EEXISTS, 0, 0);
192 return;
193 }
194 }
195
196 /*
197 * TODO:
198 * 1. send the client the IPC_M_CONNECT_TO_ME call so that it makes a
199 * callback connection.
200 * 2. add the fs_info into fs_head
201 */
202
203 futex_up(&fs_head_futex);
[b3f598e]204}
205
[c952465d]206static void vfs_connection(ipc_callid_t iid, ipc_call_t *icall)
207{
[d79dcdb]208 bool keep_on_going = 1;
[c952465d]209
210 /*
211 * The connection was opened via the IPC_CONNECT_ME_TO call.
212 * This call needs to be answered.
213 */
[d79dcdb]214 ipc_answer_fast(iid, EOK, 0, 0);
[c952465d]215
216 /*
[d79dcdb]217 * Here we enter the main connection fibril loop.
218 * The logic behind this loop and the protocol is that we'd like to keep
219 * each connection open for a while before we close it. The benefit of
220 * this is that the client doesn't have to establish a new connection
221 * upon each request. On the other hand, the client must be ready to
222 * re-establish a connection if we hang it up due to reaching of maximum
223 * number of requests per connection or due to the client timing out.
[c952465d]224 */
[d79dcdb]225
226 while (keep_on_going) {
227 ipc_callid_t callid;
228 ipc_call_t call;
229
230 callid = async_get_call(&call);
231
232 switch (IPC_GET_METHOD(call)) {
233 case IPC_M_PHONE_HUNGUP:
234 keep_on_going = false;
235 break;
236 case VFS_REGISTER:
237 vfs_register(callid, &call);
238 keep_on_going = false;
239 break;
240 case VFS_MOUNT:
241 case VFS_UNMOUNT:
242 case VFS_OPEN:
243 case VFS_CREATE:
244 case VFS_CLOSE:
245 case VFS_READ:
246 case VFS_WRITE:
247 case VFS_SEEK:
248 default:
249 ipc_answer_fast(callid, ENOTSUP, 0, 0);
250 break;
251 }
[c952465d]252 }
[d79dcdb]253
254 /* TODO: cleanup after the client */
255
[c952465d]256}
257
[0f78e74]258int main(int argc, char **argv)
259{
[c952465d]260 ipcarg_t phonead;
261
[2b20947]262 list_initialize(&fs_head);
[c952465d]263 async_set_client_connection(vfs_connection);
264 ipc_connect_to_me(PHONE_NS, SERVICE_VFS, 0, &phonead);
265 async_manager();
[0f78e74]266 return 0;
267}
268
269/**
270 * @}
271 */
Note: See TracBrowser for help on using the repository browser.