source: mainline/uspace/srv/vfs/vfs_mount.c@ 7f3e3e7

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

VFS work.
Increment reference counters for the VFS nodes representing the mount point and
the root of the mounted filesystem, respectively, during VFS_MOUNT. Take the
unlink_futex when transforming the triplet into a VFS node.

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