Refactor extfs dirty pattern to BeginWrite then FinishWrite pattern.

This commit is contained in:
Jonas 'Sortie' Termansen 2015-01-30 15:38:10 +01:00
parent 34a832dbf3
commit de21e9c8e2
11 changed files with 142 additions and 74 deletions

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2013.
Copyright(C) Jonas 'Sortie' Termansen 2013, 2014, 2015.
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
@ -82,7 +82,11 @@ void Block::Sync()
pwriteall(device->fd, block_data, device->block_size, file_offset);
}
void Block::Dirty()
void Block::BeginWrite()
{
}
void Block::FinishWrite()
{
if ( !dirty )
{

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2013.
Copyright(C) Jonas 'Sortie' Termansen 2013, 2014, 2015.
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
@ -48,7 +48,8 @@ public:
void Refer();
void Unref();
void Sync();
void Dirty();
void BeginWrite();
void FinishWrite();
void Use();
void Unlink();
void Prelink();

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2013.
Copyright(C) Jonas 'Sortie' Termansen 2013, 2014, 2015.
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
@ -96,22 +96,25 @@ uint32_t BlockGroup::AllocateBlock()
for ( ; block_bitmap_chunk_i < num_bits; block_bitmap_chunk_i++ )
if ( !checkbit(chunk_bits, block_bitmap_chunk_i) )
{
block_bitmap_chunk->BeginWrite();
setbit(chunk_bits, block_bitmap_chunk_i);
block_bitmap_chunk->Dirty();
block_bitmap_chunk->FinishWrite();
BeginWrite();
data->bg_free_blocks_count--;
Dirty();
FinishWrite();
filesystem->BeginWrite();
filesystem->sb->s_free_blocks_count--;
filesystem->Dirty();
filesystem->FinishWrite();
uint32_t group_block_id = chunk_offset + block_bitmap_chunk_i++;
uint32_t block_id = first_block_id + group_block_id;
return block_id;
}
block_bitmap_chunk->Sync();
block_bitmap_chunk->Unref();
block_bitmap_chunk = NULL;
}
BeginWrite();
data->bg_free_blocks_count = 0;
Dirty();
FinishWrite();
return errno = ENOSPC, 0;
}
@ -138,22 +141,25 @@ uint32_t BlockGroup::AllocateInode()
for ( ; inode_bitmap_chunk_i < num_bits; inode_bitmap_chunk_i++ )
if ( !checkbit(chunk_bits, inode_bitmap_chunk_i) )
{
inode_bitmap_chunk->BeginWrite();
setbit(chunk_bits, inode_bitmap_chunk_i);
inode_bitmap_chunk->Dirty();
inode_bitmap_chunk->FinishWrite();
BeginWrite();
data->bg_free_inodes_count--;
Dirty();
FinishWrite();
filesystem->BeginWrite();
filesystem->sb->s_free_inodes_count--;
filesystem->Dirty();
filesystem->FinishWrite();
uint32_t group_inode_id = chunk_offset + inode_bitmap_chunk_i++;
uint32_t inode_id = first_inode_id + group_inode_id;
return inode_id;
}
inode_bitmap_chunk->Sync();
inode_bitmap_chunk->Unref();
inode_bitmap_chunk = NULL;
}
BeginWrite();
data->bg_free_inodes_count = 0;
Dirty();
FinishWrite();
return errno = ENOSPC, 0;
}
@ -166,7 +172,6 @@ void BlockGroup::FreeBlock(uint32_t block_id)
if ( !block_bitmap_chunk || chunk_id != block_alloc_chunk )
{
if ( block_bitmap_chunk )
block_bitmap_chunk->Sync(),
block_bitmap_chunk->Unref();
block_alloc_chunk = chunk_id;
uint32_t block_id = data->bg_block_bitmap + block_alloc_chunk;
@ -174,13 +179,16 @@ void BlockGroup::FreeBlock(uint32_t block_id)
block_bitmap_chunk_i = 0;
}
block_bitmap_chunk->BeginWrite();
uint8_t* chunk_bits = block_bitmap_chunk->block_data;
clearbit(chunk_bits, chunk_bit);
block_bitmap_chunk->Dirty();
block_bitmap_chunk->FinishWrite();
BeginWrite();
data->bg_free_blocks_count++;
Dirty();
FinishWrite();
filesystem->BeginWrite();
filesystem->sb->s_free_blocks_count++;
filesystem->Dirty();
filesystem->FinishWrite();
}
void BlockGroup::FreeInode(uint32_t inode_id)
@ -192,7 +200,6 @@ void BlockGroup::FreeInode(uint32_t inode_id)
if ( !inode_bitmap_chunk || chunk_id != inode_alloc_chunk )
{
if ( inode_bitmap_chunk )
inode_bitmap_chunk->Sync(),
inode_bitmap_chunk->Unref();
inode_alloc_chunk = chunk_id;
uint32_t block_id = data->bg_inode_bitmap + inode_alloc_chunk;
@ -200,13 +207,16 @@ void BlockGroup::FreeInode(uint32_t inode_id)
inode_bitmap_chunk_i = 0;
}
inode_bitmap_chunk->BeginWrite();
uint8_t* chunk_bits = inode_bitmap_chunk->block_data;
clearbit(chunk_bits, chunk_bit);
inode_bitmap_chunk->Dirty();
inode_bitmap_chunk->FinishWrite();
BeginWrite();
data->bg_free_inodes_count++;
Dirty();
FinishWrite();
filesystem->BeginWrite();
filesystem->sb->s_free_inodes_count++;
filesystem->Dirty();
filesystem->FinishWrite();
}
void BlockGroup::Refer()
@ -223,15 +233,22 @@ void BlockGroup::Sync()
{
if ( block_bitmap_chunk )
block_bitmap_chunk->Sync();
if ( inode_bitmap_chunk )
inode_bitmap_chunk->Sync();
if ( dirty )
data_block->Sync();
dirty = false;
}
void BlockGroup::Dirty()
void BlockGroup::BeginWrite()
{
data_block->BeginWrite();
}
void BlockGroup::FinishWrite()
{
dirty = true;
data_block->Dirty();
data_block->FinishWrite();
Use();
}

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2013.
Copyright(C) Jonas 'Sortie' Termansen 2013, 2014, 2015.
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
@ -60,7 +60,8 @@ public:
void Refer();
void Unref();
void Sync();
void Dirty();
void BeginWrite();
void FinishWrite();
void Use();
void Unlink();
void Prelink();

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2013.
Copyright(C) Jonas 'Sortie' Termansen 2013, 2014, 2015.
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
@ -70,15 +70,17 @@ Block* Device::GetBlockZeroed(uint32_t block_id)
{
if ( Block* block = GetCachedBlock(block_id) )
{
block->BeginWrite();
memset(block->block_data, 0, block_size);
block->Dirty();
block->FinishWrite();
return block;
}
Block* block = new Block(this, block_id);
block->block_data = new uint8_t[block_size];
memset(block->block_data, 0, block_size);
block->Prelink();
block->Dirty();
block->BeginWrite();
block->FinishWrite();
return block;
}

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2013.
Copyright(C) Jonas 'Sortie' Termansen 2013, 2014.
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free

