1 /****************************************************************************
2 * fs/mount/fs_mount.c
3 *
4 * Copyright (C) 2007-2009, 2011-2013, 2015, 2017-2019 Gregory Nutt. All
5 * rights reserved.
6 * Author: Gregory Nutt <gnutt@nuttx.org>
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 * 3. Neither the name NuttX nor the names of its contributors may be
19 * used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
29 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 ****************************************************************************/
36
37 /****************************************************************************
38 * Included Files
39 ****************************************************************************/
40
41 #include "vfs_config.h"
42
43 #include "sys/mount.h"
44 #include "string.h"
45 #include "errno.h"
46 #include "assert.h"
47 #include "vnode.h"
48 #include "stdlib.h"
49 #ifdef LOSCFG_DRIVERS_MTD
50 #include "mtd_partition.h"
51 #endif
52 #ifdef LOSCFG_FS_FAT_VIRTUAL_PARTITION
53 #include "errcode_fat.h"
54 #endif
55 #include "los_tables.h"
56 #ifdef LOSCFG_DRIVERS_RANDOM
57 #include "hisoc/random.h"
58 #else
59 #include "stdlib.h"
60 #endif
61 #include "path_cache.h"
62 #include "fs/mount.h"
63 #include "fs/driver.h"
64 #include "fs/fs.h"
65 #ifdef LOSCFG_FS_ZPFS
66 #include "zpfs.h"
67 #endif
68
69
70 /* At least one filesystem must be defined, or this file will not compile.
71 * It may be desire-able to make filesystems dynamically registered at
72 * some time in the future, but at present, this file needs to know about
73 * every configured filesystem.
74 */
75
76 #ifdef CONFIG_FS_READABLE
77
78 /****************************************************************************
79 * Pre-processor Definitions
80 ****************************************************************************/
81 /* Configuration ************************************************************/
82 /* In the canonical case, a file system is bound to a block driver. However,
83 * some less typical cases a block driver is not required. Examples are
84 * pseudo file systems (like BINFS or PROCFS) and MTD file systems (like NXFFS).
85 *
86 * These file systems all require block drivers:
87 */
88
89 #define BLKDRVR_NOT_MOUNTED 2
90
91 extern struct fsmap_t g_fsmap[];
92 LOS_HAL_TABLE_BEGIN(g_fsmap, fsmap);
93
94 extern struct fsmap_t g_fsmap_end;
95 LOS_HAL_TABLE_END(g_fsmap_end, fsmap);
96
97 /****************************************************************************
98 * Public Data
99 ****************************************************************************/
100
101 /****************************************************************************
102 * Private Functions
103 ****************************************************************************/
104
105 /****************************************************************************
106 * Name: mount_findfs
107 *
108 * Description:
109 * find the specified filesystem
110 *
111 ****************************************************************************/
112
mount_findfs(const char * filesystemtype)113 static const struct fsmap_t *mount_findfs(const char *filesystemtype)
114 {
115 struct fsmap_t *m = NULL;
116
117 for (m = &g_fsmap[0]; m != &g_fsmap_end; ++m)
118 {
119 if (m->fs_filesystemtype &&
120 strcmp(filesystemtype, m->fs_filesystemtype) == 0)
121 {
122 return m;
123 }
124 }
125
126 return (const struct fsmap_t *)NULL;
127 }
128
129
130 /****************************************************************************
131 * Public Functions
132 ****************************************************************************/
133
134 /****************************************************************************
135 * Name: mount
136 *
137 * Description:
138 * mount() attaches the filesystem specified by the 'source' block device
139 * name into the root file system at the path specified by 'target.'
140 *
141 * Return:
142 * Zero is returned on success; -1 is returned on an error and errno is
143 * set appropriately:
144 *
145 * EACCES A component of a path was not searchable or mounting a read-only
146 * filesystem was attempted without giving the MS_RDONLY flag.
147 * EBUSY 'source' is already mounted.
148 * EFAULT One of the pointer arguments points outside the user address
149 * space.
150 * EINVAL 'source' had an invalid superblock.
151 * ENODEV 'filesystemtype' not configured
152 * ENOENT A pathname was empty or had a nonexistent component.
153 * ENOMEM Could not allocate a memory to copy filenames or data into.
154 * ENOTBLK 'source' is not a block device
155 *
156 ****************************************************************************/
157
mount(const char * source,const char * target,const char * filesystemtype,unsigned long mountflags,const void * data)158 int mount(const char *source, const char *target,
159 const char *filesystemtype, unsigned long mountflags,
160 const void *data)
161 {
162 int ret;
163 int errcode = 0;
164 struct Mount* mnt = NULL;
165 struct Vnode *device = NULL;
166 struct Vnode *mountpt_vnode = NULL;
167 const struct fsmap_t *fsmap = NULL;
168 const struct MountOps *mops = NULL;
169 LIST_HEAD *mount_list = NULL;
170 #ifdef LOSCFG_DRIVERS_MTD
171 mtd_partition *partition = NULL;
172 #endif
173
174 if (filesystemtype == NULL)
175 {
176 errcode = -EINVAL;
177 goto errout;
178 }
179
180 /* Verify required pointer arguments */
181
182 DEBUGASSERT(target && filesystemtype);
183
184 /* Find the specified filesystem. Try the block driver file systems first */
185
186 if ((fsmap = mount_findfs(filesystemtype)) == NULL || (fsmap->is_bdfs && !source))
187 {
188 PRINT_ERR("Failed to find file system %s\n", filesystemtype);
189 errcode = -ENODEV;
190 goto errout;
191 }
192
193 mops = fsmap->fs_mops;
194
195 if (fsmap->is_bdfs && source)
196 {
197 /* Make sure that a block driver argument was provided */
198
199 DEBUGASSERT(source);
200
201 /* Find the block driver */
202
203 ret = find_blockdriver(source, mountflags, &device);
204 if (ret < 0)
205 {
206 PRINT_ERR("Failed to find block driver %s\n", source);
207 errcode = ret;
208 goto errout;
209 }
210 }
211
212 VnodeHold();
213 ret = VnodeLookup(target, &mountpt_vnode, 0);
214
215 /* The mount point must be an existed vnode. */
216
217 if (ret != OK)
218 {
219 PRINT_ERR("Failed to find valid mountpoint %s\n", target);
220 errcode = -EINVAL;
221 goto errout_with_lock;
222 }
223 if (mountpt_vnode->flag & VNODE_FLAG_MOUNT_NEW)
224 {
225 PRINT_ERR("can't mount to %s, already mounted.\n", target);
226 errcode = -EINVAL;
227 goto errout_with_lock;
228 }
229
230 /* Bind the block driver to an instance of the file system. The file
231 * system returns a reference to some opaque, fs-dependent structure
232 * that encapsulates this binding.
233 */
234
235 if (mops->Mount == NULL)
236 {
237 /* The filesystem does not support the bind operation ??? */
238
239 PRINTK("ERROR: Filesystem does not support bind\n");
240 errcode = -ENOSYS;
241 goto errout_with_lock;
242 }
243
244 /* Increment reference count for the reference we pass to the file system */
245 #ifdef LOSCFG_DRIVERS_MTD
246 if (fsmap->is_mtd_support && (device != NULL))
247 {
248 partition = (mtd_partition *)((struct drv_data *)device->data)->priv;
249 partition->mountpoint_name = (char *)zalloc(strlen(target) + 1);
250 if (partition->mountpoint_name == NULL)
251 {
252 errcode = -ENOMEM;
253 goto errout_with_lock;
254 }
255 (void)strncpy_s(partition->mountpoint_name, strlen(target) + 1, target, strlen(target));
256 partition->mountpoint_name[strlen(target)] = '\0';
257 }
258 #endif
259
260 mnt = MountAlloc(mountpt_vnode, (struct MountOps*)mops);
261
262 #ifdef LOSCFG_FS_ZPFS
263 if (strcmp(filesystemtype, ZPFS_NAME) == 0)
264 {
265 ret = ZpfsPrepare(source, target, mnt);
266 if (ret < 0)
267 {
268 errcode = ret;
269 goto errout_with_mountpt;
270 }
271 }
272 #endif
273
274 mnt->mountFlags = mountflags;
275
276 mountpt_vnode->useCount++;
277 ret = mops->Mount(mnt, device, data);
278 mountpt_vnode->useCount--;
279 if (ret != 0)
280 {
281 /* The vnode is unhappy with the blkdrvr for some reason. Back out
282 * the count for the reference we failed to pass and exit with an
283 * error.
284 */
285
286 PRINT_ERR("Bind method failed: %d\n", ret);
287 errcode = ret;
288 #ifdef LOSCFG_DRIVERS_MTD
289 if (fsmap->is_mtd_support && (device != NULL) && (partition != NULL))
290 {
291 free(partition->mountpoint_name);
292 partition->mountpoint_name = NULL;
293 }
294 #endif
295 goto errout_with_mountpt;
296 }
297 mnt->vnodeBeCovered->flag |= VNODE_FLAG_MOUNT_ORIGIN;
298 mnt->vnodeCovered->flag |= VNODE_FLAG_MOUNT_NEW;
299 mnt->vnodeCovered->filePath = strdup(mountpt_vnode->filePath);
300 mnt->vnodeDev = device;
301 mnt->ops = mops;
302 if (target && (strlen(target) != 0))
303 {
304 ret = strcpy_s(mnt->pathName, PATH_MAX, target);
305 if (ret != EOK)
306 {
307 PRINT_ERR("Failed to copy mount point pathname, errno %d\n", ret);
308 }
309 }
310
311 if (source && (strlen(source) != 0))
312 {
313 ret = strcpy_s(mnt->devName, PATH_MAX, source);
314 if (ret != EOK)
315 {
316 PRINT_ERR("Failed to copy dev name, errno %d\n", ret);
317 }
318 }
319
320 //* We have it, now populate it with driver specific information. */
321
322 mount_list = GetMountList();
323 LOS_ListAdd(mount_list, &mnt->mountList);
324
325 if (!strcmp("/", target))
326 {
327 ChangeRoot(mnt->vnodeCovered);
328 }
329
330 VnodeDrop();
331
332 /* We can release our reference to the blkdrver_vnode, if the filesystem
333 * wants to retain the blockdriver vnode (which it should), then it must
334 * have called vnode_addref(). There is one reference on mountpt_vnode
335 * that will persist until umount() is called.
336 */
337
338 return OK;
339
340 /* A lot of goto's! But they make the error handling much simpler */
341
342 errout_with_mountpt:
343 if (mnt)
344 {
345 free(mnt);
346 }
347 errout_with_lock:
348 VnodeDrop();
349 errout:
350 set_errno(-errcode);
351 return VFS_ERROR;
352 }
353 #endif /* CONFIG_FS_READABLE */
354