• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /****************************************************************************
2  * fs/mount/fs_mount.c
3  *
4  * Copyright (c) 2023 Huawei Device Co., Ltd. All rights reserved.
5  * Based on NuttX originally from nuttx source (nuttx/fs/ and nuttx/drivers/)
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * 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,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations 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 #ifdef LOSCFG_MNT_CONTAINER
53 #include "los_mnt_container_pri.h"
54 #endif
55 
56 /* At least one filesystem must be defined, or this file will not compile.
57  * It may be desire-able to make filesystems dynamically registered at
58  * some time in the future, but at present, this file needs to know about
59  * every configured filesystem.
60  */
61 
62 #ifdef CONFIG_FS_READABLE
63 
64 /****************************************************************************
65  * Pre-processor Definitions
66  ****************************************************************************/
67 /* Configuration ************************************************************/
68 /* In the canonical case, a file system is bound to a block driver.  However,
69  * some less typical cases a block driver is not required.  Examples are
70  * pseudo file systems (like BINFS or PROCFS) and MTD file systems (like NXFFS).
71  *
72  * These file systems all require block drivers:
73  */
74 
75 #define BLKDRVR_NOT_MOUNTED 2
76 
77 extern struct fsmap_t g_fsmap[];
78 LOS_HAL_TABLE_BEGIN(g_fsmap, fsmap);
79 
80 extern struct fsmap_t g_fsmap_end;
81 LOS_HAL_TABLE_END(g_fsmap_end, fsmap);
82 
83 /****************************************************************************
84  * Public Data
85  ****************************************************************************/
86 
87 /****************************************************************************
88  * Private Functions
89  ****************************************************************************/
90 
91 /****************************************************************************
92  * Name: mount_findfs
93  *
94  * Description:
95  *    find the specified filesystem
96  *
97  ****************************************************************************/
98 
mount_findfs(const char * filesystemtype)99 static const struct fsmap_t *mount_findfs(const char *filesystemtype)
100 {
101   struct fsmap_t *m = NULL;
102 
103   for (m = &g_fsmap[0]; m != &g_fsmap_end; ++m)
104     {
105       if (m->fs_filesystemtype &&
106           strcmp(filesystemtype, m->fs_filesystemtype) == 0)
107         {
108           return m;
109         }
110     }
111 
112   return (const struct fsmap_t *)NULL;
113 }
114 
115 
116 /****************************************************************************
117  * Public Functions
118  ****************************************************************************/
119 
120 /****************************************************************************
121  * Name: mount
122  *
123  * Description:
124  *   mount() attaches the filesystem specified by the 'source' block device
125  *   name into the root file system at the path specified by 'target.'
126  *
127  * Return:
128  *   Zero is returned on success; -1 is returned on an error and errno is
129  *   set appropriately:
130  *
131  *   EACCES A component of a path was not searchable or mounting a read-only
132  *      filesystem was attempted without giving the MS_RDONLY flag.
133  *   EBUSY 'source' is already  mounted.
134  *   EFAULT One of the pointer arguments points outside the user address
135  *      space.
136  *   EINVAL 'source' had an invalid superblock.
137  *   ENODEV 'filesystemtype' not configured
138  *   ENOENT A pathname was empty or had a nonexistent component.
139  *   ENOMEM Could not allocate a memory to copy filenames or data into.
140  *   ENOTBLK 'source' is not a block device
141  *
142  ****************************************************************************/
143 
mount(const char * source,const char * target,const char * filesystemtype,unsigned long mountflags,const void * data)144 int mount(const char *source, const char *target,
145           const char *filesystemtype, unsigned long mountflags,
146           const void *data)
147 {
148   int ret;
149   int errcode = 0;
150   struct Mount* mnt = NULL;
151   struct Vnode *device = NULL;
152   struct Vnode *mountpt_vnode = NULL;
153   const struct fsmap_t *fsmap = NULL;
154   const struct MountOps *mops = NULL;
155   LIST_HEAD *mount_list = NULL;
156 #ifdef LOSCFG_DRIVERS_MTD
157   mtd_partition *partition = NULL;
158 #endif
159 
160   if (filesystemtype == NULL)
161     {
162       errcode = -EINVAL;
163       goto errout;
164     }
165 
166   /* Verify required pointer arguments */
167 
168   DEBUGASSERT(target && filesystemtype);
169 
170   /* Find the specified filesystem.  Try the block driver file systems first */
171 
172   if ((fsmap = mount_findfs(filesystemtype)) == NULL || (fsmap->is_bdfs && !source))
173     {
174       PRINT_ERR("Failed to find file system %s\n", filesystemtype);
175       errcode = -ENODEV;
176       goto errout;
177     }
178 
179   mops = fsmap->fs_mops;
180 
181   if (fsmap->is_bdfs && source)
182     {
183       /* Make sure that a block driver argument was provided */
184 
185       DEBUGASSERT(source);
186 
187       /* Find the block driver */
188 
189       ret = find_blockdriver(source, mountflags, &device);
190       if (ret < 0)
191         {
192           PRINT_ERR("Failed to find block driver %s\n", source);
193           errcode = ret;
194           goto errout;
195         }
196     }
197 
198   VnodeHold();
199   ret = VnodeLookup(target, &mountpt_vnode, 0);
200 
201   /* The mount point must be an existed vnode. */
202 
203   if (ret != OK)
204     {
205       PRINT_ERR("Failed to find valid mountpoint %s\n", target);
206       errcode = -EINVAL;
207       goto errout_with_lock;
208     }
209   if (mountpt_vnode->flag & VNODE_FLAG_MOUNT_NEW)
210     {
211 #ifdef LOSCFG_MNT_CONTAINER
212       struct Mount *tMnt = NULL;
213       LOS_DL_LIST_FOR_EACH_ENTRY(tMnt, GetMountList(), struct Mount, mountList)
214         {
215           if (tMnt->vnodeCovered == mountpt_vnode)
216             {
217               PRINT_ERR("can't mount to %s, already mounted.\n", target);
218               errcode = -EINVAL;
219               goto errout_with_lock;
220             }
221         }
222 #else
223       PRINT_ERR("can't mount to %s, already mounted.\n", target);
224       errcode = -EINVAL;
225       goto errout_with_lock;
226 #endif
227     }
228 
229 #ifdef LOSCFG_MNT_CONTAINER
230     struct Mount *cacheMnt = NULL;
231     if (source != NULL)
232       {
233         LOS_DL_LIST_FOR_EACH_ENTRY(cacheMnt, GetMountCache(), struct Mount, mountList)
234           {
235             if (strcmp(cacheMnt->devName, source) == 0)
236               {
237                 struct Mount *newMnt = (struct Mount *)zalloc(sizeof(struct Mount));
238                 if (newMnt == NULL)
239                   {
240                     PRINT_ERR("New mount alloc failed no memory!\n");
241                     errcode = -EINVAL;
242                     goto errout;
243                   }
244                 *newMnt = *cacheMnt;
245                 LOS_ListTailInsert(GetMountList(), &(newMnt->mountList));
246                 cacheMnt->vnodeCovered->mntCount++;
247                 VnodeDrop();
248                 return OK;
249               }
250           }
251       }
252 #endif
253   /* Bind the block driver to an instance of the file system.  The file
254    * system returns a reference to some opaque, fs-dependent structure
255    * that encapsulates this binding.
256    */
257 
258   if (mops->Mount == NULL)
259     {
260       /* The filesystem does not support the bind operation ??? */
261 
262       PRINTK("ERROR: Filesystem does not support bind\n");
263       errcode = -ENOSYS;
264       goto errout_with_lock;
265     }
266 
267   /* Increment reference count for the reference we pass to the file system */
268 #ifdef LOSCFG_DRIVERS_MTD
269   if (fsmap->is_mtd_support && (device != NULL))
270     {
271       partition = (mtd_partition *)((struct drv_data *)device->data)->priv;
272       partition->mountpoint_name = (char *)zalloc(strlen(target) + 1);
273       if (partition->mountpoint_name == NULL)
274         {
275           errcode = -ENOMEM;
276           goto errout_with_lock;
277         }
278       (void)strncpy_s(partition->mountpoint_name, strlen(target) + 1, target, strlen(target));
279       partition->mountpoint_name[strlen(target)] = '\0';
280     }
281 #endif
282 
283   mnt = MountAlloc(mountpt_vnode, (struct MountOps*)mops);
284 
285 #ifdef LOSCFG_FS_ZPFS
286   if (strcmp(filesystemtype, ZPFS_NAME) == 0)
287     {
288       ret = ZpfsPrepare(source, target, mnt);
289       if (ret < 0)
290         {
291           errcode = ret;
292           goto errout_with_mountpt;
293         }
294     }
295 #endif
296 
297   mnt->mountFlags = mountflags;
298 
299   mountpt_vnode->useCount++;
300   ret = mops->Mount(mnt, device, data);
301   mountpt_vnode->useCount--;
302   if (ret != 0)
303     {
304       /* The vnode is unhappy with the blkdrvr for some reason.  Back out
305        * the count for the reference we failed to pass and exit with an
306        * error.
307        */
308 
309       PRINT_ERR("Bind method failed: %d\n", ret);
310       errcode = ret;
311 #ifdef LOSCFG_DRIVERS_MTD
312       if (fsmap->is_mtd_support && (device != NULL) && (partition != NULL))
313         {
314           free(partition->mountpoint_name);
315           partition->mountpoint_name = NULL;
316         }
317 #endif
318       goto errout_with_mountpt;
319     }
320   mnt->vnodeBeCovered->flag |= VNODE_FLAG_MOUNT_ORIGIN;
321   mnt->vnodeCovered->flag |= VNODE_FLAG_MOUNT_NEW;
322   mnt->vnodeCovered->filePath = strdup(mountpt_vnode->filePath);
323   mnt->vnodeDev = device;
324   mnt->ops = mops;
325   if (target && (strlen(target) != 0))
326     {
327       ret = strcpy_s(mnt->pathName, PATH_MAX, target);
328       if (ret != EOK)
329         {
330           PRINT_ERR("Failed to copy mount point pathname, errno %d\n", ret);
331         }
332     }
333 
334   if (source && (strlen(source) != 0))
335     {
336       ret = strcpy_s(mnt->devName, PATH_MAX, source);
337       if (ret != EOK)
338         {
339           PRINT_ERR("Failed to copy dev name, errno %d\n", ret);
340         }
341     }
342 
343   //* We have it, now populate it with driver specific information. */
344 
345   mount_list = GetMountList();
346   LOS_ListAdd(mount_list, &mnt->mountList);
347 
348 #ifdef LOSCFG_MNT_CONTAINER
349   if (source != NULL)
350     {
351       struct Mount *newMnt = (struct Mount *)zalloc(sizeof(struct Mount));
352       if (newMnt == NULL)
353         {
354           PRINT_ERR("New mount alloc failed no memory!\n");
355           errcode = -EINVAL;
356           goto errout;
357         }
358       *newMnt = *mnt;
359       LOS_ListTailInsert(GetMountCache(), &(newMnt->mountList));
360     }
361 #endif
362 
363   if (!strcmp("/", target))
364     {
365       ChangeRoot(mnt->vnodeCovered);
366     }
367 
368   VnodeDrop();
369 
370   /* We can release our reference to the blkdrver_vnode, if the filesystem
371    * wants to retain the blockdriver vnode (which it should), then it must
372    * have called vnode_addref().  There is one reference on mountpt_vnode
373    * that will persist until umount() is called.
374    */
375 
376   return OK;
377 
378   /* A lot of goto's!  But they make the error handling much simpler */
379 
380 errout_with_mountpt:
381   if (mnt)
382     {
383       free(mnt);
384     }
385 errout_with_lock:
386   VnodeDrop();
387 errout:
388   set_errno(-errcode);
389   return VFS_ERROR;
390 }
391 #endif /* CONFIG_FS_READABLE */
392