source: mainline/uspace/srv/vfs/vfs_mount.c@ 36d852c

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

Rename IPC_M_DATA_SEND to IPC_M_DATA_WRITE. Now, when we also add
IPC_M_DATA_READ, it will not clash and cause confusion with userspace wrappers
such as ipc_data_receive(). Rename the forementioned wrappers to
ipc_data_write_send(), ipc_data_write_receive() and ipc_data_write_deliver().

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