2 * Acess2 Kernel - RAM Disk Support
3 * - By John Hodge (thePowersGang)
12 #define VERSION VER2(0,1)
14 #define MIN_RAMDISK_SIZE (1*1024*1024)
15 #define MAX_RAMDISK_SIZE (64*1024*1024)
18 int RAMFS_Install(char **Arguments);
19 int RAMFS_Cleanup(void);
20 // --- Mount/Unmount ---
21 tVFS_Node *RAMFS_InitDevice(const char *Device, const char **Options);
22 void RAMFS_Unmount(tVFS_Node *Node);
23 // --- Directories ---
24 int RAMFS_ReadDir(tVFS_Node *Node, int Index, char Dest[256]);
25 tVFS_Node *RAMFS_FindDir(tVFS_Node *Node, const char *Name, Uint Flags);
26 tVFS_Node *RAMFS_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
27 int RAMFS_Link(tVFS_Node *DirNode, const char *Name, tVFS_Node *Node);
28 int RAMFS_Unlink(tVFS_Node *Node, const char *Name);
30 size_t RAMFS_Read(tVFS_Node *Node, off_t Offset, size_t Size, void *Buffer, Uint Flags);
31 size_t RAMFS_Write(tVFS_Node *Node, off_t Offset, size_t Size, const void *Buffer, Uint Flags);
33 void RAMFS_int_RefFile(tRAMFS_Inode *Inode);
34 void RAMFS_int_DerefFile(tRAMFS_Inode *Inode);
35 void *RAMFS_int_GetPage(tRAMFS_File *File, int Page, int bCanAlloc);
36 void RAMFS_int_DropPage(void *Page);
37 Uint32 RAMFS_int_AllocatePage(tRAMDisk *Disk);
38 void RAMFS_int_RefFile(tRAMFS_Inode *Inode);
39 void RAMFS_int_DerefFile(tRAMFS_Inode *Inode);
42 MODULE_DEFINE(0, VERSION, FS_RAMDisk, RAMFS_Install, RAMFS_Cleanup, NULL);
43 tVFS_Driver gRAMFS_Driver = {
45 .InitDevice = RAMFS_InitDevice,
46 .Unmount = RAMFS_Unmount
47 // TODO: GetNodeFromInode
49 tVFS_NodeType gRAMFS_DirNodeType = {
50 .ReadDir = RAMFS_ReadDir,
51 .FindDir = RAMFS_FindDir,
54 .Unlink = RAMFS_Unlink
56 tVFS_NodeType gRAMFS_FileNodeType = {
62 int RAMFS_Install(char **Arguments)
64 VFS_AddDriver( &gRAMFS_Driver );
68 int RAMFS_Cleanup(void)
75 const char *_GetOption(const char *Data, const char *Option)
77 int len = strlen(Option);
78 if( strncmp(Data, Option, len) != 0 )
80 if( Data[len] != '=' )
82 return Data + len + 1;
85 tVFS_Node *RAMFS_InitDevice(const char *Device, const char **Options)
93 for( int i = 0; Options[i]; i ++ )
95 LOG("Options[%i] = '%s'", i, Options[i]);
96 if( (v = _GetOption(Options[i], "megs")) )
98 size = atoi(v) * 1024 * 1024;
99 LOG("Size set to %iMiB", size>>20);
104 LOG("Disk Size %iKiB", size>>10);
106 if( size > MAX_RAMDISK_SIZE || size < MIN_RAMDISK_SIZE )
109 int n_pages = size / PAGE_SIZE;
111 rd = calloc(1, sizeof(tRAMDisk) + n_pages * sizeof(tPAddr) + n_pages / 8);
112 rd->MaxPages = n_pages;
113 rd->RootDir.Inode.Disk = rd;
114 rd->RootDir.Inode.Node.ImplPtr = &rd->RootDir;
115 rd->RootDir.Inode.Node.Flags = VFS_FFLAG_DIRECTORY;
116 rd->RootDir.Inode.Node.Size = -1;
117 rd->RootDir.Inode.Node.Type = &gRAMFS_DirNodeType;
118 rd->Bitmap = (void*)&rd->PhysPages[ n_pages ];
120 for( int i = 0; i < n_pages; i ++ )
122 rd->PhysPages[i] = MM_AllocPhys();
123 if( !rd->PhysPages[i] ) {
130 return &rd->RootDir.Inode.Node;
133 void RAMFS_Unmount(tVFS_Node *Node)
135 Log_Warning("RAMDisk", "TODO: Impliment unmounting");
138 // --- Directories ---
139 int RAMFS_ReadDir(tVFS_Node *Node, int Index, char Dest[FILENAME_MAX])
141 tRAMFS_Dir *dir = Node->ImplPtr;
142 for( tRAMFS_DirEnt *d = dir->FirstEnt; d; d = d->Next )
144 if( Index -- == 0 ) {
145 LOG("Return %s", d->Name);
146 strncpy(Dest, d->Name, FILENAME_MAX);
150 LOG("Return -ENOENT");
154 tVFS_Node *RAMFS_FindDir(tVFS_Node *Node, const char *Name, Uint Flags)
156 tRAMFS_Dir *dir = Node->ImplPtr;
158 for( tRAMFS_DirEnt *d = dir->FirstEnt; d; d = d->Next )
160 if( strcmp(d->Name, Name) == 0 ) {
161 LOG("Return %p", &d->Inode->Node);
162 return &d->Inode->Node;
170 tVFS_Node *RAMFS_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
172 tRAMFS_Dir *dir = Node->ImplPtr;
173 if( RAMFS_FindDir(Node, Name, 0) != NULL )
176 tRAMFS_DirEnt *de = malloc( sizeof(tRAMFS_DirEnt) + strlen(Name) + 1 );
178 de->NameLen = strlen(Name);
179 strcpy(de->Name, Name);
181 if( Flags & VFS_FFLAG_DIRECTORY ) {
182 tRAMFS_Dir *newdir = calloc(1, sizeof(tRAMFS_Dir));
183 newdir->Inode.Node.Type = &gRAMFS_DirNodeType;
184 de->Inode = &newdir->Inode;
187 tRAMFS_File *newfile = calloc(1, sizeof(tRAMFS_File));
188 newfile->Inode.Node.Type = &gRAMFS_FileNodeType;
189 de->Inode = &newfile->Inode;
191 de->Inode->Disk = dir->Inode.Disk;
192 de->Inode->Node.Flags = Flags;
193 de->Inode->Node.ImplPtr = de->Inode;
195 RAMFS_int_RefFile(de->Inode);
199 dir->LastEnt->Next = de;
204 return &de->Inode->Node;
207 int RAMFS_Link(tVFS_Node *DirNode, const char *Name, tVFS_Node *FileNode)
209 tRAMFS_Dir *dir = DirNode->ImplPtr;
212 for( dp = dir->FirstEnt; dp; dp = dp->Next )
214 if( strcmp(dp->Name, Name) == 0 )
218 dp = malloc( sizeof(tRAMFS_DirEnt) + strlen(Name) + 1 );
220 dp->Inode = FileNode->ImplPtr;
221 RAMFS_int_RefFile(dp->Inode);
222 strcpy(dp->Name, Name);
226 dir->LastEnt->Next = dp;
234 int RAMFS_Unlink(tVFS_Node *Node, const char *Name)
236 tRAMFS_Dir *dir = Node->ImplPtr;
237 tRAMFS_DirEnt *dp, *p = NULL;
239 // TODO: Is locking needed?
241 // Find the directory entry
242 for( dp = dir->FirstEnt; dp; p = dp, dp = dp->Next )
244 if( strcmp(dp->Name, Name) == 0 )
249 // Dereference the file
250 RAMFS_int_DerefFile( dp->Inode );
252 // Remove and free directory entry
254 dir->FirstEnt = dp->Next;
257 if( dir->LastEnt == dp )
265 size_t RAMFS_int_DoIO(tRAMFS_File *File, off_t Offset, size_t Size, void *Buffer, int bRead)
271 if( Offset >= File->Size ) return 0;
273 if( Offset + Size > File->Size ) Size = File->Size - Size;
275 if( Size == 0 ) return 0;
277 page = Offset / PAGE_SIZE;
281 page_virt = RAMFS_int_GetPage(File, page++, !bRead);
282 if(!page_virt) return 0;
284 if( Offset + Size <= PAGE_SIZE )
287 memcpy(Buffer, page_virt + Offset, Size);
289 memcpy(page_virt + Offset, Buffer, Size);
294 memcpy(Buffer, page_virt + Offset, PAGE_SIZE - Offset);
296 memcpy(page_virt + Offset, Buffer, PAGE_SIZE - Offset);
297 Buffer += PAGE_SIZE - Offset;
298 rem -= PAGE_SIZE - Offset;
300 while( rem >= PAGE_SIZE )
302 RAMFS_int_DropPage(page_virt);
303 page_virt = RAMFS_int_GetPage(File, page++, !bRead);
304 if(!page_virt) return Size - rem;
307 memcpy(Buffer, page_virt, PAGE_SIZE);
309 memcpy(page_virt, Buffer, PAGE_SIZE);
317 page_virt = RAMFS_int_GetPage(File, page, !bRead);
318 if(!page_virt) return Size - rem;
320 memcpy(Buffer, page_virt, rem);
322 memcpy(page_virt, Buffer, rem);
325 RAMFS_int_DropPage(page_virt);
330 size_t RAMFS_Read(tVFS_Node *Node, off_t Offset, size_t Size, void *Buffer, Uint Flags)
332 tRAMFS_File *file = Node->ImplPtr;
334 return RAMFS_int_DoIO(file, Offset, Size, Buffer, 1);
337 size_t RAMFS_Write(tVFS_Node *Node, off_t Offset, size_t Size, const void *Buffer, Uint Flags)
339 tRAMFS_File *file = Node->ImplPtr;
341 // TODO: Limit checks?
342 if( Offset == file->Size )
345 return RAMFS_int_DoIO(file, Offset, Size, (void*)Buffer, 0);
349 void *RAMFS_int_GetPage(tRAMFS_File *File, int Page, int bCanAlloc)
352 Uint32 *page_in_1 = NULL;
353 Uint32 *page_in_2 = NULL;
357 if( Page < 0 ) return NULL;
359 if( Page < RAMFS_NDIRECT )
361 if( File->PagesDirect[Page] )
362 page_id = File->PagesDirect[Page];
364 else if( Page - RAMFS_NDIRECT < PAGE_SIZE/4 )
366 ofs = Page - RAMFS_NDIRECT;
367 if( File->Indirect1Page == 0 ) {
371 File->Indirect1Page = RAMFS_int_AllocatePage(File->Inode.Disk) + 1;
373 page_in_1 = MM_MapTemp( File->Inode.Disk->PhysPages[File->Indirect1Page-1] );
374 page_id = page_in_1[ofs];
376 else if( Page - RAMFS_NDIRECT - PAGE_SIZE/4 < (PAGE_SIZE/4)*(PAGE_SIZE/4) )
378 block = (Page - RAMFS_NDIRECT - PAGE_SIZE/4) / (PAGE_SIZE/4);
379 ofs = (Page - RAMFS_NDIRECT - PAGE_SIZE/4) % (PAGE_SIZE/4);
380 if( File->Indirect2Page == 0 ){
384 File->Indirect2Page = RAMFS_int_AllocatePage(File->Inode.Disk) + 1;
387 page_in_2 = MM_MapTemp( File->Inode.Disk->PhysPages[File->Indirect2Page-1] );
388 if( page_in_2[block] == 0 ) {
392 page_in_2[block] = RAMFS_int_AllocatePage(File->Inode.Disk) + 1;
395 page_in_1 = MM_MapTemp( File->Inode.Disk->PhysPages[page_in_2[block] - 1] );
396 page_id = page_in_1[ofs];
404 page_id = RAMFS_int_AllocatePage(File->Inode.Disk) + 1;
406 page_in_1[ofs] = page_id;
408 File->PagesDirect[Page] = page_id;
411 MM_FreeTemp( page_in_1 );
412 MM_FreeTemp( page_in_2 );
414 return MM_MapTemp( File->Inode.Disk->PhysPages[page_id - 1] );
417 void RAMFS_int_DropPage(void *Page)
422 Uint32 RAMFS_int_AllocatePage(tRAMDisk *Disk)
427 if( Disk->nUsedPages == Disk->MaxPages )
430 // Find a chunk with at least one free page
431 for( i = 0; i < Disk->MaxPages / 32; i ++ )
433 if( Disk->Bitmap[i] != -1 )
436 if( i == Disk->MaxPages / 32 ) {
437 Log_Error("RAMFS", "Bookkeeping error, count and bitmap disagree");
441 // Find the exact page
442 for( j = 0; j < 32; j ++ )
444 if( !(Disk->Bitmap[i] & (1U << j)) )
452 void RAMFS_int_RefFile(tRAMFS_Inode *Inode)
457 void RAMFS_int_DerefFile(tRAMFS_Inode *Inode)
460 if( Inode->nLink >= 0 )
463 Log_Error("RAMFS", "TODO: Clean up files when deleted");
465 // Need to delete file
466 switch( Inode->Type )