• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /****************************************************************************
2  * fs/mount/fs_mount.c
3  *
4  * Licensed to the Apache Software Foundation (ASF) under one or more
5  * contributor license agreements.  See the NOTICE file distributed with
6  * this work for additional information regarding copyright ownership.  The
7  * ASF licenses this file to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance with the
9  * License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
16  * License for the specific language governing permissions and limitations
17  * under the License.
18  *
19  ****************************************************************************/
20 
21 /****************************************************************************
22  * Included Files
23  ****************************************************************************/
24 
25 #include "vfs_config.h"
26 
27 #include "sys/mount.h"
28 #include "string.h"
29 #include "errno.h"
30 #include "assert.h"
31 #include "vnode.h"
32 #include "stdlib.h"
33 #ifdef LOSCFG_DRIVERS_MTD
34 #include "mtd_partition.h"
35 #endif
36 #ifdef LOSCFG_FS_FAT_VIRTUAL_PARTITION
37 #include "errcode_fat.h"
38 #endif
39 #include "los_tables.h"
40 #ifdef LOSCFG_DRIVERS_RANDOM
41 #include "hisoc/random.h"
42 #else
43 #include "stdlib.h"
44 #endif
45 #include "path_cache.h"
46 #include "fs/mount.h"
47 #include "fs/driver.h"
48 #include "fs/fs.h"
49 #ifdef LOSCFG_FS_ZPFS
50 #include "zpfs.h"
51 #endif
52 
53 
54 /* At least one filesystem must be defined, or this file will not compile.
55  * It may be desire-able to make filesystems dynamically registered at
56  * some time in the future, but at present, this file needs to know about
57  * every configured filesystem.
58  */
59 
60 #ifdef CONFIG_FS_READABLE
61 
62 /****************************************************************************
63  * Pre-processor Definitions
64  ****************************************************************************/
65 /* Configuration ************************************************************/
66 /* In the canonical case, a file system is bound to a block driver.  However,
67  * some less typical cases a block driver is not required.  Examples are
68  * pseudo file systems (like BINFS or PROCFS) and MTD file systems (like NXFFS).
69  *
70  * These file systems all require block drivers:
71  */
72 
73 #define BLKDRVR_NOT_MOUNTED 2
74 
75 extern struct fsmap_t g_fsmap[];
76 LOS_HAL_TABLE_BEGIN(g_fsmap, fsmap);
77 
78 extern struct fsmap_t g_fsmap_end;
79 LOS_HAL_TABLE_END(g_fsmap_end, fsmap);
80 
81 /****************************************************************************
82  * Public Data
83  ****************************************************************************/
84 
85 /****************************************************************************
86  * Private Functions
87  ****************************************************************************/
88 
89 /****************************************************************************
90  * Name: mount_findfs
91  *
92  * Description:
93  *    find the specified filesystem
94  *
95  ****************************************************************************/
96 
mount_findfs(const char * filesystemtype)97 static const struct fsmap_t *mount_findfs(const char *filesystemtype)
98 {
99   struct fsmap_t *m = NULL;
100 
101   for (m = &g_fsmap[0]; m != &g_fsmap_end; ++m)
102     {
103       if (m->fs_filesystemtype &&
104           strcmp(filesystemtype, m->fs_filesystemtype) == 0)
105         {
106           return m;
107         }
108     }
109 
110   return (const struct fsmap_t *)NULL;
111 }
112 
113 
114 /****************************************************************************
115  * Public Functions
116  ****************************************************************************/
117 
118 /****************************************************************************
119  * Name: mount
120  *
121  * Description:
122  *   mount() attaches the filesystem specified by the 'source' block device
123  *   name into the root file system at the path specified by 'target.'
124  *
125  * Return:
126  *   Zero is returned on success; -1 is returned on an error and errno is
127  *   set appropriately:
128  *
129  *   EACCES A component of a path was not searchable or mounting a read-only
130  *      filesystem was attempted without giving the MS_RDONLY flag.
131  *   EBUSY 'source' is already  mounted.
132  *   EFAULT One of the pointer arguments points outside the user address
133  *      space.
134  *   EINVAL 'source' had an invalid superblock.
135  *   ENODEV 'filesystemtype' not configured
136  *   ENOENT A pathname was empty or had a nonexistent component.
137  *   ENOMEM Could not allocate a memory to copy filenames or data into.
138  *   ENOTBLK 'source' is not a block device
139  *
140  ****************************************************************************/
141 
mount(const char * source,const char * target,const char * filesystemtype,unsigned long mountflags,const void * data)142 int mount(const char *source, const char *target,
143           const char *filesystemtype, unsigned long mountflags,
144           const void *data)
145 {
146   int ret;
147   int errcode = 0;
148   struct Mount* mnt = NULL;
149   struct Vnode *device = NULL;
150   struct Vnode *mountpt_vnode = NULL;
151   const struct fsmap_t *fsmap = NULL;
152   const struct MountOps *mops = NULL;
153   LIST_HEAD *mount_list = NULL;
154 #ifdef LOSCFG_DRIVERS_MTD
155   mtd_partition *partition = NULL;
156 #endif
157 
158   if (filesystemtype == NULL)
159     {
160       errcode = -EINVAL;
161       goto errout;
162     }
163 
164   /* Verify required pointer arguments */
165 
166   DEBUGASSERT(target && filesystemtype);
167 
168   /* Find the specified filesystem.  Try the block driver file systems first */
169 
170   if ((fsmap = mount_findfs(filesystemtype)) == NULL || (fsmap->is_bdfs && !source))
171     {
172       PRINT_ERR("Failed to find file system %s\n", filesystemtype);
173       errcode = -ENODEV;
174       goto errout;
175     }
176 
177   mops = fsmap->fs_mops;
178 
179   if (fsmap->is_bdfs && source)
180     {
181       /* Make sure that a block driver argument was provided */
182 
183       DEBUGASSERT(source);
184 
185       /* Find the block driver */
186 
187       ret = find_blockdriver(source, mountflags, &device);
188       if (ret < 0)
189         {
190           PRINT_ERR("Failed to find block driver %s\n", source);
191           errcode = ret;
192           goto errout;
193         }
194     }
195 
196   VnodeHold();
197   ret = VnodeLookup(target, &mountpt_vnode, 0);
198 
199   /* The mount point must be an existed vnode. */
200 
201   if (ret != OK)
202     {
203       PRINT_ERR("Failed to find valid mountpoint %s\n", target);
204       errcode = -EINVAL;
205       goto errout_with_lock;
206     }
207   if (mountpt_vnode->flag & VNODE_FLAG_MOUNT_NEW)
208     {
209       PRINT_ERR("can't mount to %s, already mounted.\n", target);
210       errcode = -EINVAL;
211       goto errout_with_lock;
212     }
213 
214   /* Bind the block driver to an instance of the file system.  The file
215    * system returns a reference to some opaque, fs-dependent structure
216    * that encapsulates this binding.
217    */
218 
219   if (mops->Mount == NULL)
220     {
221       /* The filesystem does not support the bind operation ??? */
222 
223       PRINTK("ERROR: Filesystem does not support bind\n");
224       errcode = -ENOSYS;
225       goto errout_with_lock;
226     }
227 
228   /* Increment reference count for the reference we pass to the file system */
229 #ifdef LOSCFG_DRIVERS_MTD
230   if (fsmap->is_mtd_support && (device != NULL))
231     {
232       partition = (mtd_partition *)((struct drv_data *)device->data)->priv;
233       partition->mountpoint_name = (char *)zalloc(strlen(target) + 1);
234       if (partition->mountpoint_name == NULL)
235         {
236           errcode = -ENOMEM;
237           goto errout_with_lock;
238         }
239       (void)strncpy_s(partition->mountpoint_name, strlen(target) + 1, target, strlen(target));
240       partition->mountpoint_name[strlen(target)] = '\0';
241     }
242 #endif
243 
244   mnt = MountAlloc(mountpt_vnode, (struct MountOps*)mops);
245 
246 #ifdef LOSCFG_FS_ZPFS
247   if (strcmp(filesystemtype, ZPFS_NAME) == 0)
248     {
249       ret = ZpfsPrepare(source, target, mnt);
250       if (ret < 0)
251         {
252           errcode = ret;
253           goto errout_with_mountpt;
254         }
255     }
256 #endif
257 
258   mnt->mountFlags = mountflags;
259 
260   mountpt_vnode->useCount++;
261   ret = mops->Mount(mnt, device, data);
262   mountpt_vnode->useCount--;
263   if (ret != 0)
264     {
265       /* The vnode is unhappy with the blkdrvr for some reason.  Back out
266        * the count for the reference we failed to pass and exit with an
267        * error.
268        */
269 
270       PRINT_ERR("Bind method failed: %d\n", ret);
271       errcode = ret;
272 #ifdef LOSCFG_DRIVERS_MTD
273       if (fsmap->is_mtd_support && (device != NULL) && (partition != NULL))
274         {
275           free(partition->mountpoint_name);
276           partition->mountpoint_name = NULL;
277         }
278 #endif
279       goto errout_with_mountpt;
280     }
281   mnt->vnodeBeCovered->flag |= VNODE_FLAG_MOUNT_ORIGIN;
282   mnt->vnodeCovered->flag |= VNODE_FLAG_MOUNT_NEW;
283   mnt->vnodeCovered->filePath = strdup(mountpt_vnode->filePath);
284   mnt->vnodeDev = device;
285   mnt->ops = mops;
286   if (target && (strlen(target) != 0))
287     {
288       ret = strcpy_s(mnt->pathName, PATH_MAX, target);
289       if (ret != EOK)
290         {
291           PRINT_ERR("Failed to copy mount point pathname, errno %d\n", ret);
292         }
293     }
294 
295   if (source && (strlen(source) != 0))
296     {
297       ret = strcpy_s(mnt->devName, PATH_MAX, source);
298       if (ret != EOK)
299         {
300           PRINT_ERR("Failed to copy dev name, errno %d\n", ret);
301         }
302     }
303 
304   //* We have it, now populate it with driver specific information. */
305 
306   mount_list = GetMountList();
307   LOS_ListAdd(mount_list, &mnt->mountList);
308 
309   if (!strcmp("/", target))
310     {
311       ChangeRoot(mnt->vnodeCovered);
312     }
313 
314   VnodeDrop();
315 
316   /* We can release our reference to the blkdrver_vnode, if the filesystem
317    * wants to retain the blockdriver vnode (which it should), then it must
318    * have called vnode_addref().  There is one reference on mountpt_vnode
319    * that will persist until umount() is called.
320    */
321 
322   return OK;
323 
324   /* A lot of goto's!  But they make the error handling much simpler */
325 
326 errout_with_mountpt:
327   if (mnt)
328     {
329       free(mnt);
330     }
331 errout_with_lock:
332   VnodeDrop();
333 errout:
334   set_errno(-errcode);
335   return VFS_ERROR;
336 }
337 #endif /* CONFIG_FS_READABLE */
338