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