// --- Disk Driver Helpers ---
Uint64 DrvUtil_ReadBlock(Uint64 Start, Uint64 Length, void *Buffer,
- tDrvUtil_Read_Callback ReadBlocks, Uint64 BlockSize, Uint Argument)
+ tDrvUtil_Read_Callback ReadBlocks, Uint64 BlockSize, void *Argument)
{
Uint8 tmp[BlockSize]; // C99
Uint64 block = Start / BlockSize;
int tailings;
Uint64 ret;
- ENTER("XStart XLength pBuffer pReadBlocks XBlockSize xArgument",
+ ENTER("XStart XLength pBuffer pReadBlocks XBlockSize pArgument",
Start, Length, Buffer, ReadBlocks, BlockSize, Argument);
// Non aligned start, let's fix that!
Uint64 DrvUtil_WriteBlock(Uint64 Start, Uint64 Length, const void *Buffer,
tDrvUtil_Read_Callback ReadBlocks, tDrvUtil_Write_Callback WriteBlocks,
- Uint64 BlockSize, Uint Argument)
+ Uint64 BlockSize, void *Argument)
{
Uint8 tmp[BlockSize]; // C99
Uint64 block = Start / BlockSize;
int tailings;
Uint64 ret;
- ENTER("XStart XLength pBuffer pReadBlocks pWriteBlocks XBlockSize xArgument",
+ ENTER("XStart XLength pBuffer pReadBlocks pWriteBlocks XBlockSize pArgument",
Start, Length, Buffer, ReadBlocks, WriteBlocks, BlockSize, Argument);
// Non aligned start, let's fix that!
* \param Buffer Destination for read blocks\r
* \param Argument Argument provided in ::DrvUtil_ReadBlock and ::DrvUtil_WriteBlock\r
*/\r
-typedef Uint (*tDrvUtil_Read_Callback)(Uint64 Address, Uint Count, void *Buffer, Uint Argument);\r
-typedef Uint (*tDrvUtil_Write_Callback)(Uint64 Address, Uint Count, const void *Buffer, Uint Argument);\r
+typedef Uint (*tDrvUtil_Read_Callback)(Uint64 Address, Uint Count, void *Buffer, void *Argument);\r
+typedef Uint (*tDrvUtil_Write_Callback)(Uint64 Address, Uint Count, const void *Buffer, void *Argument);\r
\r
/**\r
* \brief Reads a range from a block device using aligned reads\r
* \return Number of bytes read\r
*/\r
extern Uint64 DrvUtil_ReadBlock(Uint64 Start, Uint64 Length, void *Buffer,\r
- tDrvUtil_Read_Callback ReadBlocks, Uint64 BlockSize, Uint Argument);\r
+ tDrvUtil_Read_Callback ReadBlocks, Uint64 BlockSize, void *Argument);\r
/**\r
* \brief Writes a range to a block device using aligned writes\r
* \param Start Base byte offset\r
*/\r
extern Uint64 DrvUtil_WriteBlock(Uint64 Start, Uint64 Length, const void *Buffer,\r
tDrvUtil_Read_Callback ReadBlocks, tDrvUtil_Write_Callback WriteBlocks,\r
- Uint64 BlockSize, Uint Argument);\r
+ Uint64 BlockSize, void *Argument);\r
\r
/**\r
* \}\r
size_t ATA_WriteFS(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer);
int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data);
// Read/Write Interface/Quantiser
-Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk);
-Uint ATA_WriteRaw(Uint64 Address, Uint Count, const void *Buffer, Uint Disk);
+Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, void *Argument);
+Uint ATA_WriteRaw(Uint64 Address, Uint Count, const void *Buffer, void *Argument);
// === GLOBALS ===
MODULE_DEFINE(0, VERSION, i386ATA, ATA_Install, NULL, "PCI", NULL);
}
{
- int ret = DrvUtil_ReadBlock(Offset, Length, Buffer, ATA_ReadRaw, SECTOR_SIZE, disk);
+ int ret = DrvUtil_ReadBlock(
+ Offset, Length, Buffer,
+ ATA_ReadRaw, SECTOR_SIZE, (void*)disk
+ );
//Log("ATA_ReadFS: disk=%i, Offset=%lli, Length=%lli", disk, Offset, Length);
//Debug_HexDump("ATA_ReadFS", Buffer, Length);
LEAVE('i', ret);
Log("ATA_WriteFS: (Node=%p, Offset=0x%llx, Length=0x%llx, Buffer=%p)", Node, Offset, Length, Buffer);
Debug_HexDump("ATA_WriteFS", Buffer, Length);
- return DrvUtil_WriteBlock(Offset, Length, Buffer, ATA_ReadRaw, ATA_WriteRaw, SECTOR_SIZE, disk);
+ return DrvUtil_WriteBlock(
+ Offset, Length, Buffer,
+ ATA_ReadRaw, ATA_WriteRaw, SECTOR_SIZE, (void*)disk
+ );
}
const char *csaATA_IOCtls[] = {DRV_IOCTLNAMES, DRV_DISK_IOCTLNAMES, NULL};
/**
* \fn Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
*/
-Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
+Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, void *Argument)
{
+ int Disk = (tVAddr)Argument;
int ret;
Uint offset;
Uint done = 0;
/**
* \fn Uint ATA_WriteRaw(Uint64 Address, Uint Count, const void *Buffer, Uint Disk)
*/
-Uint ATA_WriteRaw(Uint64 Address, Uint Count, const void *Buffer, Uint Disk)
+Uint ATA_WriteRaw(Uint64 Address, Uint Count, const void *Buffer, void *Argument)
{
+ int Disk = (tVAddr)Argument;
int ret;
Uint offset;
Uint done = 0;
# - Handles MBR Partitions (and eventually others)
#
-OBJ = main.o mbr.o
+OBJ = main.o volumes.o mbr.o
NAME = LVM
-include ../Makefile.tpl
+/*
+ * Acess2 Logical Volume Manager
+ * - By John Hodge (thePowersGang)
+ *
+ * lvm.h
+ * - LVM Core definitions
+ */
+#ifndef _LVM_LVM_H_
+#define _LVM_LVM_H_
+
+#include <acess.h>
+
+// === TYPES ===
+typedef struct sLVM_Vol tLVM_Vol;
+
+// === FUNCTIONS ===
+extern size_t LVM_int_ReadVolume(tLVM_Vol *Volume, Uint64 BlockNum, size_t BlockCount, void *Dest);
+extern size_t LVM_int_WriteVolume(tLVM_Vol *Volume, Uint64 BlockNum, size_t BlockCount, const void *Src);
+
+// --- Subvolume Management ---
+extern void LVM_int_SetSubvolume_Anon(tLVM_Vol *Volume, int Index, Uint64 FirstBlock, Uint64 LastBlock);
+
+#endif
+
* lvm_int.h
* - Internal definitions
*/
+#ifndef _LVM_LVM_INT_H_
+#define _LVM_LVM_INT_H_
+
+#include "lvm.h"
+#include <vfs.h>
+
+typedef struct sLVM_SubVolume tLVM_SubVolume;
+
+struct sLVM_Vol
+{
+ tLVM_Vol *Next;
+
+ tVFS_Node Node;
+
+ int BackingDescriptor;
+ size_t BlockSize;
+
+ int nSubVolumes;
+ tLVM_SubVolume **SubVolumes;
+
+ char Name[];
+};
+
+struct sLVM_SubVolume
+{
+ tLVM_Vol *Vol;
+
+ tVFS_Node Node;
+
+ // Note: Only for a simple volume
+ Uint64 FirstBlock;
+ Uint64 BlockCount;
+
+ char Name[];
+};
+
+extern tVFS_NodeType gLVM_SubVolNodeType;
+
+#endif
+/*
+ * Acess2 Logical Volume Manager
+ * - By John Hodge (thePowersGang)
+ *
+ * lvm.h
+ * - LVM Core definitions
+ */
+#define DEBUG 0
+#define VERSION VER2(0,1)
+#include "lvm_int.h"
+#include <fs_devfs.h>
+#include <modules.h>
+#include <api_drv_disk.h>
+
+// === PROTOTYPES ===
+// ---
+ int LVM_Initialise(char **Arguments);
+void LVM_Cleanup(void);
+// ---
+char *LVM_Root_ReadDir(tVFS_Node *Node, int ID);
+tVFS_Node *LVM_Root_FindDir(tVFS_Node *Node, const char *Name);
+char *LVM_Vol_ReadDir(tVFS_Node *Node, int ID);
+tVFS_Node *LVM_Vol_FindDir(tVFS_Node *Node, const char *Name);
+size_t LVM_SubVol_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer);
+size_t LVM_SubVol_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer);
+
+Uint LVM_int_DrvUtil_ReadBlock(Uint64 Address, Uint Count, void *Buffer, void *Argument);
+Uint LVM_int_DrvUtil_WriteBlock(Uint64 Address, Uint Count, const void *Buffer, void *Argument);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, VERSION, LVM, LVM_Initialise, LVM_Cleanup, NULL);
+tVFS_NodeType gLVM_RootNodeType = {
+ .ReadDir = LVM_Root_ReadDir,
+ .FindDir = LVM_Root_FindDir
+};
+tVFS_NodeType gLVM_VolNodeType = {
+ .ReadDir = LVM_Vol_ReadDir,
+ .FindDir = LVM_Vol_FindDir
+};
+tVFS_NodeType gLVM_SubVolNodeType = {
+ .Read = LVM_SubVol_Read,
+ .Write = LVM_SubVol_Write
+};
+tDevFS_Driver gLVM_DevFS = {
+ NULL, "LVM",
+ {.Flags = VFS_FFLAG_DIRECTORY, .Type = &gLVM_RootNodeType}
+};
+
+tLVM_Vol *gpLVM_FirstVolume;
+tLVM_Vol *gpLVM_LastVolume = (void*)&gpLVM_FirstVolume;
+
+// === CODE ===
+int LVM_Initialise(char **Arguments)
+{
+ DevFS_AddDevice( &gLVM_DevFS );
+ return 0;
+}
+
+void LVM_Cleanup(void)
+{
+
+}
+
+// --------------------------------------------------------------------
+// VFS Inteface
+// --------------------------------------------------------------------
+char *LVM_Root_ReadDir(tVFS_Node *Node, int ID)
+{
+ tLVM_Vol *vol;
+
+ if( ID < 0 ) return NULL;
+
+ for( vol = gpLVM_FirstVolume; vol && ID --; vol = vol->Next );
+
+ if(vol)
+ return strdup(vol->Name);
+ else
+ return NULL;
+}
+tVFS_Node *LVM_Root_FindDir(tVFS_Node *Node, const char *Name)
+{
+ tLVM_Vol *vol;
+ for( vol = gpLVM_FirstVolume; vol; vol = vol->Next )
+ {
+ if( strcmp(vol->Name, Name) == 0 )
+ {
+ return &vol->Node;
+ }
+ }
+ return NULL;
+}
+
+char *LVM_Vol_ReadDir(tVFS_Node *Node, int ID)
+{
+ tLVM_Vol *vol = Node->ImplPtr;
+
+ if( ID < 0 || ID >= vol->nSubVolumes )
+ return NULL;
+
+ return strdup( vol->SubVolumes[ID]->Name );
+}
+tVFS_Node *LVM_Vol_FindDir(tVFS_Node *Node, const char *Name)
+{
+ tLVM_Vol *vol = Node->ImplPtr;
+
+ for( int i = 0; i < vol->nSubVolumes; i ++ )
+ {
+ if( strcmp(vol->SubVolumes[i]->Name, Name) == 0 )
+ {
+ return &vol->SubVolumes[i]->Node;
+ }
+ }
+
+ return NULL;
+}
+
+size_t LVM_SubVol_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
+{
+ tLVM_SubVolume *sv = Node->ImplPtr;
+ Uint64 byte_size = sv->BlockCount * sv->Vol->BlockSize;
+
+ if( Offset > byte_size )
+ return 0;
+ if( Length > byte_size )
+ Length = byte_size;
+ if( Offset + Length > byte_size )
+ Length = byte_size - Offset;
+
+ Offset += sv->FirstBlock * sv->Vol->BlockSize;
+
+ return DrvUtil_ReadBlock(
+ Offset, Length, Buffer,
+ LVM_int_DrvUtil_ReadBlock, sv->Vol->BlockSize, sv->Vol
+ );
+}
+size_t LVM_SubVol_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer)
+{
+ tLVM_SubVolume *sv = Node->ImplPtr;
+ Uint64 byte_size = sv->BlockCount * sv->Vol->BlockSize;
+
+ if( Offset > byte_size )
+ return 0;
+ if( Length > byte_size )
+ Length = byte_size;
+ if( Offset + Length > byte_size )
+ Length = byte_size - Offset;
+
+ Offset += sv->FirstBlock * sv->Vol->BlockSize;
+
+ return DrvUtil_WriteBlock(
+ Offset, Length, Buffer,
+ LVM_int_DrvUtil_ReadBlock, LVM_int_DrvUtil_WriteBlock,
+ sv->Vol->BlockSize, sv->Vol
+ );
+}
+
+Uint LVM_int_DrvUtil_ReadBlock(Uint64 Address, Uint Count, void *Buffer, void *Argument)
+{
+ return LVM_int_ReadVolume( Argument, Address, Count, Buffer );
+}
+
+Uint LVM_int_DrvUtil_WriteBlock(Uint64 Address, Uint Count, const void *Buffer, void *Argument)
+{
+ return LVM_int_WriteVolume( Argument, Address, Count, Buffer );
+}
+
/*
- * Acess2 IDE Harddisk Driver
- * - MBR Parsing Code
+ * Acess2 Logical Volume Manager
+ * - By John Hodge (thePowersGang)
+ *
* mbr.c
+ * - MBR Parsing Code
*/
#define DEBUG 0
#include <acess.h>
-#include "lvm_int.h"
+#include "lvm.h"
+#include "mbr.h"
// === PROTOTYPES ===
-void LVM_MBR_Initialise(int Disk, tMBR *MBR);
-Uint64 LVM_MBR_int_ReadExt(int Disk, Uint64 Addr, Uint64 *Base, Uint64 *Length);
+ int LVM_MBR_CountSubvolumes(tLVM_Vol *Volume, void *FirstSector);
+void LVM_MBR_PopulateSubvolumes(tLVM_Vol *Volume, void *FirstSector);
+Uint64 LVM_MBR_int_ReadExt(tLVM_Vol *Volume, Uint64 Addr, Uint64 *Base, Uint64 *Length);
// === GLOBALS ===
// === CODE ===
/**
- * \fn void ATA_ParseMBR(int Disk, tMBR *MBR)
+ * \brief Initialise a volume as
*/
-void ATA_ParseMBR(int Disk, tMBR *MBR)
+int LVM_MBR_CountSubvolumes(tLVM_Vol *Volume, void *FirstSector)
{
- int i, j = 0, k = 4;
+ tMBR *MBR = FirstSector;
+ int i;
Uint64 extendedLBA;
Uint64 base, len;
+ int numPartitions = 0;
- ENTER("iDisk", Disk);
+ ENTER("pVolume pFirstSector", Volume, FirstSector);
// Count Partitions
- gATA_Disks[Disk].NumPartitions = 0;
+ numPartitions = 0;
extendedLBA = 0;
for( i = 0; i < 4; i ++ )
{
if( MBR->Parts[i].SystemID == 0 ) continue;
- if( MBR->Parts[i].Boot == 0x0 || MBR->Parts[i].Boot == 0x80 // LBA 28
- || MBR->Parts[i].Boot == 0x1 || MBR->Parts[i].Boot == 0x81 // LBA 48
- )
+
+ if( MBR->Parts[i].Boot == 0x0 || MBR->Parts[i].Boot == 0x80 ) // LBA 28
+ {
+ base = MBR->Parts[i].LBAStart;
+ }
+ else if( MBR->Parts[i].Boot == 0x1 || MBR->Parts[i].Boot == 0x81 ) // LBA 48
+ {
+ base = (MBR->Parts[i].StartHi << 16) | MBR->Parts[i].LBAStart;
+ }
+ else
+ continue ; // Invalid, so don't count
+
+ if( MBR->Parts[i].SystemID == 0xF || MBR->Parts[i].SystemID == 5 )
{
- if( MBR->Parts[i].SystemID == 0xF || MBR->Parts[i].SystemID == 5 ) {
- LOG("Extended Partition at 0x%llx", MBR->Parts[i].LBAStart);
- if(extendedLBA != 0) {
- Warning("Disk %i has multiple extended partitions, ignoring rest", Disk);
- continue;
- }
- extendedLBA = MBR->Parts[i].LBAStart;
+ LOG("Extended Partition at 0x%llx", base);
+ if(extendedLBA != 0) {
+ Log_Warning(
+ "LBA MBR",
+ "Volume %p has multiple extended partitions, ignoring all but first",
+ Volume
+ );
continue;
}
- LOG("Primary Partition at 0x%llx", MBR->Parts[i].LBAStart);
-
- gATA_Disks[Disk].NumPartitions ++;
- continue;
+ extendedLBA = base;
+ }
+ else
+ {
+ LOG("Primary Partition at 0x%llx", base);
+ numPartitions ++;
}
- // Invalid Partition, so don't count it
}
while(extendedLBA != 0)
{
- extendedLBA = ATA_MBR_int_ReadExt(Disk, extendedLBA, &base, &len);
+ extendedLBA = LVM_MBR_int_ReadExt(Volume, extendedLBA, &base, &len);
if( extendedLBA == -1 ) break;
- gATA_Disks[Disk].NumPartitions ++;
+ numPartitions ++;
}
- LOG("gATA_Disks[Disk].NumPartitions = %i", gATA_Disks[Disk].NumPartitions);
-
- // Create patition array
- gATA_Disks[Disk].Partitions = malloc( gATA_Disks[Disk].NumPartitions * sizeof(tATA_Partition) );
+ LOG("numPartitions = %i", numPartitions);
+
+ LEAVE('i', numPartitions);
+ return numPartitions;
+}
+
+void LVM_MBR_PopulateSubvolumes(tLVM_Vol *Volume, void *FirstSector)
+{
+ Uint64 extendedLBA;
+ Uint64 base, len;
+ int i, j;
+ tMBR *MBR = FirstSector;
+
+ ENTER("pVolume pFirstSector", Volume, FirstSector);
// --- Fill Partition Info ---
extendedLBA = 0;
base = MBR->Parts[i].LBAStart;
len = MBR->Parts[i].LBALength;
}
- else if( MBR->Parts[i].Boot == 0x1 || MBR->Parts[i].Boot == 0x81 ) // LBA 58
+ else if( MBR->Parts[i].Boot == 0x1 || MBR->Parts[i].Boot == 0x81 ) // LBA 48
{
base = (MBR->Parts[i].StartHi << 16) | MBR->Parts[i].LBAStart;
len = (MBR->Parts[i].LengthHi << 16) | MBR->Parts[i].LBALength;
continue;
if( MBR->Parts[i].SystemID == 0xF || MBR->Parts[i].SystemID == 5 ) {
- if(extendedLBA != 0) {
- Log_Warning("ATA", "Disk %i has multiple extended partitions, ignoring rest", Disk);
- continue;
- }
- extendedLBA = base;
+ if(extendedLBA == 0)
+ extendedLBA = base;
continue;
}
// Create Partition
- ATA_int_MakePartition(
- &gATA_Disks[Disk].Partitions[j], Disk, j,
- base, len
- );
+ LVM_int_SetSubvolume_Anon( Volume, j, base, len );
j ++;
}
// Scan extended partitions
while(extendedLBA != 0)
{
- extendedLBA = ATA_MBR_int_ReadExt(Disk, extendedLBA, &base, &len);
+ extendedLBA = LVM_MBR_int_ReadExt(Volume, extendedLBA, &base, &len);
if(extendedLBA == -1) break;
- ATA_int_MakePartition(
- &gATA_Disks[Disk].Partitions[j], Disk, k, base, len
- );
+ LVM_int_SetSubvolume_Anon( Volume, j, base, len );
+ j ++ ;
}
LEAVE('-');
* \brief Reads an extended partition
* \return LBA of next Extended, -1 on error, 0 for last
*/
-Uint64 ATA_MBR_int_ReadExt(int Disk, Uint64 Addr, Uint64 *Base, Uint64 *Length)
+Uint64 LVM_MBR_int_ReadExt(tLVM_Vol *Volume, Uint64 Addr, Uint64 *Base, Uint64 *Length)
{
Uint64 link = 0;
int bFoundPart = 0;;
tMBR mbr;
Uint64 base, len;
- if( ATA_ReadDMA( Disk, Addr, 1, &mbr ) != 0 )
+ // TODO: Handle non-512 byte sectors
+ if( LVM_int_ReadVolume( Volume, Addr, 1, &mbr ) != 0 )
return -1; // Stop on Errors
for( i = 0; i < 4; i ++ )
len = (mbr.Parts[i].LengthHi << 16) | mbr.Parts[i].LBALength;
}
else {
- Log_Warning("ATA MBR",
- "Unknown partition type 0x%x, Disk %i Ext 0x%llx Part %i",
- mbr.Parts[i].Boot, Disk, Addr, i
+ Log_Warning("LVM MBR",
+ "Unknown partition type 0x%x, Volume %p Ext 0x%llx Part %i",
+ mbr.Parts[i].Boot, Volume, Addr, i
);
return -1;
}
case 0xF:
case 0x5:
if(link != 0) {
- Log_Warning("ATA MBR",
- "Disk %i has two forward links in the extended partition",
- Disk
+ Log_Warning("LVM MBR",
+ "Volume %p has two forward links in the extended partition",
+ Volume
);
return -1;
}
break;
default:
if(bFoundPart) {
- Warning("ATA MBR",
- "Disk %i has more than one partition in the extended partition at 0x%llx",
- Disk, Addr
+ Warning("LVM MBR",
+ "Volume %p has more than one partition in the extended partition at 0x%llx",
+ Volume, Addr
);
return -1;
}
bFoundPart = 1;
- *Base = base;
+ *Base = Addr + base; // Extended partitions are based off the sub-mbr
*Length = len;
break;
}
}
if(!bFoundPart) {
- Log_Warning("ATA MBR",
- "No partition in extended partiton, Disk %i 0x%llx",
- Disk, Addr);
+ Log_Warning("LVM MBR",
+ "No partition in extended partiton, Volume %p 0x%llx",
+ Volume, Addr
+ );
return -1;
}
--- /dev/null
+/*
+ * Acess2 Logical Volume Manager
+ * - By John Hodge (thePowersGang)
+ *
+ * mbr.h
+ * - MBR Definitions
+ */
+#ifndef _LVM_MBR_H_
+#define _LVM_MBR_H_
+
+typedef struct
+{
+ Uint8 BootCode[0x1BE];
+ struct {
+ Uint8 Boot;
+ Uint8 Unused1; // Also CHS Start
+ Uint16 StartHi; // Also CHS Start
+ Uint8 SystemID;
+ Uint8 Unused2; // Also CHS Length
+ Uint16 LengthHi; // Also CHS Length
+ Uint32 LBAStart;
+ Uint32 LBALength;
+ } __attribute__ ((packed)) Parts[4];
+ Uint16 BootFlag; // = 0xAA 55
+} __attribute__ ((packed)) tMBR;
+
+#endif
+/*
+ * Acess2 Logical Volume Manager
+ * - By John Hodge (thePowersGang)
+ *
+ * volumes.c
+ * - Volume management
+ */
+#include "lvm_int.h"
+
+// === PROTOTYPES ===
+
+// === CODE ===
+// --------------------------------------------------------------------
+// Managment / Initialisation
+// --------------------------------------------------------------------
+int LVM_AddVolume(const char *Name, int FD)
+{
+ // Make dummy volume descriptor (for the read code)
+
+ // Determine Type
+
+ // Type->CountSubvolumes
+
+ // Create real volume descriptor
+
+ // Type->PopulateSubvolumes
+
+ // Add to volume list
+
+ return 0;
+}
+
+void LVM_int_SetSubvolume_Anon(tLVM_Vol *Volume, int Index, Uint64 FirstBlock, Uint64 BlockCount)
+{
+ tLVM_SubVolume *sv;
+ int namelen;
+
+ if( Index < 0 || Index >= Volume->nSubVolumes ) {
+ Log_Warning("LVM", "SV ID is out of range (0 < %i < %i)",
+ Index, Volume->nSubVolumes);
+ return ;
+ }
+
+ if( Volume->SubVolumes[Index] ) {
+ Log_Warning("LVM", "Attempt to set SV %i of %p twice", Index, Volume);
+ return ;
+ }
+
+ namelen = snprintf(NULL, 0, "%i", Index);
+
+ sv = malloc( sizeof(tLVM_SubVolume) + namelen + 1 );
+ if(!sv) {
+ // Oh, f*ck
+ return ;
+ }
+ Volume->SubVolumes[Index] = sv;
+
+ sv->Vol = Volume;
+ sprintf(sv->Name, "%i", Index);
+ sv->FirstBlock = FirstBlock;
+ sv->BlockCount = BlockCount;
+ memset(&sv->Node, 0, sizeof(tVFS_Node));
+
+ sv->Node.ImplPtr = sv;
+ sv->Node.Type = &gLVM_SubVolNodeType;
+}
+
+// --------------------------------------------------------------------
+// IO
+// --------------------------------------------------------------------
+size_t LVM_int_ReadVolume(tLVM_Vol *Volume, Uint64 BlockNum, size_t BlockCount, void *Dest)
+{
+ size_t rv;
+ rv = VFS_ReadAt(
+ Volume->BackingDescriptor,
+ BlockNum * Volume->BlockSize,
+ BlockCount * Volume->BlockSize,
+ Dest
+ );
+ return rv / Volume->BlockSize;
+}
+
+size_t LVM_int_WriteVolume(tLVM_Vol *Volume, Uint64 BlockNum, size_t BlockCount, const void *Src)
+{
+ size_t rv;
+ rv = VFS_WriteAt(
+ Volume->BackingDescriptor,
+ BlockNum * Volume->BlockSize,
+ BlockCount * Volume->BlockSize,
+ Src
+ );
+ return rv / Volume->BlockSize;
+}
+
MODULES += Filesystems/Ext2
MODULES += Filesystems/FAT
MODULES += Filesystems/NTFS
+MODULES += Storage/LVM
include $(ACESSDIR)/BuildConf/$(ARCH)/$(PLATFORM).mk