/**
* \brief Write to a file
*/
-size_t Ext2_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer)
+size_t Ext2_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags)
{
tExt2_Disk *disk = Node->ImplPtr;
tExt2_Inode inode;
int bNewBlocks = 0;
Debug_HexDump("Ext2_Write", Buffer, Length);
-
+
+ // TODO: Handle (Flags & VFS_IOFLAG_NOBLOCK)
+
Ext2_int_ReadInode(disk, Node->Inode, &inode);
// Get the ammount of space already allocated
block = Ext2_int_AllocateBlock(disk, base/disk->BlockSize);
if(!block) return Length - retLen;
// Add it to this inode
- if( !Ext2_int_AppendBlock(disk, &inode, block) ) {
+ if( Ext2_int_AppendBlock(disk, &inode, block) ) {
+ Log_Warning("Ext2", "Appending %x to inode %p:%X failed",
+ block, disk, Node->Inode);
Ext2_int_DeallocateBlock(disk, block);
goto ret;
}
// Last block :D
block = Ext2_int_AllocateBlock(disk, base/disk->BlockSize);
if(!block) goto ret;
- if( !Ext2_int_AppendBlock(disk, &inode, block) ) {
+ if( Ext2_int_AppendBlock(disk, &inode, block) ) {
+ Log_Warning("Ext2", "Appending %x to inode %p:%X failed",
+ block, disk, Node->Inode);
Ext2_int_DeallocateBlock(disk, block);
goto ret;
}
base = block * disk->BlockSize;
VFS_WriteAt(disk->FD, base, retLen, Buffer);
+
+ // TODO: When should the size update be committed?
inode.i_size += retLen;
+ Node->Size += retLen;
+ Node->Flags |= VFS_FFLAG_DIRTY;
+
retLen = 0;
ret: // Makes sure the changes to the inode are committed
Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock)
{
int bpg = Disk->SuperBlock.s_blocks_per_group;
- Uint blockgroup = PrevBlock / bpg;
- Uint bitmap[Disk->BlockSize/sizeof(Uint)];
- Uint bitsperblock = 8*Disk->BlockSize;
- int i, j = 0;
- Uint block;
-
+ Uint firstgroup = PrevBlock / bpg;
+ Uint blockgroup = firstgroup;
+ tExt2_Group *bg;
+
+ // TODO: Need to do locking on the bitmaps
+
// Are there any free blocks?
- if(Disk->SuperBlock.s_free_blocks_count == 0) return 0;
-
- if(Disk->Groups[blockgroup].bg_free_blocks_count > 0)
+ if(Disk->SuperBlock.s_free_blocks_count == 0)
+ return 0;
+
+ // First: Check the next block after \a PrevBlock
+ if( (PrevBlock + 1) % Disk->SuperBlock.s_blocks_per_group != 0
+ && Disk->Groups[blockgroup].bg_free_blocks_count > 0 )
{
- // Search block group's bitmap
- for(i = 0; i < bpg; i++)
+ bg = &Disk->Groups[blockgroup];
+ const int sector_size = 512;
+ Uint8 buf[sector_size];
+ int iblock = (PrevBlock + 1) % Disk->SuperBlock.s_blocks_per_group;
+ int byte = iblock / 8;
+ int ofs = byte / sector_size * sector_size;
+ byte %= sector_size;
+ VFS_ReadAt(Disk->FD, Disk->BlockSize*bg->bg_block_bitmap+ofs, sector_size, buf);
+
+ if( (buf[byte] & (1 << (iblock%8))) == 0 )
{
- // Get the block in the bitmap block
- j = i & (bitsperblock-1);
-
- // Read in if needed
- if(j == 0) {
- VFS_ReadAt(
- Disk->FD,
- (Uint64)Disk->Groups[blockgroup].bg_block_bitmap + i / bitsperblock,
- Disk->BlockSize,
- bitmap
- );
- }
-
- // Fast Check
- if( bitmap[j/32] == 0xFFFFFFFF ) {
- j = (j + 31) & ~31;
- continue;
- }
-
- // Is the bit set?
- if( bitmap[j/32] & (1 << (j%32)) )
- continue;
-
- // Ooh! We found one
- break;
- }
- if( i < bpg ) {
- Warning("[EXT2 ] Inconsistency detected, Group Free Block count is non-zero when no free blocks exist");
- goto checkAll; // Search the entire filesystem for a free block
- // Goto needed for neatness
+ // Free block - nice and contig allocation
+ buf[byte] |= (1 << (iblock%8));
+ VFS_WriteAt(Disk->FD, Disk->BlockSize*bg->bg_block_bitmap+ofs, sector_size, buf);
+
+ bg->bg_free_blocks_count --;
+ Disk->SuperBlock.s_free_blocks_count --;
+ #if EXT2_UPDATE_WRITEBACK
+ Ext2_int_UpdateSuperblock(Disk);
+ #endif
+ return PrevBlock + 1;
}
-
- // Mark as used
- bitmap[j/32] |= (1 << (j%32));
- VFS_WriteAt(
- Disk->FD,
- (Uint64)Disk->Groups[blockgroup].bg_block_bitmap + i / bitsperblock,
- Disk->BlockSize,
- bitmap
- );
- block = i;
- Disk->Groups[blockgroup].bg_free_blocks_count --;
- #if EXT2_UPDATE_WRITEBACK
- //Ext2_int_UpdateBlockGroup(Disk, blockgroup);
- #endif
+ // Used... darnit
+ // Fall through and search further
}
- else
+
+ // Second: Search for a group with free blocks
+ while( blockgroup < Disk->GroupCount && Disk->Groups[blockgroup].bg_free_blocks_count == 0 )
+ blockgroup ++;
+ if( Disk->Groups[blockgroup].bg_free_blocks_count == 0 )
{
- checkAll:
- Log_Warning("EXT2", "TODO - Implement using blocks outside the current block group");
+ blockgroup = 0;
+ while( blockgroup < firstgroup && Disk->Groups[blockgroup].bg_free_blocks_count == 0 )
+ blockgroup ++;
+ }
+ if( Disk->Groups[blockgroup].bg_free_blocks_count == 0 ) {
+ Log_Notice("Ext2", "Ext2_int_AllocateBlock - Out of blockss on %p, but superblock says some free",
+ Disk);
return 0;
}
+
+ // Search the bitmap for a free block
+ bg = &Disk->Groups[blockgroup];
+ int ofs = 0;
+ do {
+ const int sector_size = 512;
+ Uint8 buf[sector_size];
+ VFS_ReadAt(Disk->FD, Disk->BlockSize*bg->bg_block_bitmap+ofs, sector_size, buf);
+
+ int byte, bit;
+ for( byte = 0; byte < sector_size && buf[byte] != 0xFF; byte ++ )
+ ;
+ if( byte < sector_size )
+ {
+ for( bit = 0; bit < 8 && buf[byte] & (1 << bit); bit ++)
+ ;
+ ASSERT(bit != 8);
+ buf[byte] |= 1 << bit;
+ VFS_WriteAt(Disk->FD, Disk->BlockSize*bg->bg_block_bitmap+ofs, sector_size, buf);
+
+ bg->bg_free_blocks_count --;
+ Disk->SuperBlock.s_free_blocks_count --;
+
+ #if EXT2_UPDATE_WRITEBACK
+ Ext2_int_UpdateSuperblock(Disk);
+ #endif
+
+ Uint32 ret = blockgroup * Disk->SuperBlock.s_blocks_per_group + byte * 8 + bit;
+ Log_Debug("Ext2", "Ext2_int_AllocateBlock - Allocated 0x%x", ret);
+ return ret;
+ }
+ } while(ofs < Disk->SuperBlock.s_blocks_per_group / 8);
- // Reduce global count
- Disk->SuperBlock.s_free_blocks_count --;
- #if EXT2_UPDATE_WRITEBACK
- Ext2_int_UpdateSuperblock(Disk);
- #endif
-
- return block;
+ Log_Notice("Ext2", "Ext2_int_AllocateBlock - Out of block in group %p:%i but header reported free",
+ Disk, blockgroup);
+ return 0;
}
/**
*/
void Ext2_int_DeallocateBlock(tExt2_Disk *Disk, Uint32 Block)
{
+ Log_Warning("Ext2", "TODO: Impliment Ext2_int_DeallocateBlock");
}
/**
if( nBlocks == 0 ) {
Inode->i_block[12] = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]);
if( !Inode->i_block[12] ) {
+ Log_Warning("Ext2", "Allocating indirect block failed");
free(blocks);
return 1;
}
if( nBlocks == 0 ) {
Inode->i_block[13] = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]);
if( !Inode->i_block[13] ) {
+ Log_Warning("Ext2", "Allocating double indirect block failed");
free(blocks);
return 1;
}
id1 = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]);
if( !id1 ) {
free(blocks);
+ Log_Warning("Ext2", "Allocating double indirect block (l2) failed");
return 1;
}
blocks[nBlocks/dwPerBlock] = id1;
if( nBlocks == 0 ) {
Inode->i_block[14] = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]);
if( !Inode->i_block[14] ) {
+ Log_Warning("Ext2", "Allocating triple indirect block failed");
free(blocks);
return 1;
}
{
id1 = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]);
if( !id1 ) {
+ Log_Warning("Ext2", "Allocating triple indirect block (l2) failed");
free(blocks);
return 1;
}
if( nBlocks % dwPerBlock == 0 ) {
id2 = Ext2_int_AllocateBlock(Disk, id1);
if( !id2 ) {
+ Log_Warning("Ext2", "Allocating triple indirect block (l3) failed");
free(blocks);
return 1;
}
return 0;
}
- Warning("[EXT2 ] Inode %i cannot have a block appended to it, all indirects used");
+ Log_Warning("Ext2", "Inode ?? cannot have a block appended to it, all indirects used");
free(blocks);
return 1;
}