X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=KernelLand%2FKernel%2Fvfs%2Fmount.c;h=c49e6d952b3a73557d80438c6cf6b3f5e323f51f;hb=4842e2d6740bcb81da4e94019285bfd2c45425b8;hp=f281247bfbe18b2db6d8512fec1cd452390a55a8;hpb=be490e1dd003780a02493a51ebbab1a5225c30d1;p=tpg%2Facess2.git 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 );