Kernel/VFS - Fixed bug with setting flags on FD0
[tpg/acess2.git] / KernelLand / Kernel / vfs / mount.c
index c49e6d9..1823857 100644 (file)
@@ -1,7 +1,8 @@
 /* 
  * Acess Micro - VFS Server version 1
  */
-#define DEBUG  1
+#define SANITY 1
+#define DEBUG  0
 #include <acess.h>
 #include <vfs.h>
 #include <vfs_int.h>
@@ -15,6 +16,7 @@ extern char   *gsVFS_MountFile;
 #if 0
  int   VFS_Mount(const char *Device, const char *MountPoint, const char *Filesystem, const char *Options);
 #endif
+void   VFS_int_Unmount(tVFS_Mount *Mount);
 void   VFS_UpdateMountFile(void);
 
 // === GLOBALS ===
@@ -45,18 +47,43 @@ int VFS_Mount(const char *Device, const char *MountPoint, const char *Filesystem
         int    argLen = strlen(Options);
        
        // Get the filesystem
-       fs = VFS_GetFSByName(Filesystem);
-       if(!fs) {
-               Log_Warning("VFS", "VFS_Mount - Unknown FS Type '%s'", Filesystem);
-               return -1;
+       if( Filesystem && Filesystem[0] )
+       {
+               fs = VFS_GetFSByName(Filesystem);
+               if(!fs) {
+                       Log_Warning("VFS", "VFS_Mount - Unknown FS Type '%s'", Filesystem);
+                       return -ENOENT;
+               }
        }
-       
-       // Create mount information
-       mnt = malloc( sizeof(tVFS_Mount)+deviceLen+1+mountLen+1+argLen+1 );
-       if(!mnt) {
-               return -2;
+       else
+       {
+               int fd = VFS_Open(Device, VFS_OPENFLAG_READ);
+               if( fd == -1 ) {
+                       Log_Warning("VFS", "VFS_Mount - Unable to open '%s' for autodetect", Device);
+                       return -ENOENT;
+               }
+               
+               tVFS_Driver     *bestfs = NULL;
+                int    bestrank = 0, rank;
+               for( fs = gVFS_Drivers; fs; fs = fs->Next )
+               {
+                       if(!fs->Detect) continue ;
+                       rank = fs->Detect(fd);
+                       if(!rank)       continue ;
+                       if(!bestfs || rank > bestrank) {
+                               bestfs = fs;
+                               bestrank = rank;
+                       }
+               }
+               VFS_Close(fd);
+               if( bestfs == NULL ) {
+                       Log_Warning("VFS", "VFS_Mount - Filesystem autodetection failed");
+                       return -1;
+               }
+               
+               fs = bestfs;
        }
-
+       
        // Validate the mountpoint target
        // - Only if / is mounted
        if( gVFS_Mounts )
@@ -75,6 +102,14 @@ int VFS_Mount(const char *Device, const char *MountPoint, const char *Filesystem
                }
        }
        
+       // Create mount information
+       mnt = malloc( sizeof(tVFS_Mount)+deviceLen+1+mountLen+1+argLen+1 );
+       if(!mnt) {
+               ASSERT(parent_mnt->OpenHandleCount > 0);
+               parent_mnt->OpenHandleCount --;
+               return -2;
+       }
+
        // HACK: Forces VFS_ParsePath to fall back on root  
        if(mountLen == 1 && MountPoint[0] == '/')
                mnt->MountPointLen = 0;
@@ -115,6 +150,7 @@ int VFS_Mount(const char *Device, const char *MountPoint, const char *Filesystem
        mnt->RootNode = fs->InitDevice(Device, (const char **)args);
        if(!mnt->RootNode) {
                free(mnt);
+               ASSERT(parent_mnt->OpenHandleCount>0);
                parent_mnt->OpenHandleCount --;
                return -2;
        }
@@ -149,13 +185,42 @@ int VFS_Mount(const char *Device, const char *MountPoint, const char *Filesystem
        }
        RWLock_Release( &glVFS_MountList );
        
-       Log_Log("VFS", "Mounted '%s' to '%s' ('%s')", Device, MountPoint, Filesystem);
+       Log_Log("VFS", "Mounted '%s' to '%s' ('%s')", Device, MountPoint, fs->Name);
        
        VFS_UpdateMountFile();
        
        return 0;
 }
 
+void VFS_int_Unmount(tVFS_Mount *Mount)
+{
+       // Decrease the open handle count for the mountpoint filesystem.
+       if( Mount != gVFS_RootMount )
+       {
+               tVFS_Mount      *mpmnt;
+               for( mpmnt = gVFS_Mounts; mpmnt; mpmnt = mpmnt->Next )
+               {
+                       if( strncmp(mpmnt->MountPoint, Mount->MountPoint, mpmnt->MountPointLen) != 0 )
+                               continue ;
+                       if( Mount->MountPoint[ mpmnt->MountPointLen ] != '/' )
+                               continue ;
+                       break;
+               }
+               if(mpmnt) {
+                       ASSERT(mpmnt->OpenHandleCount>0);
+                       mpmnt->OpenHandleCount --;
+               }
+               else {
+                       Log_Notice("VFS", "Mountpoint '%s' has no parent", Mount->MountPoint);
+               }
+       }
+
+       if( Mount->Filesystem->Unmount )
+               Mount->Filesystem->Unmount( Mount->RootNode );
+       LOG("%p (%s) unmounted", Mount, Mount->MountPoint);
+       free(Mount);
+}
+
 int VFS_Unmount(const char *Mountpoint)
 {
        tVFS_Mount      *mount, *prev = NULL;
@@ -166,6 +231,8 @@ int VFS_Unmount(const char *Mountpoint)
                        if( mount->OpenHandleCount ) {
                                LOG("Mountpoint busy");
                                RWLock_Release(&glVFS_MountList);
+                               Log_Log("VFS", "Unmount of '%s' deferred, still busy (%i open handles)",
+                                       Mountpoint, mount->OpenHandleCount);
                                return EBUSY;
                        }
                        if(prev)
@@ -180,20 +247,11 @@ int VFS_Unmount(const char *Mountpoint)
                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);
+       VFS_int_Unmount(mount);
 
+       VFS_UpdateMountFile();
+       
        return EOK;
 }
 
@@ -206,12 +264,18 @@ int VFS_UnmountAll(void)
        // If we've unmounted the final filesystem, all good
        if( gVFS_Mounts == NULL) {
                RWLock_Release( &glVFS_MountList );
+               
+               // Final unmount means VFS completely deinited
+               VFS_Deinit();
                return -1;
        }
 
        for( mount = gVFS_Mounts; mount; prev = mount, mount = next )
        {
                next = mount->Next;
+               
+               ASSERT(mount->OpenHandleCount >= 0);            
+
                // Can't unmount stuff with open handles
                if( mount->OpenHandleCount > 0 ) {
                        LOG("%p (%s) has open handles (%i of them)",
@@ -224,19 +288,14 @@ int VFS_UnmountAll(void)
                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);
+               VFS_int_Unmount(mount);
                mount = prev;
                nUnmounted ++;
        }
        RWLock_Release( &glVFS_MountList );
 
+       VFS_UpdateMountFile();
+
        return nUnmounted;
 }
 

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