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

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

Use async relations introduced in the previous changeset to implement
vfs_grab_phone() and vfs_release_phone().

With this change, VFS will not be pointlessly connecting and disconnecting
phones on each VFS request.

Judging from the output of the top utility, this reduces the share of VFS on
kernel time by about 7% (from 25% down to 18%) and DEVFS kernel time by about 5%
(from 28% to 23%). This also makes CONSOLE the biggest consumer of kernel time,
while it used to be third after DEVFS and VFS.

  • Property mode set to 100644
File size: 9.0 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/ipc.h>
39#include <ipc/services.h>
40#include <async.h>
41#include <async_rel.h>
42#include <fibril.h>
43#include <fibril_synch.h>
44#include <errno.h>
45#include <stdio.h>
46#include <stdlib.h>
47#include <str.h>
48#include <ctype.h>
49#include <bool.h>
50#include <adt/list.h>
51#include <as.h>
52#include <assert.h>
53#include <atomic.h>
54#include "vfs.h"
55
56FIBRIL_CONDVAR_INITIALIZE(fs_head_cv);
57FIBRIL_MUTEX_INITIALIZE(fs_head_lock);
58LIST_INITIALIZE(fs_head);
59
60atomic_t fs_handle_next = {
61 .count = 1
62};
63
64/** Verify the VFS info structure.
65 *
66 * @param info Info structure to be verified.
67 *
68 * @return Non-zero if the info structure is sane, zero otherwise.
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 for (i = 1; i < FS_NAME_MAXLEN; i++) {
83 if (!(islower(info->name[i]) || isdigit(info->name[i])) &&
84 (info->name[i] != '-') && (info->name[i] != '_')) {
85 if (info->name[i] == '\0') {
86 break;
87 } else {
88 dprintf("The name contains illegal "
89 "characters.\n");
90 return false;
91 }
92 }
93 }
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') {
99 dprintf("The name is not properly NULL-terminated.\n");
100 return false;
101 }
102
103 return true;
104}
105
106/** VFS_REGISTER protocol function.
107 *
108 * @param rid Hash of the call with the request.
109 * @param request Call structure with the request.
110 */
111void vfs_register(ipc_callid_t rid, ipc_call_t *request)
112{
113 dprintf("Processing VFS_REGISTER request received from %p.\n",
114 request->in_phone_hash);
115
116 vfs_info_t *vfs_info;
117 int rc = async_data_write_accept((void **) &vfs_info, false,
118 sizeof(vfs_info_t), sizeof(vfs_info_t), 0, NULL);
119
120 if (rc != EOK) {
121 dprintf("Failed to deliver the VFS info into our AS, rc=%d.\n",
122 rc);
123 ipc_answer_0(rid, rc);
124 return;
125 }
126
127 /*
128 * Allocate and initialize a buffer for the fs_info structure.
129 */
130 fs_info_t *fs_info = (fs_info_t *) malloc(sizeof(fs_info_t));
131 if (!fs_info) {
132 dprintf("Could not allocate memory for FS info.\n");
133 ipc_answer_0(rid, ENOMEM);
134 return;
135 }
136
137 link_initialize(&fs_info->fs_link);
138 fibril_mutex_initialize(&fs_info->phone_lock);
139 fs_info->vfs_info = *vfs_info;
140 free(vfs_info);
141
142 dprintf("VFS info delivered.\n");
143
144 if (!vfs_info_sane(&fs_info->vfs_info)) {
145 free(fs_info);
146 ipc_answer_0(rid, EINVAL);
147 return;
148 }
149
150 fibril_mutex_lock(&fs_head_lock);
151
152 /*
153 * Check for duplicit registrations.
154 */
155 if (fs_name_to_handle(fs_info->vfs_info.name, false)) {
156 /*
157 * We already register a fs like this.
158 */
159 dprintf("FS is already registered.\n");
160 fibril_mutex_unlock(&fs_head_lock);
161 free(fs_info);
162 ipc_answer_0(rid, EEXISTS);
163 return;
164 }
165
166 /*
167 * Add fs_info to the list of registered FS's.
168 */
169 dprintf("Inserting FS into the list of registered file systems.\n");
170 list_append(&fs_info->fs_link, &fs_head);
171
172 /*
173 * Now we want the client to send us the IPC_M_CONNECT_TO_ME call so
174 * that a callback connection is created and we have a phone through
175 * which to forward VFS requests to it.
176 */
177 ipc_call_t call;
178 ipc_callid_t callid = async_get_call(&call);
179 if (IPC_GET_METHOD(call) != IPC_M_CONNECT_TO_ME) {
180 dprintf("Unexpected call, method = %d\n", IPC_GET_METHOD(call));
181 list_remove(&fs_info->fs_link);
182 fibril_mutex_unlock(&fs_head_lock);
183 free(fs_info);
184 ipc_answer_0(callid, EINVAL);
185 ipc_answer_0(rid, EINVAL);
186 return;
187 }
188 fs_info->phone = IPC_GET_ARG5(call);
189 ipc_answer_0(callid, EOK);
190
191 dprintf("Callback connection to FS created.\n");
192
193 /*
194 * The client will want us to send him the address space area with PLB.
195 */
196
197 size_t size;
198 if (!async_share_in_receive(&callid, &size)) {
199 dprintf("Unexpected call, method = %d\n", IPC_GET_METHOD(call));
200 list_remove(&fs_info->fs_link);
201 fibril_mutex_unlock(&fs_head_lock);
202 ipc_hangup(fs_info->phone);
203 free(fs_info);
204 ipc_answer_0(callid, EINVAL);
205 ipc_answer_0(rid, EINVAL);
206 return;
207 }
208
209 /*
210 * We can only send the client address space area PLB_SIZE bytes long.
211 */
212 if (size != PLB_SIZE) {
213 dprintf("Client suggests wrong size of PFB, size = %d\n", size);
214 list_remove(&fs_info->fs_link);
215 fibril_mutex_unlock(&fs_head_lock);
216 ipc_hangup(fs_info->phone);
217 free(fs_info);
218 ipc_answer_0(callid, EINVAL);
219 ipc_answer_0(rid, EINVAL);
220 return;
221 }
222
223 /*
224 * Commit to read-only sharing the PLB with the client.
225 */
226 (void) async_share_in_finalize(callid, plb,
227 AS_AREA_READ | AS_AREA_CACHEABLE);
228
229 dprintf("Sharing PLB.\n");
230
231 /*
232 * That was it. The FS has been registered.
233 * In reply to the VFS_REGISTER request, we assign the client file
234 * system a global file system handle.
235 */
236 fs_info->fs_handle = (fs_handle_t) atomic_postinc(&fs_handle_next);
237 ipc_answer_1(rid, EOK, (ipcarg_t) fs_info->fs_handle);
238
239 fibril_condvar_broadcast(&fs_head_cv);
240 fibril_mutex_unlock(&fs_head_lock);
241
242 dprintf("\"%.*s\" filesystem successfully registered, handle=%d.\n",
243 FS_NAME_MAXLEN, fs_info->vfs_info.name, fs_info->fs_handle);
244}
245
246/** For a given file system handle, implement policy for allocating a phone.
247 *
248 * @param handle File system handle.
249 *
250 * @return Phone over which a multi-call request can be safely
251 * sent. Return 0 if no phone was found.
252 */
253int vfs_grab_phone(fs_handle_t handle)
254{
255 link_t *cur;
256 fs_info_t *fs;
257 int phone;
258
259 /*
260 * For now, we don't try to be very clever and very fast. We simply
261 * lookup the phone in the fs_head list and duplicate it. The duplicate
262 * phone will be returned to the client and the client will use it for
263 * communication. In the future, we should cache the connections so
264 * that they do not have to be reestablished over and over again.
265 */
266 fibril_mutex_lock(&fs_head_lock);
267 for (cur = fs_head.next; cur != &fs_head; cur = cur->next) {
268 fs = list_get_instance(cur, fs_info_t, fs_link);
269 if (fs->fs_handle == handle) {
270 fibril_mutex_unlock(&fs_head_lock);
271 fibril_mutex_lock(&fs->phone_lock);
272 phone = async_relation_create(fs->phone);
273 fibril_mutex_unlock(&fs->phone_lock);
274
275 assert(phone > 0);
276 return phone;
277 }
278 }
279 fibril_mutex_unlock(&fs_head_lock);
280 return 0;
281}
282
283/** Tell VFS that the phone is not needed anymore.
284 *
285 * @param phone Phone to FS task.
286 */
287void vfs_release_phone(fs_handle_t handle, int phone)
288{
289 link_t *cur;
290 fs_info_t *fs;
291
292 fibril_mutex_lock(&fs_head_lock);
293 for (cur = fs_head.next; cur != &fs_head; cur = cur->next) {
294 fs = list_get_instance(cur, fs_info_t, fs_link);
295 if (fs->fs_handle == handle) {
296 fibril_mutex_unlock(&fs_head_lock);
297 fibril_mutex_lock(&fs->phone_lock);
298 async_relation_destroy(fs->phone, phone);
299 fibril_mutex_unlock(&fs->phone_lock);
300 return;
301 }
302 }
303 /* should not really get here */
304 abort();
305 fibril_mutex_unlock(&fs_head_lock);
306}
307
308/** Convert file system name to its handle.
309 *
310 * @param name File system name.
311 * @param lock If true, the function will lock and unlock the
312 * fs_head_lock.
313 *
314 * @return File system handle or zero if file system not found.
315 */
316fs_handle_t fs_name_to_handle(char *name, bool lock)
317{
318 int handle = 0;
319
320 if (lock)
321 fibril_mutex_lock(&fs_head_lock);
322 link_t *cur;
323 for (cur = fs_head.next; cur != &fs_head; cur = cur->next) {
324 fs_info_t *fs = list_get_instance(cur, fs_info_t, fs_link);
325 if (str_cmp(fs->vfs_info.name, name) == 0) {
326 handle = fs->fs_handle;
327 break;
328 }
329 }
330 if (lock)
331 fibril_mutex_unlock(&fs_head_lock);
332 return handle;
333}
334
335/**
336 * @}
337 */
Note: See TracBrowser for help on using the repository browser.