Kernel - Added return value to module cleanup, fixed LVM bugs
[tpg/acess2.git] / KernelLand / Modules / Storage / LVM / main.c
1 /*
2  * Acess2 Logical Volume Manager
3  * - By John Hodge (thePowersGang)
4  *
5  * lvm.h
6  * - LVM Core definitions
7  */
8 #define DEBUG   1
9 #define VERSION VER2(0,1)
10 #include "lvm_int.h"
11 #include <fs_devfs.h>
12 #include <modules.h>
13 #include <api_drv_disk.h>
14
15 // === PROTOTYPES ===
16 // ---
17  int    LVM_Initialise(char **Arguments);
18  int    LVM_Cleanup(void);
19 // ---
20 char    *LVM_Root_ReadDir(tVFS_Node *Node, int ID);
21 tVFS_Node       *LVM_Root_FindDir(tVFS_Node *Node, const char *Name);
22 char    *LVM_Vol_ReadDir(tVFS_Node *Node, int ID);
23 tVFS_Node       *LVM_Vol_FindDir(tVFS_Node *Node, const char *Name);
24 size_t  LVM_Vol_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer);
25 size_t  LVM_Vol_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer);
26 size_t  LVM_SubVol_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer);
27 size_t  LVM_SubVol_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer);
28
29 Uint    LVM_int_DrvUtil_ReadBlock(Uint64 Address, Uint Count, void *Buffer, void *Argument);
30 Uint    LVM_int_DrvUtil_WriteBlock(Uint64 Address, Uint Count, const void *Buffer, void *Argument);
31
32 // === GLOBALS ===
33 MODULE_DEFINE(0, VERSION, LVM, LVM_Initialise, LVM_Cleanup, NULL);
34 tVFS_NodeType   gLVM_RootNodeType = {
35         .ReadDir = LVM_Root_ReadDir,
36         .FindDir = LVM_Root_FindDir
37 };
38 tVFS_NodeType   gLVM_VolNodeType = {
39         .ReadDir = LVM_Vol_ReadDir,
40         .FindDir = LVM_Vol_FindDir,
41         .Read = LVM_Vol_Read,
42         .Write = LVM_Vol_Write
43 };
44 tVFS_NodeType   gLVM_SubVolNodeType = {
45         .Read = LVM_SubVol_Read,
46         .Write = LVM_SubVol_Write
47 };
48 tDevFS_Driver   gLVM_DevFS = {
49         NULL, "LVM",
50         {.Flags = VFS_FFLAG_DIRECTORY, .Type = &gLVM_RootNodeType, .Size = -1}
51 };
52
53 tLVM_Vol        *gpLVM_FirstVolume;
54 tLVM_Vol        *gpLVM_LastVolume = (void*)&gpLVM_FirstVolume;
55
56 // === CODE ===
57 int LVM_Initialise(char **Arguments)
58 {
59         DevFS_AddDevice( &gLVM_DevFS );
60         return 0;
61 }
62
63 int LVM_Cleanup(void)
64 {
65         // Attempt to destroy all volumes
66         tLVM_Vol        *vol, *prev = NULL, *next;
67         
68         // TODO: Locks?
69         for( vol = gpLVM_FirstVolume; vol; prev = vol, vol = next )
70         {
71                 next = vol->Next;
72                  int    nFree = 0;
73                 
74                 for( int i = 0; i < vol->nSubVolumes; i ++ )
75                 {
76                         tLVM_SubVolume  *sv;
77                         sv = vol->SubVolumes[i];
78                         if( sv == NULL ) {
79                                 nFree ++;
80                                 continue;
81                         }
82
83                         Mutex_Acquire(&sv->Node.Lock);
84                         if(sv->Node.ReferenceCount == 0) {
85                                 nFree ++;
86                                 vol->SubVolumes[i] = NULL;
87                         }
88                         Mutex_Release(&sv->Node.Lock);
89                         
90                         Mutex_Acquire(&sv->Node.Lock);
91                         LOG("Removed subvolume %s:%s", vol->Name, sv->Name);
92                         free(sv);
93                 }
94                 
95                 if( nFree != vol->nSubVolumes )
96                         continue ;
97
98                 if(prev)
99                         prev->Next = next;
100                 else
101                         gpLVM_FirstVolume = next;
102
103                 Mutex_Acquire(&vol->DirNode.Lock);
104                 Mutex_Acquire(&vol->VolNode.Lock);
105                 if( vol->Type->Cleanup )
106                         vol->Type->Cleanup( vol->Ptr );
107                 LOG("Removed volume %s", vol->Name);
108                 free(vol);
109         }
110
111         if( gpLVM_FirstVolume ) 
112                 return EBUSY;
113         
114         return EOK;
115 }
116
117 // --------------------------------------------------------------------
118 // VFS Inteface
119 // --------------------------------------------------------------------
120 char *LVM_Root_ReadDir(tVFS_Node *Node, int ID)
121 {
122         tLVM_Vol        *vol;
123         
124         if( ID < 0 )    return NULL;    
125
126         for( vol = gpLVM_FirstVolume; vol && ID --; vol = vol->Next );
127         
128         if(vol)
129                 return strdup(vol->Name);
130         else
131                 return NULL;
132 }
133 tVFS_Node *LVM_Root_FindDir(tVFS_Node *Node, const char *Name)
134 {
135         tLVM_Vol        *vol;
136         for( vol = gpLVM_FirstVolume; vol; vol = vol->Next )
137         {
138                 if( strcmp(vol->Name, Name) == 0 )
139                 {
140                         return &vol->DirNode;
141                 }
142         }
143         return NULL;
144 }
145
146 char *LVM_Vol_ReadDir(tVFS_Node *Node, int ID)
147 {
148         tLVM_Vol        *vol = Node->ImplPtr;
149         
150         if( ID < 0 || ID >= vol->nSubVolumes+1 )
151                 return NULL;
152
153         if( ID == 0 )
154                 return strdup(".volume");
155         else
156                 return strdup( vol->SubVolumes[ID-1]->Name );
157 }
158 tVFS_Node *LVM_Vol_FindDir(tVFS_Node *Node, const char *Name)
159 {
160         tLVM_Vol        *vol = Node->ImplPtr;
161
162         if( strcmp(".volume", Name) == 0 )
163                 return &vol->VolNode;
164         
165         for( int i = 0; i < vol->nSubVolumes; i ++ )
166         {
167                 if( strcmp(vol->SubVolumes[i]->Name, Name) == 0 )
168                 {
169                         return &vol->SubVolumes[i]->Node;
170                 }
171         }
172
173         return NULL;
174 }
175
176 size_t LVM_Vol_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
177 {
178         tLVM_Vol        *vol = Node->ImplPtr;
179         Uint64  byte_size = vol->BlockCount * vol->BlockSize;   
180
181         if( Offset > byte_size )
182                 return 0;
183         if( Length > byte_size )
184                 Length = byte_size;
185         if( Offset + Length > byte_size )
186                 Length = byte_size - Offset;
187
188         return DrvUtil_ReadBlock(
189                 Offset, Length, Buffer, 
190                 LVM_int_DrvUtil_ReadBlock, vol->BlockSize, vol
191                 );
192 }
193
194 size_t LVM_Vol_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer)
195 {
196         return 0;
197 }
198
199 size_t LVM_SubVol_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
200 {
201         tLVM_SubVolume  *sv = Node->ImplPtr;
202         Uint64  byte_size = sv->BlockCount * sv->Vol->BlockSize;
203
204         if( Offset > byte_size )
205                 return 0;
206         if( Length > byte_size )
207                 Length = byte_size;
208         if( Offset + Length > byte_size )
209                 Length = byte_size - Offset;
210
211         LOG("Reading (0x%llx+0x%llx)+0x%x to %p",
212                 (Uint64)(sv->FirstBlock * sv->Vol->BlockSize), Offset,
213                 Length, Buffer
214                 );
215         
216         Offset += sv->FirstBlock * sv->Vol->BlockSize;  
217
218         return DrvUtil_ReadBlock(
219                 Offset, Length, Buffer, 
220                 LVM_int_DrvUtil_ReadBlock, sv->Vol->BlockSize, sv->Vol
221                 );
222 }
223 size_t LVM_SubVol_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer)
224 {
225         tLVM_SubVolume  *sv = Node->ImplPtr;
226         Uint64  byte_size = sv->BlockCount * sv->Vol->BlockSize;
227
228         if( Offset > byte_size )
229                 return 0;
230         if( Length > byte_size )
231                 Length = byte_size;
232         if( Offset + Length > byte_size )
233                 Length = byte_size - Offset;
234
235         Offset += sv->FirstBlock * sv->Vol->BlockSize;  
236         
237         return DrvUtil_WriteBlock(
238                 Offset, Length, Buffer,
239                 LVM_int_DrvUtil_ReadBlock, LVM_int_DrvUtil_WriteBlock,
240                 sv->Vol->BlockSize, sv->Vol
241                 );
242 }
243
244 Uint LVM_int_DrvUtil_ReadBlock(Uint64 Address, Uint Count, void *Buffer, void *Argument)
245 {
246         return LVM_int_ReadVolume( Argument, Address, Count, Buffer );
247 }
248
249 Uint LVM_int_DrvUtil_WriteBlock(Uint64 Address, Uint Count, const void *Buffer, void *Argument)
250 {
251         return LVM_int_WriteVolume( Argument, Address, Count, Buffer );
252 }
253

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