From de21e9c8e20fa06c1d8c84b1bf7b23f92822a93e Mon Sep 17 00:00:00 2001 From: Jonas 'Sortie' Termansen Date: Fri, 30 Jan 2015 15:38:10 +0100 Subject: [PATCH] Refactor extfs dirty pattern to BeginWrite then FinishWrite pattern. --- ext/block.cpp | 8 +++-- ext/block.h | 5 +-- ext/blockgroup.cpp | 59 +++++++++++++++++++----------- ext/blockgroup.h | 5 +-- ext/device.cpp | 8 +++-- ext/device.h | 2 +- ext/extfs.cpp | 7 ++-- ext/filesystem.cpp | 23 ++++++++---- ext/filesystem.h | 5 +-- ext/inode.cpp | 89 +++++++++++++++++++++++++++++++--------------- ext/inode.h | 5 +-- 11 files changed, 142 insertions(+), 74 deletions(-) diff --git a/ext/block.cpp b/ext/block.cpp index 8299e232..b75dcc64 100644 --- a/ext/block.cpp +++ b/ext/block.cpp @@ -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 ) { diff --git a/ext/block.h b/ext/block.h index 6a3f68f4..77c32f03 100644 --- a/ext/block.h +++ b/ext/block.h @@ -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(); diff --git a/ext/blockgroup.cpp b/ext/blockgroup.cpp index f600cd43..2875611f 100644 --- a/ext/blockgroup.cpp +++ b/ext/blockgroup.cpp @@ -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(); } diff --git a/ext/blockgroup.h b/ext/blockgroup.h index 4038f29f..e0699b36 100644 --- a/ext/blockgroup.h +++ b/ext/blockgroup.h @@ -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(); diff --git a/ext/device.cpp b/ext/device.cpp index 4c7a38ab..7e451857 100644 --- a/ext/device.cpp +++ b/ext/device.cpp @@ -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; } diff --git a/ext/device.h b/ext/device.h index b736f408..29a01a26 100644 --- a/ext/device.h +++ b/ext/device.h @@ -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 diff --git a/ext/extfs.cpp b/ext/extfs.cpp index 90f298e2..fd261ad4 100644 --- a/ext/extfs.cpp +++ b/ext/extfs.cpp @@ -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; } diff --git a/ext/filesystem.cpp b/ext/filesystem.cpp index bff163cc..180ff81d 100644 --- a/ext/filesystem.cpp +++ b/ext/filesystem.cpp @@ -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; } diff --git a/ext/filesystem.h b/ext/filesystem.h index 2c1ebdfc..071f2106 100644 --- a/ext/filesystem.h +++ b/ext/filesystem.h @@ -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(); }; diff --git a/ext/inode.cpp b/ext/inode.cpp index 3bd22b75..fb85e890 100644 --- a/ext/inode.cpp +++ b/ext/inode.cpp @@ -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; diff --git a/ext/inode.h b/ext/inode.h index 18dd1a37..2e398adf 100644 --- a/ext/inode.h +++ b/ext/inode.h @@ -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();