Modules/RAMDisk - a bit more work
[tpg/acess2.git] / KernelLand / Modules / Filesystems / RAMDisk / ramdisk.c
1 /*
2  * Acess2 Kernel - RAM Disk Support
3  * - By John Hodge (thePowersGang)
4  *
5  * ramdisk.c
6  * - Core File
7  */
8 #define DEBUG   0
9 #include <acess.h>
10 #include <modules.h>
11 #include "ramdisk.h"
12 #define VERSION VER2(0,1)
13
14 #define MIN_RAMDISK_SIZE        (1*1024*1024)
15 #define MAX_RAMDISK_SIZE        (64*1024*1024)
16
17 // === PROTOTYPES ===
18  int    RAMDisk_Install(char **Arguments);
19 void    RAMDisk_Cleanup(void);
20 // --- Mount/Unmount ---
21 tVFS_Node       *RAMDisk_InitDevice(const char *Device, const char **Options);
22 void    RAMDisk_Unmount(tVFS_Node *Node);
23 // --- Directories ---
24 char    *RAMDisk_ReadDir(tVFS_Node *Node, int Index);
25 tVFS_Node       *RAMDisk_FindDir(tVFS_Node *Node, const char *Name);
26  int    RAMDisk_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
27  int    RAMDisk_Link(tVFS_Node *DirNode, const char *Name, tVFS_Node *Node);
28  int    RAMDisk_Unlink(tVFS_Node *Node, const char *Name);
29 // --- Files ---
30 size_t  RAMDisk_Read(tVFS_Node *Node, off_t Offset, size_t Size, void *Buffer);
31 size_t  RAMDisk_Write(tVFS_Node *Node, off_t Offset, size_t Size, const void *Buffer);
32 // --- Internals --
33 void    RAMDisk_int_RefFile(tRAMDisk_Inode *Inode);
34 void    RAMDisk_int_DerefFile(tRAMDisk_Inode *Inode);
35 void    *_GetPage(tRAMDisk_File *File, int Page, int bCanAlloc);
36 void    _DropPage(void *Page);
37
38 // === GLOBALS ===
39 MODULE_DEFINE(0, VERSION, FS_RAMDisk, RAMDisk_Install, RAMDisk_Cleanup, NULL);
40 tVFS_Driver     gRAMDisk_Driver = {
41         .Name = "RAMDisk",
42         .InitDevice = RAMDisk_InitDevice,
43         .Unmount = RAMDisk_Unmount
44         // TODO: GetNodeFromInode
45         };
46 tVFS_NodeType   gRAMDisk_DirNodeType = {
47         .ReadDir = RAMDisk_ReadDir,
48         .FindDir = RAMDisk_FindDir,
49         .MkNod   = RAMDisk_MkNod,
50 //      .Link    = RAMDisk_Link,
51 //      .Unlink  = RAMDisk_Unink
52         };
53 tVFS_NodeType   gRAMDisk_FileNodeType = {
54         .Read  = RAMDisk_Read,
55         .Write = RAMDisk_Write
56         };
57
58 // === CODE ===
59 int RAMDisk_Install(char **Arguments)
60 {
61         VFS_AddDriver( &gRAMDisk_Driver );
62         return 0;
63 }
64
65 void RAMDisk_Cleanup(void)
66 {
67         
68 }
69
70
71 // --- Mount/Unmount
72 tVFS_Node *RAMDisk_InitDevice(const char *Device, const char **Options)
73 {
74         size_t  size = 0;
75         tRAMDisk        *rd;
76
77         if( Options ) 
78         {
79                 for( int i = 0; Options[i]; i ++ )
80                 {
81                         if( strcmp(Options[i], "megs") == '=' )
82                         {
83                                 size = atoi(Options[i] + 5) * 1024 * 1024;
84                         }
85                 }
86         }
87
88         if( size > MAX_RAMDISK_SIZE || size < MIN_RAMDISK_SIZE )
89                 return NULL;
90
91          int    n_pages = size / PAGE_SIZE;
92         
93         rd = calloc(1, sizeof(tRAMDisk) + n_pages * sizeof(tPAddr) + n_pages / 8);
94         rd->MaxPages = n_pages;
95         rd->RootDir.Inode.Disk = rd;
96         rd->RootDir.Inode.Node.ImplPtr = &rd->RootDir;
97         rd->RootDir.Inode.Node.Flags = VFS_FFLAG_DIRECTORY;
98         rd->RootDir.Inode.Node.Size = -1;
99         rd->RootDir.Inode.Node.Type = &gRAMDisk_DirNodeType;
100         rd->Bitmap = (void*)&rd->PhysPages[ n_pages ];
101
102         for( int i = 0; i < n_pages; i ++ )
103         {
104                 rd->PhysPages[i] = MM_AllocPhys();
105                 if( !rd->PhysPages[i] ) {
106                         // Um... oops?
107                         break;
108                 }
109         }
110
111         return &rd->RootDir.Inode.Node;
112 }
113
114 void RAMDisk_Unmount(tVFS_Node *Node)
115 {
116         Log_Warning("RAMDisk", "TODO: Impliment unmounting");
117 }
118
119 // --- Directories ---
120 char *RAMDisk_ReadDir(tVFS_Node *Node, int Index)
121 {
122         tRAMDisk_Dir    *dir = Node->ImplPtr;
123         for( tRAMDisk_DirEnt *d = dir->FirstEnt; d; d = d->Next )
124         {
125                 if( Index -- == 0 )
126                         return strdup(d->Name);
127         }
128         return NULL;
129 }
130
131 tVFS_Node *RAMDisk_FindDir(tVFS_Node *Node, const char *Name)
132 {
133         tRAMDisk_Dir    *dir = Node->ImplPtr;
134         for( tRAMDisk_DirEnt *d = dir->FirstEnt; d; d = d->Next )
135         {
136                 if( strcmp(d->Name, Name) == 0 )
137                         return &d->Inode->Node;
138         }
139         
140         return NULL;
141 }
142
143 int RAMDisk_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
144 {
145         tRAMDisk_Dir    *dir = Node->ImplPtr;
146         if( RAMDisk_FindDir(Node, Name) != NULL )
147                 return -1;
148         
149         tRAMDisk_DirEnt *de = malloc( sizeof(tRAMDisk_DirEnt) + strlen(Name) + 1 );
150         de->Next = NULL;
151         de->NameLen = strlen(Name);
152         strcpy(de->Name, Name);
153
154         if( Flags & VFS_FFLAG_DIRECTORY ) {
155                 tRAMDisk_Dir    *newdir = calloc(1, sizeof(tRAMDisk_Dir));
156                 newdir->Inode.Node.Type = &gRAMDisk_DirNodeType;
157                 de->Inode = &newdir->Inode;
158         }
159         else {
160                 tRAMDisk_File   *newfile = calloc(1, sizeof(tRAMDisk_File));
161                 newfile->Inode.Node.Type = &gRAMDisk_FileNodeType;
162                 de->Inode = &newfile->Inode;
163         }
164         de->Inode->Disk = dir->Inode.Disk;
165         de->Inode->Node.Flags = Flags;
166         de->Inode->Node.ImplPtr = de->Inode;
167
168         RAMDisk_int_RefFile(de->Inode);
169
170         // TODO: Lock?
171         if(dir->FirstEnt)
172                 dir->LastEnt->Next = de;
173         else
174                 dir->FirstEnt = de;
175         dir->LastEnt = de;
176
177         return 0;
178 }
179
180 int RAMDisk_Link(tVFS_Node *DirNode, const char *Name, tVFS_Node *FileNode)
181 {
182         tRAMDisk_Dir    *dir = DirNode->ImplPtr;
183         tRAMDisk_DirEnt *dp;
184
185         for( dp = dir->FirstEnt; dp; dp = dp->Next )
186         {
187                 if( strcmp(dp->Name, Name) == 0 )
188                         return -1;
189         }
190         
191         dp = malloc( sizeof(tRAMDisk_DirEnt) + strlen(Name) + 1 );
192         dp->Next = NULL;
193         dp->Inode = FileNode->ImplPtr;
194         RAMDisk_int_RefFile(dp->Inode);
195         strcpy(dp->Name, Name);
196
197         // TODO: Lock?  
198         if(dir->FirstEnt)
199                 dir->LastEnt->Next = dp;
200         else
201                 dir->FirstEnt = dp;
202         dir->LastEnt = dp;
203         
204         return 0;
205 }
206
207 int RAMDisk_Unlink(tVFS_Node *Node, const char *Name)
208 {
209         tRAMDisk_Dir    *dir = Node->ImplPtr;
210         tRAMDisk_DirEnt *dp, *p = NULL;
211
212         // TODO: Is locking needed?
213
214         for( dp = dir->FirstEnt; dp; p = dp, dp = dp->Next )
215         {
216                 if( strcmp(dp->Name, Name) == 0 )
217                         break ;
218         }
219         if( !dp )       return -1;
220         
221         RAMDisk_int_DerefFile( dp->Inode );
222
223         if( !p )
224                 dir->FirstEnt = dp->Next;
225         else
226                 p->Next = dp->Next;
227         if( dir->LastEnt == dp )
228                 dir->LastEnt = p;
229         free(dp);
230
231         return 0;
232 }
233
234 // --- Files ---
235 size_t _DoIO(tRAMDisk_File *File, off_t Offset, size_t Size, void *Buffer, int bRead)
236 {
237         size_t  rem;
238         Uint8   *page_virt;
239          int    page;
240
241         if( Offset >= File->Size )      return 0;
242         
243         if( Offset + Size > File->Size )        Size = File->Size - Size;
244
245         if( Size == 0 )         return 0;
246
247         page = Offset / PAGE_SIZE;
248         Offset %= PAGE_SIZE;
249         rem = Size;
250
251         page_virt = _GetPage(File, page++, !bRead);
252         if(!page_virt)  return 0;
253         
254         if( Offset + Size <= PAGE_SIZE )
255         {
256                 if( bRead )
257                         memcpy(Buffer, page_virt + Offset, Size);
258                 else
259                         memcpy(page_virt + Offset, Buffer, Size);
260                 return 0;
261         }
262         
263         if( bRead )
264                 memcpy(Buffer, page_virt + Offset, PAGE_SIZE - Offset);
265         else
266                 memcpy(page_virt + Offset, Buffer, PAGE_SIZE - Offset);
267         Buffer += PAGE_SIZE - Offset;
268         rem -= PAGE_SIZE - Offset;
269         
270         while( rem >= PAGE_SIZE )
271         {
272                 _DropPage(page_virt);
273                 page_virt = _GetPage(File, page++, !bRead);
274                 if(!page_virt)  return Size - rem;
275                 
276                 if( bRead )
277                         memcpy(Buffer, page_virt, PAGE_SIZE);
278                 else
279                         memcpy(page_virt, Buffer, PAGE_SIZE);
280                 
281                 Buffer += PAGE_SIZE;
282                 rem -= PAGE_SIZE;
283         }
284
285         if( rem > 0 )
286         {
287                 page_virt = _GetPage(File, page, !bRead);
288                 if(!page_virt)  return Size - rem;
289                 if( bRead )
290                         memcpy(Buffer, page_virt, rem);
291                 else
292                         memcpy(page_virt, Buffer, rem);
293         }
294
295         _DropPage(page_virt);
296         
297         return Size;
298 }
299
300 size_t RAMDisk_Read(tVFS_Node *Node, off_t Offset, size_t Size, void *Buffer)
301 {
302         tRAMDisk_File   *file = Node->ImplPtr;
303         
304         return _DoIO(file, Offset, Size, Buffer, 1);
305 }
306
307 size_t RAMDisk_Write(tVFS_Node *Node, off_t Offset, size_t Size, const void *Buffer)
308 {
309         tRAMDisk_File   *file = Node->ImplPtr;
310         
311         // TODO: Limit checks?
312         if( Offset == file->Size )
313                 file->Size += Size;
314
315         return _DoIO(file, Offset, Size, (void*)Buffer, 0);
316 }
317
318

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