Kernel/VFS - Added unmount support
[tpg/acess2.git] / KernelLand / Kernel / vfs / mount.c
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 );

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