source: mainline/uspace/srv/vfs/vfs_register.c@ c20cccb

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since c20cccb was 984a9ba, checked in by Martin Decky <martin@…>, 7 years ago

do not expose the call capability handler from the async framework

Keep the call capability handler encapsulated within the async framework
and do not expose it explicitly via its API. Use the pointer to
ipc_call_t as the sole object identifying an IPC call in the code that
uses the async framework.

This plugs a major leak in the abstraction and also simplifies both the
async framework (slightly) and all IPC servers.

  • Property mode set to 100644
File size: 9.4 KB
Line 
1/*
2 * Copyright (c) 2008 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_register.c
35 * @brief
36 */
37
38#include <ipc/services.h>
39#include <async.h>
40#include <fibril.h>
41#include <fibril_synch.h>
42#include <errno.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <str.h>
46#include <ctype.h>
47#include <stdbool.h>
48#include <adt/list.h>
49#include <as.h>
50#include <assert.h>
51#include <atomic.h>
52#include <vfs/vfs.h>
53#include "vfs.h"
54
55FIBRIL_CONDVAR_INITIALIZE(fs_list_cv);
56FIBRIL_MUTEX_INITIALIZE(fs_list_lock);
57LIST_INITIALIZE(fs_list);
58
59atomic_t fs_handle_next = {
60 .count = 1
61};
62
63/** Verify the VFS info structure.
64 *
65 * @param info Info structure to be verified.
66 *
67 * @return Non-zero if the info structure is sane, zero otherwise.
68 *
69 */
70static bool vfs_info_sane(vfs_info_t *info)
71{
72 int i;
73
74 /*
75 * Check if the name is non-empty and is composed solely of ASCII
76 * characters [a-z]+[a-z0-9_-]*.
77 */
78 if (!islower(info->name[0])) {
79 dprintf("The name doesn't start with a lowercase character.\n");
80 return false;
81 }
82
83 for (i = 1; i < FS_NAME_MAXLEN; i++) {
84 if (!(islower(info->name[i]) || isdigit(info->name[i])) &&
85 (info->name[i] != '-') && (info->name[i] != '_')) {
86 if (info->name[i] == '\0') {
87 break;
88 } else {
89 dprintf("The name contains illegal "
90 "characters.\n");
91 return false;
92 }
93 }
94 }
95
96 /*
97 * This check is not redundant. It ensures that the name is
98 * NULL-terminated, even if FS_NAME_MAXLEN characters are used.
99 */
100 if (info->name[i] != '\0') {
101 dprintf("The name is not properly NULL-terminated.\n");
102 return false;
103 }
104
105 return true;
106}
107
108/** VFS_REGISTER protocol function.
109 *
110 * @param req Call structure with the request.
111 *
112 */
113void vfs_register(ipc_call_t *req)
114{
115 dprintf("Processing VFS_REGISTER request received from %zx.\n",
116 req->in_phone_hash);
117
118 vfs_info_t *vfs_info;
119 errno_t rc = async_data_write_accept((void **) &vfs_info, false,
120 sizeof(vfs_info_t), sizeof(vfs_info_t), 0, NULL);
121
122 if (rc != EOK) {
123 dprintf("Failed to deliver the VFS info into our AS, rc=%d.\n",
124 rc);
125 async_answer_0(req, rc);
126 return;
127 }
128
129 /*
130 * Allocate and initialize a buffer for the fs_info structure.
131 */
132 fs_info_t *fs_info = (fs_info_t *) malloc(sizeof(fs_info_t));
133 if (!fs_info) {
134 dprintf("Could not allocate memory for FS info.\n");
135 async_answer_0(req, ENOMEM);
136 return;
137 }
138
139 link_initialize(&fs_info->fs_link);
140 fs_info->vfs_info = *vfs_info;
141 free(vfs_info);
142
143 dprintf("VFS info delivered.\n");
144
145 if (!vfs_info_sane(&fs_info->vfs_info)) {
146 free(fs_info);
147 async_answer_0(req, EINVAL);
148 return;
149 }
150
151 fibril_mutex_lock(&fs_list_lock);
152
153 /*
154 * Check for duplicit registrations.
155 */
156 if (fs_name_to_handle(fs_info->vfs_info.instance,
157 fs_info->vfs_info.name, false)) {
158 /*
159 * We already register a fs like this.
160 */
161 dprintf("FS is already registered.\n");
162 fibril_mutex_unlock(&fs_list_lock);
163 free(fs_info);
164 async_answer_0(req, EEXIST);
165 return;
166 }
167
168 /*
169 * Add fs_info to the list of registered FS's.
170 */
171 dprintf("Inserting FS into the list of registered file systems.\n");
172 list_append(&fs_info->fs_link, &fs_list);
173
174 /*
175 * Now we want the client to send us the IPC_M_CONNECT_TO_ME call so
176 * that a callback connection is created and we have a phone through
177 * which to forward VFS requests to it.
178 */
179 fs_info->sess = async_callback_receive(EXCHANGE_PARALLEL);
180 if (!fs_info->sess) {
181 dprintf("Callback connection expected\n");
182 list_remove(&fs_info->fs_link);
183 fibril_mutex_unlock(&fs_list_lock);
184 free(fs_info);
185 async_answer_0(req, EINVAL);
186 return;
187 }
188
189 dprintf("Callback connection to FS created.\n");
190
191 /*
192 * The client will want us to send him the address space area with PLB.
193 */
194
195 ipc_call_t call;
196 size_t size;
197 if (!async_share_in_receive(&call, &size)) {
198 dprintf("Unexpected call\n");
199 list_remove(&fs_info->fs_link);
200 fibril_mutex_unlock(&fs_list_lock);
201 async_hangup(fs_info->sess);
202 free(fs_info);
203 async_answer_0(&call, EINVAL);
204 async_answer_0(req, EINVAL);
205 return;
206 }
207
208 /*
209 * We can only send the client address space area PLB_SIZE bytes long.
210 */
211 if (size != PLB_SIZE) {
212 dprintf("Client suggests wrong size of PFB, size = %zu\n", size);
213 list_remove(&fs_info->fs_link);
214 fibril_mutex_unlock(&fs_list_lock);
215 async_hangup(fs_info->sess);
216 free(fs_info);
217 async_answer_0(&call, EINVAL);
218 async_answer_0(req, EINVAL);
219 return;
220 }
221
222 /*
223 * Commit to read-only sharing the PLB with the client.
224 */
225 (void) async_share_in_finalize(&call, plb,
226 AS_AREA_READ | AS_AREA_CACHEABLE);
227
228 dprintf("Sharing PLB.\n");
229
230 /*
231 * That was it. The FS has been registered.
232 * In reply to the VFS_REGISTER request, we assign the client file
233 * system a global file system handle.
234 */
235 fs_info->fs_handle = (fs_handle_t) atomic_postinc(&fs_handle_next);
236 async_answer_1(req, EOK, (sysarg_t) fs_info->fs_handle);
237
238 fibril_condvar_broadcast(&fs_list_cv);
239 fibril_mutex_unlock(&fs_list_lock);
240
241 dprintf("\"%.*s\" filesystem successfully registered, handle=%d.\n",
242 FS_NAME_MAXLEN, fs_info->vfs_info.name, fs_info->fs_handle);
243}
244
245/** Begin an exchange for a given file system handle
246 *
247 * @param handle File system handle.
248 *
249 * @return Exchange for a multi-call request.
250 * @return NULL if no such file exists.
251 *
252 */
253async_exch_t *vfs_exchange_grab(fs_handle_t handle)
254{
255 /*
256 * For now, we don't try to be very clever and very fast.
257 * We simply lookup the session in fs_list and
258 * begin an exchange.
259 */
260 fibril_mutex_lock(&fs_list_lock);
261
262 list_foreach(fs_list, fs_link, fs_info_t, fs) {
263 if (fs->fs_handle == handle) {
264 fibril_mutex_unlock(&fs_list_lock);
265
266 assert(fs->sess);
267 async_exch_t *exch = async_exchange_begin(fs->sess);
268
269 assert(exch);
270 return exch;
271 }
272 }
273
274 fibril_mutex_unlock(&fs_list_lock);
275
276 return NULL;
277}
278
279/** End VFS server exchange.
280 *
281 * @param exch VFS server exchange.
282 *
283 */
284void vfs_exchange_release(async_exch_t *exch)
285{
286 async_exchange_end(exch);
287}
288
289/** Convert file system name to its handle.
290 *
291 * @param name File system name.
292 * @param lock If true, the function will lock and unlock the
293 * fs_list_lock.
294 *
295 * @return File system handle or zero if file system not found.
296 *
297 */
298fs_handle_t fs_name_to_handle(unsigned int instance, const char *name, bool lock)
299{
300 int handle = 0;
301
302 if (lock)
303 fibril_mutex_lock(&fs_list_lock);
304
305 list_foreach(fs_list, fs_link, fs_info_t, fs) {
306 if (str_cmp(fs->vfs_info.name, name) == 0 &&
307 instance == fs->vfs_info.instance) {
308 handle = fs->fs_handle;
309 break;
310 }
311 }
312
313 if (lock)
314 fibril_mutex_unlock(&fs_list_lock);
315
316 return handle;
317}
318
319/** Find the VFS info structure.
320 *
321 * @param handle FS handle for which the VFS info structure is sought.
322 *
323 * @return VFS info structure on success or NULL otherwise.
324 *
325 */
326vfs_info_t *fs_handle_to_info(fs_handle_t handle)
327{
328 vfs_info_t *info = NULL;
329
330 fibril_mutex_lock(&fs_list_lock);
331 list_foreach(fs_list, fs_link, fs_info_t, fs) {
332 if (fs->fs_handle == handle) {
333 info = &fs->vfs_info;
334 break;
335 }
336 }
337 fibril_mutex_unlock(&fs_list_lock);
338
339 return info;
340}
341
342/** Get list of file system types.
343 *
344 * @param fstypes Place to store list of file system types. Free using
345 * vfs_fstypes_free().
346 *
347 * @return EOK on success or an error code
348 */
349errno_t vfs_get_fstypes(vfs_fstypes_t *fstypes)
350{
351 size_t size;
352 size_t count;
353 size_t l;
354
355 fibril_mutex_lock(&fs_list_lock);
356
357 size = 0;
358 count = 0;
359 list_foreach(fs_list, fs_link, fs_info_t, fs) {
360 size += str_size(fs->vfs_info.name) + 1;
361 count++;
362 }
363
364 if (size == 0)
365 size = 1;
366
367 fstypes->buf = calloc(1, size);
368 if (fstypes->buf == NULL) {
369 fibril_mutex_unlock(&fs_list_lock);
370 return ENOMEM;
371 }
372
373 fstypes->fstypes = calloc(sizeof(char *), count);
374 if (fstypes->fstypes == NULL) {
375 free(fstypes->buf);
376 fstypes->buf = NULL;
377 fibril_mutex_unlock(&fs_list_lock);
378 return ENOMEM;
379 }
380
381 fstypes->size = size;
382
383 size = 0;
384 count = 0;
385 list_foreach(fs_list, fs_link, fs_info_t, fs) {
386 l = str_size(fs->vfs_info.name) + 1;
387 memcpy(fstypes->buf + size, fs->vfs_info.name, l);
388 fstypes->fstypes[count] = &fstypes->buf[size];
389 size += l;
390 count++;
391 }
392
393 fibril_mutex_unlock(&fs_list_lock);
394 return EOK;
395}
396
397/**
398 * @}
399 */
Note: See TracBrowser for help on using the repository browser.