• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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