1/*
2 * Copyright (c) 2021-2021 Huawei Device Co., Ltd. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification,
5 * are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice, this list of
8 *    conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 *    of conditions and the following disclaimer in the documentation and/or other materials
12 *    provided with the distribution.
13 *
14 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
15 *    to endorse or promote products derived from this software without specific prior written
16 *    permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
22 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
27 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
28 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include "fs/mount.h"
32#include "fs/dirent_fs.h"
33#include "fs/file.h"
34#include "vnode.h"
35#include "path_cache.h"
36
37/* vnode operations returns EIO */
38static int ErrorVopCreate(struct Vnode *parent, const char *name, int mode, struct Vnode **vnode)
39{
40    (void)parent;
41    (void)name;
42    (void)mode;
43    (void)vnode;
44    return -EIO;
45}
46
47static int ErrorVopLookup(struct Vnode *parent, const char *name, int len, struct Vnode **vnode)
48{
49    (void)parent;
50    (void)name;
51    (void)len;
52    (void)vnode;
53    return -EIO;
54}
55
56static int ErrorVopOpen(struct Vnode *vnode, int fd, int mode, int flags)
57{
58    (void)vnode;
59    (void)fd;
60    (void)mode;
61    (void)flags;
62    return -EIO;
63}
64
65static int ErrorVopClose(struct Vnode *vnode)
66{
67    (void)vnode;
68    /* already closed at force umount, do nothing here */
69    return OK;
70}
71
72static int ErrorVopReclaim(struct Vnode *vnode)
73{
74    (void)vnode;
75    return -EIO;
76}
77
78static int ErrorVopUnlink(struct Vnode *parent, struct Vnode *vnode, const char *fileName)
79{
80    (void)parent;
81    (void)vnode;
82    (void)fileName;
83    return -EIO;
84}
85
86static int ErrorVopRmdir(struct Vnode *parent, struct Vnode *vnode, const char *dirName)
87{
88    (void)parent;
89    (void)vnode;
90    (void)dirName;
91    return -EIO;
92}
93
94static int ErrorVopMkdir(struct Vnode *parent, const char *dirName, mode_t mode, struct Vnode **vnode)
95{
96    (void)parent;
97    (void)dirName;
98    (void)mode;
99    (void)vnode;
100    return -EIO;
101}
102
103static int ErrorVopReaddir(struct Vnode *vnode, struct fs_dirent_s *dir)
104{
105    (void)vnode;
106    (void)dir;
107    return -EIO;
108}
109
110static int ErrorVopOpendir(struct Vnode *vnode, struct fs_dirent_s *dir)
111{
112    (void)vnode;
113    (void)dir;
114    return -EIO;
115}
116
117static int ErrorVopRewinddir(struct Vnode *vnode, struct fs_dirent_s *dir)
118{
119    (void)vnode;
120    (void)dir;
121    return -EIO;
122}
123
124static int ErrorVopClosedir(struct Vnode *vnode, struct fs_dirent_s *dir)
125{
126    (void)vnode;
127    (void)dir;
128    /* already closed at force umount, do nothing here */
129    return OK;
130}
131
132static int ErrorVopGetattr(struct Vnode *vnode, struct stat *st)
133{
134    (void)vnode;
135    (void)st;
136    return -EIO;
137}
138
139static int ErrorVopSetattr(struct Vnode *vnode, struct stat *st)
140{
141    (void)vnode;
142    (void)st;
143    return -EIO;
144}
145
146static int ErrorVopChattr(struct Vnode *vnode, struct IATTR *attr)
147{
148    (void)vnode;
149    (void)attr;
150    return -EIO;
151}
152
153static int ErrorVopRename(struct Vnode *src, struct Vnode *dstParent, const char *srcName, const char *dstName)
154{
155    (void)src;
156    (void)dstParent;
157    (void)srcName;
158    (void)dstName;
159    return -EIO;
160}
161
162static int ErrorVopTruncate(struct Vnode *vnode, off_t len)
163{
164    (void)vnode;
165    (void)len;
166    return -EIO;
167}
168
169static int ErrorVopTruncate64(struct Vnode *vnode, off64_t len)
170{
171    (void)vnode;
172    (void)len;
173    return -EIO;
174}
175
176static int ErrorVopFscheck(struct Vnode *vnode, struct fs_dirent_s *dir)
177{
178    (void)vnode;
179    (void)dir;
180    return -EIO;
181}
182
183static int ErrorVopLink(struct Vnode *src, struct Vnode *dstParent, struct Vnode **dst, const char *dstName)
184{
185    (void)src;
186    (void)dstParent;
187    (void)dst;
188    (void)dstName;
189    return -EIO;
190}
191
192static int ErrorVopSymlink(struct Vnode *parentVnode, struct Vnode **newVnode, const char *path, const char *target)
193{
194    (void)parentVnode;
195    (void)newVnode;
196    (void)path;
197    (void)target;
198    return -EIO;
199}
200
201static ssize_t ErrorVopReadlink(struct Vnode *vnode, char *buffer, size_t bufLen)
202{
203    (void)vnode;
204    (void)buffer;
205    (void)bufLen;
206    return -EIO;
207}
208
209static struct VnodeOps g_errorVnodeOps = {
210    .Create = ErrorVopCreate,
211    .Lookup = ErrorVopLookup,
212    .Open = ErrorVopOpen,
213    .Close = ErrorVopClose,
214    .Reclaim = ErrorVopReclaim,
215    .Unlink = ErrorVopUnlink,
216    .Rmdir = ErrorVopRmdir,
217    .Mkdir = ErrorVopMkdir,
218    .Readdir = ErrorVopReaddir,
219    .Opendir = ErrorVopOpendir,
220    .Rewinddir = ErrorVopRewinddir,
221    .Closedir = ErrorVopClosedir,
222    .Getattr = ErrorVopGetattr,
223    .Setattr = ErrorVopSetattr,
224    .Chattr = ErrorVopChattr,
225    .Rename = ErrorVopRename,
226    .Truncate = ErrorVopTruncate,
227    .Truncate64 = ErrorVopTruncate64,
228    .Fscheck = ErrorVopFscheck,
229    .Link = ErrorVopLink,
230    .Symlink = ErrorVopSymlink,
231    .Readlink = ErrorVopReadlink,
232};
233
234/* file operations returns EIO */
235static int ErrorFopOpen(struct file *filep)
236{
237    (void)filep;
238    return -EIO;
239}
240
241static int ErrorFopClose(struct file *filep)
242{
243    (void)filep;
244    /* already closed at force umount, do nothing here */
245    return OK;
246}
247
248static ssize_t ErrorFopRead(struct file *filep, char *buffer, size_t buflen)
249{
250    (void)filep;
251    (void)buffer;
252    (void)buflen;
253    return -EIO;
254}
255
256static ssize_t ErrorFopWrite(struct file *filep, const char *buffer, size_t buflen)
257{
258    (void)filep;
259    (void)buffer;
260    (void)buflen;
261    return -EIO;
262}
263
264static off_t ErrorFopSeek(struct file *filep, off_t offset, int whence)
265{
266    (void)filep;
267    (void)offset;
268    (void)whence;
269    return -EIO;
270}
271
272static int ErrorFopIoctl(struct file *filep, int cmd, unsigned long arg)
273{
274    (void)filep;
275    (void)cmd;
276    (void)arg;
277    return -EIO;
278}
279
280static int ErrorFopMmap(struct file* filep, struct VmMapRegion *region)
281{
282    (void)filep;
283    (void)region;
284    return -EIO;
285}
286
287static int ErrorFopPoll(struct file *filep, poll_table *fds)
288{
289    (void)filep;
290    (void)fds;
291    return -EIO;
292}
293
294static int ErrorFopStat(struct file *filep, struct stat* st)
295{
296    (void)filep;
297    (void)st;
298    return -EIO;
299}
300
301static int ErrorFopFallocate(struct file* filep, int mode, off_t offset, off_t len)
302{
303    (void)filep;
304    (void)mode;
305    (void)offset;
306    (void)len;
307    return -EIO;
308}
309
310static int ErrorFopFallocate64(struct file *filep, int mode, off64_t offset, off64_t len)
311{
312    (void)filep;
313    (void)mode;
314    (void)offset;
315    (void)len;
316    return -EIO;
317}
318
319static int ErrorFopFsync(struct file *filep)
320{
321    (void)filep;
322    return -EIO;
323}
324
325static ssize_t ErrorFopReadpage(struct file *filep, char *buffer, size_t buflen)
326{
327    (void)filep;
328    (void)buffer;
329    (void)buflen;
330    return -EIO;
331}
332
333static int ErrorFopUnlink(struct Vnode *vnode)
334{
335    (void)vnode;
336    return -EIO;
337}
338
339static struct file_operations_vfs g_errorFileOps = {
340    .open = ErrorFopOpen,
341    .close = ErrorFopClose,
342    .read = ErrorFopRead,
343    .write = ErrorFopWrite,
344    .seek = ErrorFopSeek,
345    .ioctl = ErrorFopIoctl,
346    .mmap = ErrorFopMmap,
347    .poll = ErrorFopPoll,
348    .stat = ErrorFopStat,
349    .fallocate = ErrorFopFallocate,
350    .fallocate64 = ErrorFopFallocate64,
351    .fsync = ErrorFopFsync,
352    .readpage = ErrorFopReadpage,
353    .unlink = ErrorFopUnlink,
354};
355
356static struct Mount* GetDevMountPoint(const struct Vnode *dev)
357{
358    struct Mount *mnt = NULL;
359    LIST_HEAD *mntList = GetMountList();
360    if (mntList == NULL) {
361        return NULL;
362    }
363
364    LOS_DL_LIST_FOR_EACH_ENTRY(mnt, mntList, struct Mount, mountList) {
365        if (mnt->vnodeDev == dev) {
366            return mnt;
367        }
368    }
369    return NULL;
370}
371
372static void DirPreClose(struct fs_dirent_s *dirp)
373{
374    struct Vnode *node = NULL;
375    if (dirp == NULL || dirp->fd_root == NULL) {
376        return;
377    }
378
379    node = dirp->fd_root;
380    if (node->vop && node->vop->Closedir) {
381        node->vop->Closedir(node, dirp);
382    }
383}
384
385static void FilePreClose(struct file *filep, const struct file_operations_vfs *ops)
386{
387    if (filep->f_oflags & O_DIRECTORY) {
388        DirPreClose(filep->f_dir);
389        return;
390    }
391
392    if (ops && ops->close) {
393        ops->close(filep);
394    }
395}
396
397static void FileDisableAndClean(const struct Mount *mnt)
398{
399    struct filelist *flist = &tg_filelist;
400    struct file *filep = NULL;
401    const struct file_operations_vfs *originOps = NULL;
402
403    for (int i = 3; i < CONFIG_NFILE_DESCRIPTORS; i++) {
404        if (!get_bit(i)) {
405            continue;
406        }
407        filep = &flist->fl_files[i];
408        if (filep == NULL || filep->f_vnode == NULL) {
409            continue;
410        }
411        if (filep->f_vnode->originMount != mnt) {
412            continue;
413        }
414        originOps = filep->ops;
415        filep->ops = &g_errorFileOps;
416        FilePreClose(filep, originOps);
417    }
418}
419
420static void VnodeTryFree(struct Vnode *vnode)
421{
422    if (vnode->useCount == 0) {
423        VnodeFree(vnode);
424        return;
425    }
426
427    VnodePathCacheFree(vnode);
428    LOS_ListDelete(&(vnode->hashEntry));
429    LOS_ListDelete(&vnode->actFreeEntry);
430
431    if (vnode->vop->Reclaim) {
432        vnode->vop->Reclaim(vnode);
433    }
434    vnode->vop = &g_errorVnodeOps;
435    vnode->fop = &g_errorFileOps;
436}
437
438static void VnodeTryFreeAll(const struct Mount *mount)
439{
440    struct Vnode *vnode = NULL;
441    struct Vnode *nextVnode = NULL;
442
443    LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(vnode, nextVnode, GetVnodeActiveList(), struct Vnode, actFreeEntry) {
444        if ((vnode->originMount != mount) || (vnode->flag & VNODE_FLAG_MOUNT_NEW)) {
445            continue;
446        }
447        VnodeTryFree(vnode);
448    }
449}
450
451int ForceUmountDev(struct Vnode *dev)
452{
453    int ret;
454    struct Vnode *origin = NULL;
455    struct filelist *flist = &tg_filelist;
456    if (dev == NULL) {
457        return -EINVAL;
458    }
459
460    (void)sem_wait(&flist->fl_sem);
461    VnodeHold();
462
463    struct Mount *mnt = GetDevMountPoint(dev);
464    if (mnt == NULL) {
465        VnodeDrop();
466        (void)sem_post(&flist->fl_sem);
467        return -ENXIO;
468    }
469    origin = mnt->vnodeBeCovered;
470
471    FileDisableAndClean(mnt);
472    VnodeTryFreeAll(mnt);
473    ret = mnt->ops->Unmount(mnt, &dev);
474    if (ret != OK) {
475        PRINT_ERR("unmount in fs failed, ret = %d, errno = %d\n", ret, errno);
476    }
477
478    LOS_ListDelete(&mnt->mountList);
479    free(mnt);
480    origin->newMount = NULL;
481    origin->flag &= ~(VNODE_FLAG_MOUNT_ORIGIN);
482
483    VnodeDrop();
484    (void)sem_post(&flist->fl_sem);
485
486    return OK;
487}
488