View File

@ -305,9 +305,10 @@ void HandleUTimens(int chl, struct fsm_req_utimens* msg, Filesystem* fs)
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; }
Inode* inode = fs->GetInode((uint32_t) msg->ino);
if ( !inode ) { RespondError(chl, errno); return; }
inode->BeginWrite();
inode->data->i_atime = msg->times[0].tv_sec;
inode->data->i_mtime = msg->times[1].tv_sec;
inode->Dirty();
inode->FinishWrite();
inode->Unref();
RespondSuccess(chl);
}
@ -1177,7 +1178,6 @@ int ext2_fuse_readdir(const char* /*path*/, void* buf, fuse_fill_dir_t filler,
if ( block )
block->Unref();
inode->Sync();
inode->Unref();
return 0;
}
@ -1192,9 +1192,10 @@ int ext2_fuse_utimens(const char* path, const struct timespec tv[2])
Inode* inode = ext2_fuse_resolve_path(path);
if ( !inode )
return -errno;
inode->BeginWrite();
inode->data->i_atime = tv[0].tv_sec;
inode->data->i_mtime = tv[1].tv_sec;
inode->Dirty();
inode->FinishWrite();
inode->Unref();
return 0;
}

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2013.
Copyright(C) Jonas 'Sortie' Termansen 2013, 2014, 2015.
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
@ -64,10 +64,11 @@ Filesystem::Filesystem(Device* device)
clock_gettime(CLOCK_MONOTONIC, &now_monotonic);
mtime_realtime = now_realtime.tv_sec;
mtime_monotonic = now_monotonic.tv_sec;
BeginWrite();
sb->s_mtime = mtime_realtime;
sb->s_mnt_count++;
sb->s_state = EXT2_ERROR_FS;
Dirty();
FinishWrite();
Sync();
}
@ -79,16 +80,22 @@ Filesystem::~Filesystem()
for ( size_t i = 0; i < num_groups; i++ )
delete block_groups[i];
delete[] block_groups;
BeginWrite();
sb->s_state = EXT2_VALID_FS;
Dirty();
FinishWrite();
Sync();
sb_block->Unref();
}
void Filesystem::Dirty()
void Filesystem::BeginWrite()
{
sb_block->BeginWrite();
}
void Filesystem::FinishWrite()
{
dirty = true;
sb_block->Dirty();
sb_block->FinishWrite();
}
void Filesystem::Sync()
@ -185,8 +192,9 @@ uint32_t Filesystem::AllocateBlock(BlockGroup* preferred)
// rebuild all these values upon filesystem mount instead so we know
// this can't happen. That also allows us to make the linked list
// requested above.
BeginWrite();
sb->s_free_blocks_count--;
Dirty();
FinishWrite();
return errno = ENOSPC, 0;
}
@ -206,8 +214,9 @@ uint32_t Filesystem::AllocateInode(BlockGroup* preferred)
// rebuild all these values upon filesystem mount instead so we know
// this can't happen. That also allows us to make the linked list
// requested above.
BeginWrite();
sb->s_free_inodes_count--;
Dirty();
FinishWrite();
return errno = ENOSPC, 0;
}

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2013.
Copyright(C) Jonas 'Sortie' Termansen 2013, 2014, 2015.
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
@ -60,7 +60,8 @@ public:
uint32_t AllocateInode(BlockGroup* preferred = NULL);
void FreeBlock(uint32_t block_id);
void FreeInode(uint32_t inode_id);
void Dirty();
void BeginWrite();
void FinishWrite();
void Sync();
};

