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