2 * Acess2 Logical Volume Manager
3 * - By John Hodge (thePowersGang)
9 #define VERSION VER2(0,1)
13 #include <api_drv_disk.h>
17 int LVM_Initialise(char **Arguments);
18 int LVM_Cleanup(void);
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);
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);
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
39 tVFS_NodeType gLVM_VolNodeType = {
40 .ReadDir = LVM_Vol_ReadDir,
41 .FindDir = LVM_Vol_FindDir,
43 .Write = LVM_Vol_Write,
44 .Close = LVM_CloseNode
46 tVFS_NodeType gLVM_SubVolNodeType = {
47 .Read = LVM_SubVol_Read,
48 .Write = LVM_SubVol_Write,
49 .Close = LVM_CloseNode
51 tDevFS_Driver gLVM_DevFS = {
53 {.Flags = VFS_FFLAG_DIRECTORY, .Type = &gLVM_RootNodeType, .Size = -1}
56 tLVM_Vol *gpLVM_FirstVolume;
57 tLVM_Vol *gpLVM_LastVolume = (void*)&gpLVM_FirstVolume;
60 int LVM_Initialise(char **Arguments)
62 DevFS_AddDevice( &gLVM_DevFS );
68 // Attempt to destroy all volumes
69 tLVM_Vol *vol, *prev = NULL, *next;
72 for( vol = gpLVM_FirstVolume; vol; prev = vol, vol = next )
77 for( int i = 0; i < vol->nSubVolumes; i ++ )
80 sv = vol->SubVolumes[i];
86 Mutex_Acquire(&sv->Node.Lock);
87 if(sv->Node.ReferenceCount == 0) {
89 vol->SubVolumes[i] = NULL;
90 Mutex_Release(&sv->Node.Lock);
93 Mutex_Release(&sv->Node.Lock);
97 Mutex_Acquire(&sv->Node.Lock);
98 LOG("Removed subvolume %s:%s", vol->Name, sv->Name);
102 if( nFree != vol->nSubVolumes )
108 gpLVM_FirstVolume = next;
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);
120 if( gpLVM_FirstVolume )
126 // --------------------------------------------------------------------
128 // --------------------------------------------------------------------
129 int LVM_Root_ReadDir(tVFS_Node *Node, int ID, char Dest[FILENAME_MAX])
133 if( ID < 0 ) return -EINVAL;
135 // TODO: Sub-dirs for 'by-uuid', 'by-label' etc
137 for( vol = gpLVM_FirstVolume; vol && ID --; vol = vol->Next );
140 strncpy(Dest, vol->Name, FILENAME_MAX);
146 tVFS_Node *LVM_Root_FindDir(tVFS_Node *Node, const char *Name, Uint Flags)
149 for( vol = gpLVM_FirstVolume; vol; vol = vol->Next )
151 if( strcmp(vol->Name, Name) == 0 )
153 vol->DirNode.ReferenceCount ++;
154 return &vol->DirNode;
160 int LVM_Vol_ReadDir(tVFS_Node *Node, int ID, char Dest[FILENAME_MAX])
162 tLVM_Vol *vol = Node->ImplPtr;
165 if( ID < 0 || ID >= vol->nSubVolumes+1 )
172 src = vol->SubVolumes[ID-1]->Name;
174 strncpy(Dest, src, FILENAME_MAX);
177 tVFS_Node *LVM_Vol_FindDir(tVFS_Node *Node, const char *Name, Uint Flags)
179 tLVM_Vol *vol = Node->ImplPtr;
181 if( strcmp("ROOT", Name) == 0 )
182 return &vol->VolNode;
184 for( int i = 0; i < vol->nSubVolumes; i ++ )
186 if( strcmp(vol->SubVolumes[i]->Name, Name) == 0 )
188 vol->SubVolumes[i]->Node.ReferenceCount ++;
189 return &vol->SubVolumes[i]->Node;
196 size_t LVM_Vol_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uint Flags)
198 tLVM_Vol *vol = Node->ImplPtr;
199 Uint64 byte_size = vol->BlockCount * vol->BlockSize;
201 if( Offset > byte_size )
203 if( Length > byte_size )
205 if( Offset + Length > byte_size )
206 Length = byte_size - Offset;
208 return DrvUtil_ReadBlock(
209 Offset, Length, Buffer,
210 LVM_int_DrvUtil_ReadBlock, vol->BlockSize, vol
214 size_t LVM_Vol_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags)
219 size_t LVM_SubVol_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uint Flags)
221 tLVM_SubVolume *sv = Node->ImplPtr;
222 Uint64 byte_size = sv->BlockCount * sv->Vol->BlockSize;
224 if( Offset > byte_size )
226 if( Length > byte_size )
228 if( Offset + Length > byte_size )
229 Length = byte_size - Offset;
231 LOG("Reading (0x%llx+0x%llx)+0x%x to %p",
232 (Uint64)(sv->FirstBlock * sv->Vol->BlockSize), Offset,
236 Offset += sv->FirstBlock * sv->Vol->BlockSize;
238 return DrvUtil_ReadBlock(
239 Offset, Length, Buffer,
240 LVM_int_DrvUtil_ReadBlock, sv->Vol->BlockSize, sv->Vol
243 size_t LVM_SubVol_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags)
245 tLVM_SubVolume *sv = Node->ImplPtr;
246 Uint64 byte_size = sv->BlockCount * sv->Vol->BlockSize;
248 if( Offset > byte_size )
250 if( Length > byte_size )
252 if( Offset + Length > byte_size )
253 Length = byte_size - Offset;
255 Offset += sv->FirstBlock * sv->Vol->BlockSize;
257 return DrvUtil_WriteBlock(
258 Offset, Length, Buffer,
259 LVM_int_DrvUtil_ReadBlock, LVM_int_DrvUtil_WriteBlock,
260 sv->Vol->BlockSize, sv->Vol
264 void LVM_CloseNode(tVFS_Node *Node)
266 Node->ReferenceCount --;
269 Uint LVM_int_DrvUtil_ReadBlock(Uint64 Address, Uint Count, void *Buffer, void *Argument)
271 return LVM_int_ReadVolume( Argument, Address, Count, Buffer );
274 Uint LVM_int_DrvUtil_WriteBlock(Uint64 Address, Uint Count, const void *Buffer, void *Argument)
276 return LVM_int_WriteVolume( Argument, Address, Count, Buffer );