View File

@ -82,9 +82,10 @@ uint32_t Inode::Mode()
void Inode::SetMode(uint32_t mode)
{
BeginWrite();
// TODO: Use i_mode_high.
data->i_mode = (uint16_t) mode;
Dirty();
FinishWrite();
}
uint32_t Inode::UserId()
@ -95,9 +96,10 @@ uint32_t Inode::UserId()
void Inode::SetUserId(uint32_t user)
{
BeginWrite();
// TODO: Use i_uid_high.
data->i_uid = (uint16_t) user;
Dirty();
FinishWrite();
}
uint32_t Inode::GroupId()
@ -108,9 +110,10 @@ uint32_t Inode::GroupId()
void Inode::SetGroupId(uint32_t group)
{
BeginWrite();
// TODO: Use i_gid_high.
data->i_gid = (uint16_t) group;
Dirty();
FinishWrite();
}
uint64_t Inode::Size()
@ -150,24 +153,28 @@ void Inode::SetSize(uint64_t new_size)
actual_blocks += divup(logical_blocks - max_singly, ENTRIES * ENTRIES);
if ( max_doubly <= logical_blocks )
actual_blocks += divup(logical_blocks - max_doubly, ENTRIES * ENTRIES * ENTRIES);
data->i_blocks = (actual_blocks * filesystem->block_size) / 512;
BeginWrite();
data->i_blocks = (actual_blocks * filesystem->block_size) / 512;
if ( EXT2_S_ISREG(data->i_mode) && largefile )
data->i_dir_acl = upper;
Dirty();
FinishWrite();
Modified();
}
void Inode::Linked()
{
BeginWrite();
data->i_links_count++;
Dirty();
FinishWrite();
}
void Inode::Unlinked()
{
BeginWrite();
data->i_links_count--;
Dirty();
FinishWrite();
}
Block* Inode::GetBlockFromTable(Block* table, uint32_t index)
@ -182,8 +189,9 @@ Block* Inode::GetBlockFromTable(Block* table, uint32_t index)
if ( block_id )
{
Block* block = filesystem->device->GetBlockZeroed(block_id);
table->BeginWrite();
((uint32_t*) table->block_data)[index] = block_id;
table->Dirty();
table->FinishWrite();
return block;
}
return NULL;
@ -276,6 +284,7 @@ bool Inode::FreeIndirect(uint64_t from, uint64_t offset, uint32_t block_id,
Block* block = filesystem->device->GetBlock(block_id);
uint32_t* table = (uint32_t*) block->block_data;
bool any_children = false;
bool begun_writing = false;
for ( uint64_t i = 0; i < ENTRIES; i++ )
{
if ( !table[i] )
@ -290,9 +299,15 @@ bool Inode::FreeIndirect(uint64_t from, uint64_t offset, uint32_t block_id,
continue;
}
filesystem->FreeBlock(table[i]);
if ( !begun_writing )
{
block->BeginWrite();
begun_writing = true;
}
table[i] = 0;
block->Dirty();
}
if ( begun_writing )
block->FinishWrite();
return any_children;
}
@ -319,8 +334,9 @@ void Inode::Truncate(uint64_t new_size)
{
Block* partial_block = GetBlock(new_num_blocks-1);
uint8_t* data = partial_block->block_data;
partial_block->BeginWrite();
memset(data + partial, 0, filesystem->block_size - partial);
partial_block->Dirty();
partial_block->FinishWrite();
}
const uint64_t ENTRIES = filesystem->block_size / sizeof(uint32_t);
@ -333,6 +349,8 @@ void Inode::Truncate(uint64_t new_size)
uint64_t max_doubly = max_singly + block_doubly;
uint64_t max_triply = max_doubly + block_triply;
BeginWrite();
for ( uint64_t i = new_num_blocks; i < old_num_blocks && i < 12; i++ )
{
filesystem->FreeBlock(data->i_block[i]);
@ -359,7 +377,7 @@ void Inode::Truncate(uint64_t new_size)
(void) max_triply;
Dirty();
FinishWrite();
}
Inode* Inode::Open(const char* elem, int flags, mode_t mode)
@ -520,6 +538,8 @@ bool Inode::Link(const char* elem, Inode* dest, bool directories)
if ( !block && !(block = GetBlock(block_id = hole_block_id)) )
return NULL;
block->BeginWrite();
uint8_t* block_data = block->block_data + hole_block_offset;
struct ext_dirent* entry = (struct ext_dirent*) block_data;
@ -528,7 +548,6 @@ bool Inode::Link(const char* elem, Inode* dest, bool directories)
{
entry->reclen = roundup(sizeof(struct ext_dirent) + entry->name_len, (size_t) 4);
assert(entry->reclen);
// Block marked dirty below.
block_data += entry->reclen;
entry = (struct ext_dirent*) block_data;
}
@ -544,7 +563,7 @@ bool Inode::Link(const char* elem, Inode* dest, bool directories)
assert(entry->reclen);
block->Dirty();
block->FinishWrite();
dest->Linked();
@ -610,6 +629,9 @@ Inode* Inode::Unlink(const char* elem, bool directories, bool force)
}
inode->Unlinked();
block->BeginWrite();
entry->inode = 0;
entry->name_len = 0;
entry->file_type = 0;
@ -628,7 +650,6 @@ Inode* Inode::Unlink(const char* elem, bool directories, bool force)
strncpy(entry->name + entry->name_len, "",
entry->reclen - sizeof(struct ext_dirent) - entry->name_len);
assert(entry->reclen);
block->Dirty();
// If the entire block is empty, we'll need to remove it.
if ( !entry->name[0] && entry->reclen == block_size )
@ -641,12 +662,13 @@ Inode* Inode::Unlink(const char* elem, bool directories, bool force)
{
Block* last_block = GetBlock(num_blocks-1);
memcpy(block->block_data, last_block->block_data, block_size);
block->Dirty();
last_block->Unref();
}
Truncate(filesize - block_size);
}
block->FinishWrite();
block->Unref();
return inode;
@ -733,8 +755,9 @@ ssize_t Inode::WriteAt(const uint8_t* buf, size_t s_count, off_t o_offset)
if ( !block )
return sofar ? sofar : -1;
size_t amount = count - sofar < block_left ? count - sofar : block_left;
block->BeginWrite();
memcpy(block->block_data + block_offset, buf + sofar, amount);
block->Dirty();
block->FinishWrite();
sofar += amount;
offset += amount;
block->Unref();
@ -835,8 +858,9 @@ Inode* Inode::CreateDirectory(const char* path, mode_t mode)
uint32_t group_id = (result->inode_id - 1) / filesystem->sb->s_inodes_per_group;
assert(group_id < filesystem->num_groups);
BlockGroup* block_group = filesystem->GetBlockGroup(group_id);
block_group->BeginWrite();
block_group->data->bg_used_dirs_count++;
block_group->Dirty();
block_group->FinishWrite();
block_group->Unref();
struct timespec now;
@ -886,8 +910,9 @@ bool Inode::RemoveDirectory(const char* path)
uint32_t group_id = (result->inode_id - 1) / filesystem->sb->s_inodes_per_group;
assert(group_id < filesystem->num_groups);
BlockGroup* block_group = filesystem->GetBlockGroup(group_id);
block_group->BeginWrite();
block_group->data->bg_used_dirs_count--;
block_group->Dirty();
block_group->FinishWrite();
block_group->Unref();
result->Unref();
@ -939,13 +964,14 @@ void Inode::Delete()
Truncate(0);
uint32_t deleted_inode_id = inode_id;
memset(data, 0, sizeof(*data));
struct timespec now;
clock_gettime(CLOCK_REALTIME, &now);
data->i_dtime = now.tv_sec;
Dirty();
delete this;
BeginWrite();
memset(data, 0, sizeof(*data));
data->i_dtime = now.tv_sec;
FinishWrite();
filesystem->FreeInode(deleted_inode_id);
}
@ -962,8 +988,7 @@ void Inode::Unref()
{
if ( !data->i_links_count )
Delete();
else
delete this;
delete this;
}
}
@ -979,8 +1004,7 @@ void Inode::RemoteUnref()
{
if ( !data->i_links_count )
Delete();
else
delete this;
delete this;
}
}
@ -988,11 +1012,17 @@ void Inode::Modified()
{
struct timespec now;
clock_gettime(CLOCK_REALTIME, &now);
BeginWrite();
data->i_mtime = now.tv_sec;
Dirty();
FinishWrite();
}
void Inode::Dirty()
void Inode::BeginWrite()
{
data_block->BeginWrite();
}
void Inode::FinishWrite()
{
struct timespec now;
clock_gettime(CLOCK_REALTIME, &now);
@ -1006,7 +1036,7 @@ void Inode::Dirty()
next_dirty->prev_dirty = this;
filesystem->dirty_inode = this;
}
data_block->Dirty();
data_block->FinishWrite();
Use();
}
@ -1015,6 +1045,7 @@ void Inode::Sync()
if ( !dirty )
return;
data_block->Sync();
// TODO: The inode contents needs to be sync'd as well!
(prev_dirty ? prev_dirty->next_dirty : filesystem->dirty_inode) = next_dirty;
if ( next_dirty )
next_dirty->prev_dirty = prev_dirty;

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2013.
Copyright(C) Jonas 'Sortie' Termansen 2013, 2014, 2015.
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
@ -76,7 +76,8 @@ public:
void RemoteRefer();
void RemoteUnref();
void Sync();
void Dirty();
void BeginWrite();
void FinishWrite();
void Modified();
void Use();
void Unlink();