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

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