1 /****************************************************************************
2 * fs/mount/fs_umount.c
3 *
4 * Copyright (c) 2023 Huawei Device Co., Ltd. All rights reserved.
5 * Based on NuttX originally written by Gregory Nutt
6 *
7 * Copyright (C) 2007-2009, 2015 Gregory Nutt. All rights reserved.
8 * Author: Gregory Nutt <gnutt@nuttx.org>
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 *
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
19 * distribution.
20 * 3. Neither the name NuttX nor the names of its contributors may be
21 * used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
31 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
32 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 *
37 ****************************************************************************/
38
39 /****************************************************************************
40 * Included Files
41 ****************************************************************************/
42
43 #include "vfs_config.h"
44
45 #include "sys/mount.h"
46 #include "errno.h"
47 #include "vnode.h"
48 #include "stdlib.h"
49 #include "unistd.h"
50 #include "string.h"
51 #include "disk.h"
52 #include "fs/mount.h"
53 #ifdef LOSCFG_MNT_CONTAINER
54 #include "los_mnt_container_pri.h"
55 #endif
56
57 /****************************************************************************
58 * Public Functions
59 ****************************************************************************/
60
61 /****************************************************************************
62 * Name: umount
63 *
64 * Description:
65 * umount() detaches the filesystem mounted at the path specified by
66 * 'target.'
67 *
68 * Return:
69 * Zero is returned on success; -1 is returned on an error and errno is
70 * set appropriately:
71 *
72 * EACCES A component of a path was not searchable or mounting a read-only
73 * filesystem was attempted without giving the MS_RDONLY flag.
74 * EBUSY The target could not be unmounted because it is busy.
75 * EFAULT The pointer argument points outside the user address space.
76 *
77 ****************************************************************************/
78
fs_in_use(struct Mount * mnt,const char * target)79 BOOL fs_in_use(struct Mount *mnt, const char *target)
80 {
81 char cwd[PATH_MAX];
82 char *pret = getcwd(cwd, PATH_MAX);
83 if (pret != NULL)
84 {
85 if (!strncmp(target, cwd, strlen(target)))
86 {
87 return TRUE;
88 }
89 }
90 return VnodeInUseIter(mnt);
91 }
92
umount(const char * target)93 int umount(const char *target)
94 {
95 struct Vnode *mountpt_vnode = NULL;
96 struct Vnode *blkdrvr_vnode = NULL;
97 struct Vnode *covered_vnode = NULL;
98 struct Mount *mnt = NULL;
99 int ret;
100
101 /* Verify required pointer arguments */
102
103 if (target == NULL)
104 {
105 ret = -EFAULT;
106 goto errout;
107 }
108
109 /* Find the mountpt */
110 VnodeHold();
111 ret = VnodeLookup(target, &mountpt_vnode, 0);
112 if (ret != OK || !mountpt_vnode)
113 {
114 goto errout;
115 }
116 /* Verify that the vnode is a mountpoint */
117 if (!mountpt_vnode || !(mountpt_vnode->flag & VNODE_FLAG_MOUNT_NEW))
118 {
119 ret = -EINVAL;
120 goto errout;
121 }
122
123 #ifdef LOSCFG_MNT_CONTAINER
124 /* Verify that the vnode is a mountpoint */
125 struct Mount *tMnt = NULL;
126 bool found = false;
127 LOS_DL_LIST_FOR_EACH_ENTRY(tMnt, GetMountList(), struct Mount, mountList)
128 {
129 if (tMnt->vnodeCovered == mountpt_vnode)
130 {
131 found = true;
132 break;
133 }
134 }
135
136 if (!found)
137 {
138 ret = -EINVAL;
139 goto errout;
140 }
141
142 if (tMnt->vnodeCovered->mntCount > 0)
143 {
144 tMnt->vnodeCovered->mntCount--;
145 LOS_ListDelete(&tMnt->mountList);
146 free(tMnt);
147 VnodeDrop();
148 return OK;
149 }
150 #endif
151
152 /* Get mount point covered vnode and mount structure */
153 mnt = mountpt_vnode->originMount;
154 if (!mnt)
155 {
156 ret = -EINVAL;
157 goto errout;
158 }
159 covered_vnode = mnt->vnodeBeCovered;
160 if (!covered_vnode || !(covered_vnode->flag & VNODE_FLAG_MOUNT_ORIGIN))
161 {
162 ret = -EINVAL;
163 goto errout;
164 }
165
166 /* Unbind the block driver from the file system (destroying any fs
167 * private data.
168 */
169
170 if (mnt->ops == NULL || mnt->ops->Unmount == NULL)
171 {
172 /* The filesystem does not support the unbind operation ??? */
173
174 ret = -EINVAL;
175 goto errout;
176 }
177
178 /* Release the vnode under the mount point */
179 if (fs_in_use(mnt, target))
180 {
181 ret = -EBUSY;
182 goto errout;
183 }
184
185 ret = VnodeFreeAll(mnt);
186 if (ret != OK)
187 {
188 goto errout;
189 }
190 /* Umount the filesystem */
191 ret = mnt->ops->Unmount(mnt, &blkdrvr_vnode);
192 if (ret != OK)
193 {
194 goto errout;
195 }
196 #ifdef LOSCFG_MNT_CONTAINER
197 struct Mount *tCacheMnt = NULL;
198 LOS_DL_LIST_FOR_EACH_ENTRY(tCacheMnt, GetMountCache(), struct Mount, mountList)
199 {
200 if (tCacheMnt->vnodeCovered == mountpt_vnode)
201 {
202 LOS_ListDelete(&tCacheMnt->mountList);
203 free(tCacheMnt);
204 break;
205 }
206 }
207 #endif
208 VnodeFree(mountpt_vnode);
209 LOS_ListDelete(&mnt->mountList);
210
211 free(mnt);
212
213 /* Did the unbind method return a contained block driver */
214 if (blkdrvr_vnode)
215 {
216 ; /* block driver operations after umount */
217 }
218
219 covered_vnode->newMount = NULL;
220 #ifdef LOSCFG_MNT_CONTAINER
221 tCacheMnt = NULL;
222 found = false;
223 LOS_DL_LIST_FOR_EACH_ENTRY(tCacheMnt, GetMountCache(), struct Mount, mountList)
224 {
225 if (tCacheMnt->vnodeBeCovered == covered_vnode)
226 {
227 found = true;
228 break;
229 }
230 }
231 if (!found)
232 {
233 covered_vnode->flag &= ~(VNODE_FLAG_MOUNT_ORIGIN);
234 }
235 #else
236 covered_vnode->flag &= ~(VNODE_FLAG_MOUNT_ORIGIN);
237 #endif
238 VnodeDrop();
239
240 return OK;
241
242 /* A lot of goto's! But they make the error handling much simpler */
243 errout:
244 VnodeDrop();
245 set_errno(-ret);
246 return VFS_ERROR;
247 }
248
umount2(const char * __target,int __flags)249 int umount2(const char* __target, int __flags)
250 {
251 /* TODO: __flags need to be support */
252 if (__flags) {
253 set_errno(ENOSYS);
254 return VFS_ERROR;
255 }
256 return umount(__target);
257 }
258