source: mainline/uspace/srv/vfs/vfs_register.c@ 08e103d4

Last change on this file since 08e103d4 was 08e103d4, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

Use clearer naming for string length functions

This and the following commit change the names of functions, as well as
their documentation, to use unambiguous terms "bytes" and "code points"
instead of ambiguous terms "size", "length", and "characters".

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