From 2db80ecb389176b53c77807567895470bb180a06 Mon Sep 17 00:00:00 2001 From: mucor Date: Wed, 11 Aug 2021 11:36:05 +0800 Subject: [PATCH] feat: vfs support sdcard hotplug close: #I44WH1 Signed-off-by: mucor --- drivers/block/disk/src/disk.c | 3 + fs/include/fs/mount.h | 2 + fs/vfs/BUILD.gn | 1 + fs/vfs/operation/vfs_force_umount.c | 391 ++++++++++++++++++++++++++++ 4 files changed, 397 insertions(+) create mode 100644 fs/vfs/operation/vfs_force_umount.c diff --git a/drivers/block/disk/src/disk.c b/drivers/block/disk/src/disk.c index 34f48d47..fc3eb01e 100644 --- a/drivers/block/disk/src/disk.c +++ b/drivers/block/disk/src/disk.c @@ -1422,10 +1422,13 @@ DISK_FIND_ERROR: INT32 los_disk_deinit(INT32 diskID) { + int ret; los_disk *disk = get_disk(diskID); if (disk == NULL) { return -EINVAL; } + ret = ForceUmountDev(disk->dev); + PRINTK("warning: %s lost, force umount ret = %d\n", disk->disk_name, ret); DISK_LOCK(&disk->disk_mutex); diff --git a/fs/include/fs/mount.h b/fs/include/fs/mount.h index 3ac08860..8f9460d7 100644 --- a/fs/include/fs/mount.h +++ b/fs/include/fs/mount.h @@ -45,6 +45,7 @@ struct Mount { const struct MountOps *ops; /* operations of mount */ struct Vnode *vnodeBeCovered; /* vnode we mounted on */ struct Vnode *vnodeCovered; /* syncer vnode */ + struct Vnode *vnodeDev; /* dev vnode */ LIST_HEAD vnodeList; /* list of vnodes */ int vnodeSize; /* size of vnode list */ LIST_HEAD activeVnodeList; /* list of active vnodes */ @@ -70,4 +71,5 @@ typedef int (*foreach_mountpoint_t)(const char *devpoint, struct Mount* MountAlloc(struct Vnode* vnode, struct MountOps* mop); LIST_HEAD* GetMountList(void); int foreach_mountpoint(foreach_mountpoint_t handler, void *arg); +int ForceUmountDev(struct Vnode *dev); #endif diff --git a/fs/vfs/BUILD.gn b/fs/vfs/BUILD.gn index 441b907a..1a3c48c1 100644 --- a/fs/vfs/BUILD.gn +++ b/fs/vfs/BUILD.gn @@ -41,6 +41,7 @@ kernel_module(module_name) { "operation/vfs_fallocate64.c", "operation/vfs_fcntl.c", "operation/vfs_file_mapping.c", + "operation/vfs_force_umount.c", "operation/vfs_init.c", "operation/vfs_other.c", "operation/vfs_preadv.c", diff --git a/fs/vfs/operation/vfs_force_umount.c b/fs/vfs/operation/vfs_force_umount.c new file mode 100644 index 00000000..609bee39 --- /dev/null +++ b/fs/vfs/operation/vfs_force_umount.c @@ -0,0 +1,391 @@ +/* + * Copyright (c) 2021-2021 Huawei Device Co., Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "fs/mount.h" +#include "fs/dirent_fs.h" +#include "fs/file.h" +#include "vnode.h" +#include "path_cache.h" + +/* vnode operations returns EIO */ +static int ErrorVopCreate (struct Vnode *parent, const char *name, int mode, struct Vnode **vnode) +{ + return -EIO; +} + +static int ErrorVopLookup (struct Vnode *parent, const char *name, int len, struct Vnode **vnode) +{ + return -EIO; +} + +static int ErrorVopOpen (struct Vnode *vnode, int fd, int mode, int flags) +{ + return -EIO; +} + +static int ErrorVopClose (struct Vnode *vnode) +{ + /* already closed at force umount, do nothing here */ + return OK; +} + +static int ErrorVopReclaim (struct Vnode *vnode) +{ + return -EIO; +} + +static int ErrorVopUnlink (struct Vnode *parent, struct Vnode *vnode, const char *fileName) +{ + return -EIO; +} + +static int ErrorVopRmdir (struct Vnode *parent, struct Vnode *vnode, const char *dirName) +{ + return -EIO; +} + +static int ErrorVopMkdir (struct Vnode *parent, const char *dirName, mode_t mode, struct Vnode **vnode) +{ + return -EIO; +} + +static int ErrorVopReaddir (struct Vnode *vnode, struct fs_dirent_s *dir) +{ + return -EIO; +} + +static int ErrorVopOpendir (struct Vnode *vnode, struct fs_dirent_s *dir) +{ + return -EIO; +} + +static int ErrorVopRewinddir (struct Vnode *vnode, struct fs_dirent_s *dir) +{ + return -EIO; +} + +static int ErrorVopClosedir (struct Vnode *vnode, struct fs_dirent_s *dir) +{ + /* already closed at force umount, do nothing here */ + return OK; +} + +static int ErrorVopGetattr (struct Vnode *vnode, struct stat *st) +{ + return -EIO; +} + +static int ErrorVopSetattr (struct Vnode *vnode, struct stat *st) +{ + return -EIO; +} + +static int ErrorVopChattr (struct Vnode *vnode, struct IATTR *attr) +{ + return -EIO; +} + +static int ErrorVopRename (struct Vnode *src, struct Vnode *dstParent, const char *srcName, const char *dstName) +{ + return -EIO; +} + +static int ErrorVopTruncate (struct Vnode *vnode, off_t len) +{ + return -EIO; +} + +static int ErrorVopTruncate64 (struct Vnode *vnode, off64_t len) +{ + return -EIO; +} + +static int ErrorVopFscheck (struct Vnode *vnode, struct fs_dirent_s *dir) +{ + return -EIO; +} + +static int ErrorVopLink (struct Vnode *src, struct Vnode *dstParent, struct Vnode **dst, const char *dstName) +{ + return -EIO; +} + +static int ErrorVopSymlink (struct Vnode *parentVnode, struct Vnode **newVnode, const char *path, const char *target) +{ + return -EIO; +} + +static ssize_t ErrorVopReadlink (struct Vnode *vnode, char *buffer, size_t bufLen) +{ + return -EIO; +} + +static struct VnodeOps g_errorVnodeOps = { + .Create = ErrorVopCreate, + .Lookup = ErrorVopLookup, + .Open = ErrorVopOpen, + .Close = ErrorVopClose, + .Reclaim = ErrorVopReclaim, + .Unlink = ErrorVopUnlink, + .Rmdir = ErrorVopRmdir, + .Mkdir = ErrorVopMkdir, + .Readdir = ErrorVopReaddir, + .Opendir = ErrorVopOpendir, + .Rewinddir = ErrorVopRewinddir, + .Closedir = ErrorVopClosedir, + .Getattr = ErrorVopGetattr, + .Setattr = ErrorVopSetattr, + .Chattr = ErrorVopChattr, + .Rename = ErrorVopRename, + .Truncate = ErrorVopTruncate, + .Truncate64 = ErrorVopTruncate64, + .Fscheck = ErrorVopFscheck, + .Link = ErrorVopLink, + .Symlink = ErrorVopSymlink, + .Readlink = ErrorVopReadlink, +}; + +/* file operations returns EIO */ +static int ErrorFopOpen (struct file *filep) +{ + return -EIO; +} + +static int ErrorFopClose (struct file *filep) +{ + /* already closed at force umount, do nothing here */ + return OK; +} + +static ssize_t ErrorFopRead (struct file *filep, char *buffer, size_t buflen) +{ + return -EIO; +} + +static ssize_t ErrorFopWrite (struct file *filep, const char *buffer, size_t buflen) +{ + return -EIO; +} + +static off_t ErrorFopSeek (struct file *filep, off_t offset, int whence) +{ + return -EIO; +} + +static int ErrorFopIoctl (struct file *filep, int cmd, unsigned long arg) +{ + return -EIO; +} + +static int ErrorFopMmap (struct file* filep, struct VmMapRegion *region) +{ + return -EIO; +} + +static int ErrorFopPoll (struct file *filep, poll_table *fds) +{ + return -EIO; +} + +static int ErrorFopStat (struct file *filep, struct stat* st) +{ + return -EIO; +} + +static int ErrorFopFallocate (struct file* filep, int mode, off_t offset, off_t len) +{ + return -EIO; +} + +static int ErrorFopFallocate64 (struct file *filep, int mode, off64_t offset, off64_t len) +{ + return -EIO; +} + +static int ErrorFopFsync (struct file *filep) +{ + return -EIO; +} + +static ssize_t ErrorFopReadpage (struct file *filep, char *buffer, size_t buflen) +{ + return -EIO; +} + +static int ErrorFopUnlink (struct Vnode *vnode) +{ + return -EIO; +} + +static struct file_operations_vfs g_errorFileOps = { + .open = ErrorFopOpen, + .close = ErrorFopClose, + .read = ErrorFopRead, + .write = ErrorFopWrite, + .seek = ErrorFopSeek, + .ioctl = ErrorFopIoctl, + .mmap = ErrorFopMmap, + .poll = ErrorFopPoll, + .stat = ErrorFopStat, + .fallocate = ErrorFopFallocate, + .fallocate64 = ErrorFopFallocate64, + .fsync = ErrorFopFsync, + .readpage = ErrorFopReadpage, + .unlink = ErrorFopUnlink, +}; + +static struct Mount* GetDevMountPoint(struct Vnode *dev) +{ + struct Mount *mnt = NULL; + LIST_HEAD *mntList = GetMountList(); + LOS_DL_LIST_FOR_EACH_ENTRY(mnt, mntList, struct Mount, mountList) { + if (mnt->vnodeDev == dev) { + return mnt; + } + } + return NULL; +} + +static void DirPreClose(struct fs_dirent_s *dirp) +{ + struct Vnode *node = NULL; + if (dirp == NULL || dirp->fd_root == NULL) { + return; + } + + node = dirp->fd_root; + if (node->vop && node->vop->Closedir) { + node->vop->Closedir(node, dirp); + } +} + +static void FilePreClose(struct file *filep, const struct file_operations_vfs *ops) +{ + if (filep->f_oflags & O_DIRECTORY) { + DirPreClose(filep->f_dir); + return; + } + + if (ops && ops->close) { + ops->close(filep); + } +} + +static void FileDisableAndClean(struct Mount *mnt) +{ + struct filelist *flist = &tg_filelist; + struct file *filep = NULL; + const struct file_operations_vfs *originOps; + + for (int i = 3; i < CONFIG_NFILE_DESCRIPTORS; i++) { + if (!get_bit(i)) { + continue; + } + filep = &flist->fl_files[i]; + if (filep == NULL || filep->f_vnode == NULL) { + continue; + } + if (filep->f_vnode->originMount != mnt) { + continue; + } + originOps = filep->ops; + filep->ops = &g_errorFileOps; + FilePreClose(filep, originOps); + } +} + +static void VnodeTryFree(struct Vnode *vnode) +{ + if (vnode->useCount == 0) { + VnodeFree(vnode); + return; + } + + VnodePathCacheFree(vnode); + LOS_ListDelete(&(vnode->hashEntry)); + LOS_ListDelete(&vnode->actFreeEntry); + + if (vnode->vop->Reclaim) { + vnode->vop->Reclaim(vnode); + } + vnode->vop = &g_errorVnodeOps; + vnode->fop = &g_errorFileOps; +} + +static void VnodeTryFreeAll(struct Mount *mount) +{ + struct Vnode *vnode = NULL; + struct Vnode *nextVnode = NULL; + + LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(vnode, nextVnode, GetVnodeActiveList(), struct Vnode, actFreeEntry) { + if ((vnode->originMount != mount) || (vnode->flag & VNODE_FLAG_MOUNT_NEW)) { + continue; + } + VnodeTryFree(vnode); + } +} + +int ForceUmountDev(struct Vnode *dev) +{ + int ret; + struct Vnode *origin; + struct filelist *flist = &tg_filelist; + if (dev == NULL) { + return -EINVAL; + } + + (void)sem_wait(&flist->fl_sem); + VnodeHold(); + + struct Mount *mnt = GetDevMountPoint(dev); + if (mnt == NULL) { + VnodeDrop(); + (void)sem_post(&flist->fl_sem); + return -ENXIO; + } + origin = mnt->vnodeBeCovered; + + FileDisableAndClean(mnt); + VnodeTryFreeAll(mnt); + ret = mnt->ops->Unmount(mnt, &dev); + if (ret != OK) { + PRINT_ERR("unmount in fs failed, ret = %d, errno = %d\n", ret, errno); + } + + LOS_ListDelete(&mnt->mountList); + free(mnt); + origin->newMount = NULL; + origin->flag &= ~(VNODE_FLAG_MOUNT_ORIGIN); + + VnodeDrop(); + (void)sem_post(&flist->fl_sem); + + return OK; +}