From 4842e2d6740bcb81da4e94019285bfd2c45425b8 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 14 Jul 2012 13:07:22 +0800 Subject: [PATCH] Kernel/VFS - Added unmount support --- KernelLand/Kernel/include/errno.h | 1 + KernelLand/Kernel/include/vfs_ext.h | 13 +++ KernelLand/Kernel/include/vfs_int.h | 5 ++ KernelLand/Kernel/vfs/dir.c | 12 ++- KernelLand/Kernel/vfs/fs/devfs.c | 8 +- KernelLand/Kernel/vfs/fs/root.c | 23 +++-- KernelLand/Kernel/vfs/handle.c | 3 + KernelLand/Kernel/vfs/mount.c | 130 ++++++++++++++++++++++++++-- KernelLand/Kernel/vfs/open.c | 22 ++++- 9 files changed, 193 insertions(+), 24 deletions(-) diff --git a/KernelLand/Kernel/include/errno.h b/KernelLand/Kernel/include/errno.h index 3652f19f..7c2e97ab 100644 --- a/KernelLand/Kernel/include/errno.h +++ b/KernelLand/Kernel/include/errno.h @@ -13,6 +13,7 @@ enum eErrorNums EINVAL, // Invalid Paramater ENOMEM, // No free memory EACCES, // Not permitted + EBUSY, // Resource is busy ENOTFOUND, // Item not found EREADONLY, // Read only ENOTIMPL, // Not implemented diff --git a/KernelLand/Kernel/include/vfs_ext.h b/KernelLand/Kernel/include/vfs_ext.h index df68c4c5..8cabfa18 100644 --- a/KernelLand/Kernel/include/vfs_ext.h +++ b/KernelLand/Kernel/include/vfs_ext.h @@ -338,6 +338,19 @@ extern char *VFS_GetTruePath(const char *Path); * \return 1 on succes, -1 on error */ extern int VFS_Mount(const char *Device, const char *MountPoint, const char *Filesystem, const char *Options); +/** + * \brief Unmount a mounted filesystem + * \param Mountpoint Location of the mount + * \return 0 on success, errno on error + */ +extern int VFS_Unmount(const char *Mountpoint); +/** + * \brief Attemt to unmount all fileystems + * \return Number of unmounted filesytems, -1 if none left to unmount + * \note Can return 0 when there are stil volumes mounted if there are open handles + */ +extern int VFS_UnmountAll(void); + /** * \brief Create a new directory * \param Path Path to new directory (absolute or relative) diff --git a/KernelLand/Kernel/include/vfs_int.h b/KernelLand/Kernel/include/vfs_int.h index a8eadb6d..f48e277b 100644 --- a/KernelLand/Kernel/include/vfs_int.h +++ b/KernelLand/Kernel/include/vfs_int.h @@ -5,6 +5,7 @@ #define _VFS_INT_H #include "vfs.h" +#include // === TYPES === typedef struct sVFS_Mount { @@ -16,6 +17,9 @@ typedef struct sVFS_Mount { char *Options; tVFS_Driver *Filesystem; tVFS_Node *RootNode; + + int OpenHandleCount; + char StrData[]; } tVFS_Mount; @@ -42,6 +46,7 @@ typedef struct sVFS_MMapPage { } tVFS_MMapPage; // === GLOBALS === +extern tRWLock glVFS_MountList; extern tVFS_Mount *gVFS_Mounts; // === PROTOTYPES === diff --git a/KernelLand/Kernel/vfs/dir.c b/KernelLand/Kernel/vfs/dir.c index e2b124dc..fcf361ec 100644 --- a/KernelLand/Kernel/vfs/dir.c +++ b/KernelLand/Kernel/vfs/dir.c @@ -36,6 +36,7 @@ int VFS_MkDir(const char *Path) */ int VFS_MkNod(const char *Path, Uint Flags) { + tVFS_Mount *mountpt; char *absPath, *name; int pos = 0, oldpos = 0; int next = 0; @@ -60,9 +61,9 @@ int VFS_MkNod(const char *Path, Uint Flags) // Check for root if(absPath[0] == '\0') - parent = VFS_ParsePath("/", NULL, NULL); + parent = VFS_ParsePath("/", NULL, &mountpt); else - parent = VFS_ParsePath(absPath, NULL, NULL); + parent = VFS_ParsePath(absPath, NULL, &mountpt); LOG("parent = %p", parent); @@ -70,10 +71,11 @@ int VFS_MkNod(const char *Path, Uint Flags) LEAVE('i', -1); return -1; // Error Check } - + // Permissions Check if( !VFS_CheckACL(parent, VFS_PERM_EXECUTE|VFS_PERM_WRITE) ) { _CloseNode(parent); + mountpt->OpenHandleCount --; free(absPath); LEAVE('i', -1); return -1; @@ -82,7 +84,8 @@ int VFS_MkNod(const char *Path, Uint Flags) LOG("parent = %p", parent); if(!parent->Type || !parent->Type->MkNod) { - Warning("VFS_MkNod - Directory has no MkNod method"); + Log_Warning("VFS", "VFS_MkNod - Directory has no MkNod method"); + mountpt->OpenHandleCount --; LEAVE('i', -1); return -1; } @@ -94,6 +97,7 @@ int VFS_MkNod(const char *Path, Uint Flags) free(absPath); // Free Parent + mountpt->OpenHandleCount --; _CloseNode(parent); // Error Check diff --git a/KernelLand/Kernel/vfs/fs/devfs.c b/KernelLand/Kernel/vfs/fs/devfs.c index 13552260..354f4020 100644 --- a/KernelLand/Kernel/vfs/fs/devfs.c +++ b/KernelLand/Kernel/vfs/fs/devfs.c @@ -14,12 +14,13 @@ void DevFS_DelDevice(tDevFS_Driver *Device); #endif tVFS_Node *DevFS_InitDevice(const char *Device, const char **Options); +void DevFS_Unmount(tVFS_Node *RootNode); char *DevFS_ReadDir(tVFS_Node *Node, int Pos); tVFS_Node *DevFS_FindDir(tVFS_Node *Node, const char *Name); // === GLOBALS === tVFS_Driver gDevFS_Info = { - "devfs", 0, DevFS_InitDevice, NULL, NULL + "devfs", 0, DevFS_InitDevice, DevFS_Unmount, NULL }; tVFS_NodeType gDevFS_DirType = { .TypeName = "DevFS-Dir", @@ -117,6 +118,11 @@ tVFS_Node *DevFS_InitDevice(const char *Device, const char **Options) return &gDevFS_RootNode; } +void DevFS_Unmount(tVFS_Node *RootNode) +{ + +} + /** * \fn char *DevFS_ReadDir(tVFS_Node *Node, int Pos) */ diff --git a/KernelLand/Kernel/vfs/fs/root.c b/KernelLand/Kernel/vfs/fs/root.c index 00829edf..4416750c 100644 --- a/KernelLand/Kernel/vfs/fs/root.c +++ b/KernelLand/Kernel/vfs/fs/root.c @@ -60,7 +60,9 @@ tVFS_Node *Root_InitDevice(const char *Device, const char **Options) // Create Root Node root = &RootFS_Files[0]; - + + root->Name[0] = '/'; + root->Name[1] = '\0'; root->Node.ImplPtr = root; root->Node.CTime @@ -82,11 +84,11 @@ int Root_MkNod(tVFS_Node *Node, const char *Name, Uint Flags) { tRamFS_File *parent = Node->ImplPtr; tRamFS_File *child; - tRamFS_File *prev = (tRamFS_File *) &parent->Data.FirstChild; + tRamFS_File *prev = NULL; ENTER("pNode sName xFlags", Node, Name, Flags); - LOG("%i > %i", strlen(Name)+1, sizeof(child->Name)); + LOG("Sanity check name length - %i > %i", strlen(Name)+1, sizeof(child->Name)); if(strlen(Name) + 1 > sizeof(child->Name)) LEAVE_RET('i', 0); @@ -94,6 +96,7 @@ int Root_MkNod(tVFS_Node *Node, const char *Name, Uint Flags) for( child = parent->Data.FirstChild; child; prev = child, child = child->Next ) { if(strcmp(child->Name, Name) == 0) { + LOG("Duplicate"); LEAVE('i', 0); return 0; } @@ -103,6 +106,7 @@ int Root_MkNod(tVFS_Node *Node, const char *Name, Uint Flags) memset(child, 0, sizeof(tRamFS_File)); strcpy(child->Name, Name); + LOG("Name = '%s'", child->Name); child->Parent = parent; child->Next = NULL; @@ -125,7 +129,11 @@ int Root_MkNod(tVFS_Node *Node, const char *Name, Uint Flags) child->Node.Type = &gRootFS_FileType; } - prev->Next = child; + // Append! + if( prev ) + prev->Next = child; + else + parent->Data.FirstChild = child; parent->Node.Size ++; @@ -143,13 +151,12 @@ tVFS_Node *Root_FindDir(tVFS_Node *Node, const char *Name) tRamFS_File *child = parent->Data.FirstChild; ENTER("pNode sName", Node, Name); - //Log("Root_FindDir: (Node=%p, Name='%s')", Node, Name); - for(;child;child = child->Next) + for( child = parent->Data.FirstChild; child; child = child->Next ) { - //Log(" Root_FindDir: strcmp('%s', '%s')", child->Node.Name, Name); LOG("child->Name = '%s'", child->Name); - if(strcmp(child->Name, Name) == 0) { + if(strcmp(child->Name, Name) == 0) + { LEAVE('p', &child->Node); return &child->Node; } diff --git a/KernelLand/Kernel/vfs/handle.c b/KernelLand/Kernel/vfs/handle.c index d22f9656..6d2b83fb 100644 --- a/KernelLand/Kernel/vfs/handle.c +++ b/KernelLand/Kernel/vfs/handle.c @@ -198,6 +198,7 @@ void *VFS_SaveHandles(int NumFDs, int *FDs) continue ; if( h->Node->Type && h->Node->Type->Reference ) h->Node->Type->Reference( h->Node ); + h->Mount->OpenHandleCount ++; } return ret; @@ -244,6 +245,7 @@ void VFS_RestoreHandles(int NumFDs, void *Handles) continue ; if( h->Node->Type && h->Node->Type->Reference ) h->Node->Type->Reference( h->Node ); + h->Mount->OpenHandleCount ++; } } @@ -265,6 +267,7 @@ void VFS_FreeSavedHandles(int NumFDs, void *Handles) continue ; if( h->Node->Type && h->Node->Type->Close ) h->Node->Type->Close( h->Node ); + h->Mount->OpenHandleCount --; } free( Handles ); } diff --git a/KernelLand/Kernel/vfs/mount.c b/KernelLand/Kernel/vfs/mount.c index f281247b..c49e6d95 100644 --- a/KernelLand/Kernel/vfs/mount.c +++ b/KernelLand/Kernel/vfs/mount.c @@ -1,6 +1,7 @@ /* * Acess Micro - VFS Server version 1 */ +#define DEBUG 1 #include #include #include @@ -17,7 +18,7 @@ extern char *gsVFS_MountFile; void VFS_UpdateMountFile(void); // === GLOBALS === -tMutex glVFS_MountList; +tRWLock glVFS_MountList; tVFS_Mount *gVFS_Mounts; tVFS_Mount *gVFS_RootMount = NULL; Uint32 giVFS_NextMountIdent = 1; @@ -37,7 +38,7 @@ Uint32 giVFS_NextMountIdent = 1; */ int VFS_Mount(const char *Device, const char *MountPoint, const char *Filesystem, const char *Options) { - tVFS_Mount *mnt; + tVFS_Mount *mnt, *parent_mnt; tVFS_Driver *fs; int deviceLen = strlen(Device); int mountLen = strlen(MountPoint); @@ -55,6 +56,24 @@ int VFS_Mount(const char *Device, const char *MountPoint, const char *Filesystem if(!mnt) { return -2; } + + // Validate the mountpoint target + // - Only if / is mounted + if( gVFS_Mounts ) + { + tVFS_Node *mpnode = VFS_ParsePath(MountPoint, NULL, &parent_mnt); + if( !mpnode ) { + Log_Warning("VFS", "VFS_Mount - Mountpoint '%s' does not exist", MountPoint); + return -1; + } + if( mpnode->Type->Close ) + mpnode->Type->Close(mpnode); + if( parent_mnt->RootNode == mpnode ) { + Log_Warning("VFS", "VFS_Mount - Attempt to mount over '%s' (%s)", + MountPoint, parent_mnt->MountPoint); + return -1; + } + } // HACK: Forces VFS_ParsePath to fall back on root if(mountLen == 1 && MountPoint[0] == '/') @@ -64,6 +83,7 @@ int VFS_Mount(const char *Device, const char *MountPoint, const char *Filesystem // Fill Structure mnt->Filesystem = fs; + mnt->OpenHandleCount = 0; mnt->Device = &mnt->StrData[0]; memcpy( mnt->Device, Device, deviceLen+1 ); @@ -90,11 +110,12 @@ int VFS_Mount(const char *Device, const char *MountPoint, const char *Filesystem if(str) *str = '\0'; } while( str ); args[nArg] = 0; // NULL terminal - + // Initialise Volume mnt->RootNode = fs->InitDevice(Device, (const char **)args); if(!mnt->RootNode) { free(mnt); + parent_mnt->OpenHandleCount --; return -2; } @@ -114,11 +135,11 @@ int VFS_Mount(const char *Device, const char *MountPoint, const char *Filesystem if(!gVFS_RootMount) gVFS_RootMount = mnt; // Add to mount list - Mutex_Acquire( &glVFS_MountList ); + RWLock_AcquireWrite( &glVFS_MountList ); { - tVFS_Mount *tmp; mnt->Next = NULL; if(gVFS_Mounts) { + tVFS_Mount *tmp; for( tmp = gVFS_Mounts; tmp->Next; tmp = tmp->Next ); tmp->Next = mnt; } @@ -126,7 +147,7 @@ int VFS_Mount(const char *Device, const char *MountPoint, const char *Filesystem gVFS_Mounts = mnt; } } - Mutex_Release( &glVFS_MountList ); + RWLock_Release( &glVFS_MountList ); Log_Log("VFS", "Mounted '%s' to '%s' ('%s')", Device, MountPoint, Filesystem); @@ -135,18 +156,107 @@ int VFS_Mount(const char *Device, const char *MountPoint, const char *Filesystem return 0; } +int VFS_Unmount(const char *Mountpoint) +{ + tVFS_Mount *mount, *prev = NULL; + RWLock_AcquireWrite( &glVFS_MountList ); + for( mount = gVFS_Mounts; mount; prev = mount, mount = mount->Next ) + { + if( strcmp(Mountpoint, mount->MountPoint) == 0 ) { + if( mount->OpenHandleCount ) { + LOG("Mountpoint busy"); + RWLock_Release(&glVFS_MountList); + return EBUSY; + } + if(prev) + prev->Next = mount->Next; + else + gVFS_Mounts = mount->Next; + break; + } + } + RWLock_Release( &glVFS_MountList ); + if( !mount ) { + LOG("Mountpoint not found"); + return ENOENT; + } + + Log_Warning("VFS", "TODO: Impliment unmount"); + + // Decrease the open handle count for the mountpoint filesystem. + tVFS_Mount *mpmnt; + tVFS_Node *mpnode = VFS_ParsePath(mount->MountPoint, NULL, &mpmnt); + if(mpnode) + { + mpmnt->OpenHandleCount -= 2; // -1 for _ParsePath here, -1 for in _Mount + } + + mount->Filesystem->Unmount( mount->RootNode ); + free(mount); + + return EOK; +} + +int VFS_UnmountAll(void) +{ + int nUnmounted = 0; + tVFS_Mount *mount, *prev = NULL, *next; + + RWLock_AcquireWrite( &glVFS_MountList ); + // If we've unmounted the final filesystem, all good + if( gVFS_Mounts == NULL) { + RWLock_Release( &glVFS_MountList ); + return -1; + } + + for( mount = gVFS_Mounts; mount; prev = mount, mount = next ) + { + next = mount->Next; + // Can't unmount stuff with open handles + if( mount->OpenHandleCount > 0 ) { + LOG("%p (%s) has open handles (%i of them)", + mount, mount->MountPoint, mount->OpenHandleCount); + continue; + } + + if(prev) + prev->Next = mount->Next; + else + gVFS_Mounts = mount->Next; + + if( mount->Filesystem->Unmount ) { + mount->Filesystem->Unmount( mount->RootNode ); + } + else { + Log_Error("VFS", "%s (%s) does not have an unmount method, not calling it", + mount->MountPoint, mount->Filesystem->Name); + } + free(mount); + mount = prev; + nUnmounted ++; + } + RWLock_Release( &glVFS_MountList ); + + return nUnmounted; +} + /** * \brief Gets a mount point given the identifier */ tVFS_Mount *VFS_GetMountByIdent(Uint32 MountID) { tVFS_Mount *mnt; + + RWLock_AcquireRead(&glVFS_MountList); for(mnt = gVFS_Mounts; mnt; mnt = mnt->Next) { if(mnt->Identifier == MountID) - return mnt; + break; } - return NULL; + if(mnt) + mnt->OpenHandleCount ++; + RWLock_Release(&glVFS_MountList); + return mnt; } /** @@ -163,14 +273,17 @@ void VFS_UpdateMountFile(void) // Format: // \t\t\t\n + RWLock_AcquireRead( &glVFS_MountList ); for(mnt = gVFS_Mounts; mnt; mnt = mnt->Next) { len += 4 + strlen(mnt->Device) + strlen(mnt->MountPoint) + strlen(mnt->Filesystem->Name) + strlen(mnt->Options); } + RWLock_Release( &glVFS_MountList ); buf = malloc( len + 1 ); len = 0; + RWLock_AcquireRead( &glVFS_MountList ); for(mnt = gVFS_Mounts; mnt; mnt = mnt->Next) { strcpy( &buf[len], mnt->Device ); @@ -189,6 +302,7 @@ void VFS_UpdateMountFile(void) len += strlen(mnt->Options); buf[len++] = '\n'; } + RWLock_Release( &glVFS_MountList ); buf[len] = 0; SysFS_UpdateFile( giVFS_MountFileID, buf, len ); diff --git a/KernelLand/Kernel/vfs/open.c b/KernelLand/Kernel/vfs/open.c index d55b7546..e7d6e1e8 100644 --- a/KernelLand/Kernel/vfs/open.c +++ b/KernelLand/Kernel/vfs/open.c @@ -214,6 +214,7 @@ restart_parse: // Find Mountpoint longestMount = gVFS_RootMount; + RWLock_AcquireRead( &glVFS_MountList ); for(mnt = gVFS_Mounts; mnt; mnt = mnt->Next) { // Quick Check @@ -223,6 +224,8 @@ restart_parse: if(mnt->MountPointLen < longestMount->MountPointLen) continue; // String Compare cmp = strncmp(Path, mnt->MountPoint, mnt->MountPointLen); + // Not a match, continue + if(cmp != 0) continue; #if OPEN_MOUNT_ROOT // Fast Break - Request Mount Root @@ -233,14 +236,16 @@ restart_parse: } if(MountPoint) *MountPoint = mnt; + RWLock_Release( &glVFS_MountList ); + LOG("Mount %p root", mnt); LEAVE('p', mnt->RootNode); return mnt->RootNode; } #endif - // Not a match, continue - if(cmp != 0) continue; longestMount = mnt; } + longestMount->OpenHandleCount ++; // Increment assuimg it worked + RWLock_Release( &glVFS_MountList ); // Save to shorter variable mnt = longestMount; @@ -333,6 +338,7 @@ restart_parse: // EVIL: Goto :) LOG("Symlink -> '%s', restart", Path); + mnt->OpenHandleCount --; // Not in this mountpoint goto restart_parse; } @@ -402,6 +408,8 @@ restart_parse: *MountPoint = mnt; } + // Leave the mointpoint's count increased + LEAVE('p', tmpNode); return tmpNode; @@ -412,6 +420,9 @@ _error: free(*TruePath); *TruePath = NULL; } + // Open failed, so decrement the open handle count + mnt->OpenHandleCount --; + LEAVE('n'); return NULL; } @@ -571,6 +582,9 @@ int VFS_OpenChild(int FD, const char *Name, Uint Mode) LEAVE_RET('i', -1); } + // Increment open handle count, no problems with the mount going away as `h` is already open on it + h->Mount->OpenHandleCount ++; + LEAVE_RET('x', VFS_int_CreateHandle(node, h->Mount, Mode)); } @@ -631,7 +645,9 @@ void VFS_Close(int FD) #endif _CloseNode(h->Node); - + + h->Mount->OpenHandleCount --; + h->Node = NULL; } -- 2.20.1