Kernel/VFS - Added unmount support
authorJohn Hodge <[email protected]>
Sat, 14 Jul 2012 05:07:22 +0000 (13:07 +0800)
committerJohn Hodge <[email protected]>
Sat, 14 Jul 2012 05:07:22 +0000 (13:07 +0800)
KernelLand/Kernel/include/errno.h
KernelLand/Kernel/include/vfs_ext.h
KernelLand/Kernel/include/vfs_int.h
KernelLand/Kernel/vfs/dir.c
KernelLand/Kernel/vfs/fs/devfs.c
KernelLand/Kernel/vfs/fs/root.c
KernelLand/Kernel/vfs/handle.c
KernelLand/Kernel/vfs/mount.c
KernelLand/Kernel/vfs/open.c

index 3652f19..7c2e97a 100644 (file)
@@ -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
index df68c4c..8cabfa1 100644 (file)
@@ -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)
index a8eadb6..f48e277 100644 (file)
@@ -5,6 +5,7 @@
 #define _VFS_INT_H
 
 #include "vfs.h"
+#include <rwlock.h>
 
 // === 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 ===
index e2b124d..fcf361e 100644 (file)
@@ -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
index 1355226..354f402 100644 (file)
 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)
  */
index 00829ed..4416750 100644 (file)
@@ -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;
                }
index d22f965..6d2b83f 100644 (file)
@@ -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 );
 }
index f281247..c49e6d9 100644 (file)
@@ -1,6 +1,7 @@
 /* 
  * Acess Micro - VFS Server version 1
  */
+#define DEBUG  1
 #include <acess.h>
 #include <vfs.h>
 #include <vfs_int.h>
@@ -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:
        // <device>\t<location>\t<type>\t<options>\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 );
index d55b754..e7d6e1e 100644 (file)
@@ -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;
 }
 

UCC git Repository :: git.ucc.asn.au