source: mainline/uspace/srv/vfs/vfs_mount.c@ 45ee9ed

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

VFS work. Releas the FS phone earlier.

  • Property mode set to 100644
File size: 6.8 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_mount.c
35 * @brief VFS_MOUNT method.
36 */
37
38#include <ipc/ipc.h>
39#include <async.h>
40#include <errno.h>
41#include <stdlib.h>
42#include <string.h>
43#include <bool.h>
44#include <futex.h>
45#include <libadt/list.h>
46#include "vfs.h"
47
48atomic_t rootfs_futex = FUTEX_INITIALIZER;
49vfs_triplet_t rootfs = {
50 .fs_handle = 0,
51 .dev_handle = 0,
52 .index = 0,
53};
54
55static int lookup_root(int fs_handle, int dev_handle, vfs_triplet_t *root)
56{
57 vfs_pair_t altroot = {
58 .fs_handle = fs_handle,
59 .dev_handle = dev_handle,
60 };
61
62 return vfs_lookup_internal("/", strlen("/"), root, &altroot);
63}
64
65void vfs_mount(ipc_callid_t rid, ipc_call_t *request)
66{
67 int dev_handle;
68 vfs_node_t *mp_node = NULL;
69
70 /*
71 * We expect the library to do the device-name to device-handle
72 * translation for us, thus the device handle will arrive as ARG1
73 * in the request.
74 */
75 dev_handle = IPC_GET_ARG1(*request);
76
77 /*
78 * For now, don't make use of ARG2 and ARG3, but they can be used to
79 * carry mount options in the future.
80 */
81
82 /*
83 * Now, we expect the client to send us data with the name of the file
84 * system and the path of the mountpoint.
85 */
86 ipc_callid_t callid;
87 size_t size;
88 if (!ipc_data_receive(&callid, NULL, &size)) {
89 ipc_answer_0(callid, EINVAL);
90 ipc_answer_0(rid, EINVAL);
91 return;
92 }
93
94 /*
95 * There is no sense in receiving data that can't hold a single
96 * character of path. We won't accept data that exceed certain limits
97 * either.
98 */
99 if ((size < FS_NAME_MAXLEN + 1) ||
100 (size > FS_NAME_MAXLEN + MAX_PATH_LEN)) {
101 ipc_answer_0(callid, EINVAL);
102 ipc_answer_0(rid, EINVAL);
103 return;
104 }
105
106 /*
107 * Allocate buffer for the data being received.
108 */
109 uint8_t *buf;
110 buf = malloc(size);
111 if (!buf) {
112 ipc_answer_0(callid, ENOMEM);
113 ipc_answer_0(rid, ENOMEM);
114 return;
115 }
116
117 /*
118 * Deliver the data.
119 */
120 (void) ipc_data_deliver(callid, buf, size);
121
122 char fs_name[FS_NAME_MAXLEN + 1];
123 memcpy(fs_name, buf, FS_NAME_MAXLEN);
124 fs_name[FS_NAME_MAXLEN] = '\0';
125
126 /*
127 * Check if we know a file system with the same name as is in fs_name.
128 * This will also give us its file system handle.
129 */
130 int fs_handle = fs_name_to_handle(fs_name, true);
131 if (!fs_handle) {
132 free(buf);
133 ipc_answer_0(rid, ENOENT);
134 return;
135 }
136
137 /*
138 * Lookup the root node of the filesystem being mounted.
139 * In this case, we don't need to take the unlink_futex as the root node
140 * cannot be removed. However, we do take a reference to it so that
141 * we can track how many times it has been mounted.
142 */
143 int rc;
144 vfs_triplet_t mounted_root;
145 rc = lookup_root(fs_handle, dev_handle, &mounted_root);
146 if (rc != EOK) {
147 free(buf);
148 ipc_answer_0(rid, rc);
149 return;
150 }
151 vfs_node_t *mr_node = vfs_node_get(&mounted_root);
152 if (!mr_node) {
153 free(buf);
154 ipc_answer_0(rid, ENOMEM);
155 return;
156 }
157
158 /*
159 * Finally, we need to resolve the path to the mountpoint.
160 */
161 vfs_triplet_t mp;
162 futex_down(&rootfs_futex);
163 if (rootfs.fs_handle) {
164 /*
165 * We already have the root FS.
166 */
167 futex_down(&unlink_futex);
168 rc = vfs_lookup_internal((char *) (buf + FS_NAME_MAXLEN),
169 size - FS_NAME_MAXLEN, &mp, NULL);
170 if (rc != EOK) {
171 /*
172 * The lookup failed for some reason.
173 */
174 futex_up(&unlink_futex);
175 futex_up(&rootfs_futex);
176 vfs_node_put(mr_node); /* failed -> drop reference */
177 free(buf);
178 ipc_answer_0(rid, rc);
179 return;
180 }
181 mp_node = vfs_node_get(&mp);
182 if (!mp_node) {
183 futex_up(&unlink_futex);
184 futex_up(&rootfs_futex);
185 vfs_node_put(mr_node); /* failed -> drop reference */
186 free(buf);
187 ipc_answer_0(rid, ENOMEM);
188 return;
189 }
190 /*
191 * Now we hold a reference to mp_node.
192 * It will be dropped upon the corresponding VFS_UNMOUNT.
193 * This prevents the mount point from being deleted.
194 */
195 futex_up(&unlink_futex);
196 } else {
197 /*
198 * We still don't have the root file system mounted.
199 */
200 if ((size - FS_NAME_MAXLEN == strlen("/")) &&
201 (buf[FS_NAME_MAXLEN] == '/')) {
202 /*
203 * For this simple, but important case, we are done.
204 */
205 rootfs = mounted_root;
206 futex_up(&rootfs_futex);
207 free(buf);
208 ipc_answer_0(rid, EOK);
209 return;
210 } else {
211 /*
212 * We can't resolve this without the root filesystem
213 * being mounted first.
214 */
215 futex_up(&rootfs_futex);
216 free(buf);
217 vfs_node_put(mr_node); /* failed -> drop reference */
218 ipc_answer_0(rid, ENOENT);
219 return;
220 }
221 }
222 futex_up(&rootfs_futex);
223
224 free(buf); /* The buffer is not needed anymore. */
225
226 /*
227 * At this point, we have all necessary pieces: file system and device
228 * handles, and we know the mount point VFS node and also the root node
229 * of the file system being mounted.
230 */
231
232 int phone = vfs_grab_phone(mp.fs_handle);
233 /* Later we can use ARG3 to pass mode/flags. */
234 aid_t req1 = async_send_3(phone, VFS_MOUNT, (ipcarg_t) mp.dev_handle,
235 (ipcarg_t) mp.index, 0, NULL);
236 /* The second call uses the same method. */
237 aid_t req2 = async_send_3(phone, VFS_MOUNT,
238 (ipcarg_t) mounted_root.fs_handle,
239 (ipcarg_t) mounted_root.dev_handle, (ipcarg_t) mounted_root.index,
240 NULL);
241 vfs_release_phone(phone);
242
243 ipcarg_t rc1;
244 ipcarg_t rc2;
245 async_wait_for(req1, &rc1);
246 async_wait_for(req2, &rc2);
247
248 if ((rc1 != EOK) || (rc2 != EOK)) {
249 /* Mount failed, drop references to mr_node and mp_node. */
250 vfs_node_put(mr_node);
251 if (mp_node)
252 vfs_node_put(mp_node);
253 }
254
255 if (rc2 == EOK)
256 ipc_answer_0(rid, rc1);
257 else if (rc1 == EOK)
258 ipc_answer_0(rid, rc2);
259 else
260 ipc_answer_0(rid, rc1);
261}
262
263/**
264 * @}
265 */
Note: See TracBrowser for help on using the repository browser.