From 5deb51eeae478c31048a05912ace47269441b7ce Mon Sep 17 00:00:00 2001 From: Jonas 'Sortie' Termansen Date: Wed, 8 Jul 2015 22:38:40 +0200 Subject: [PATCH] Fix extfs reference counts. --- ext/blockgroup.cpp | 4 ++++ ext/fsmarshall.cpp | 14 ++++++++++---- ext/fuse.cpp | 8 ++++---- ext/inode.cpp | 32 ++++++++++++++++++++------------ ext/inode.h | 3 ++- 5 files changed, 40 insertions(+), 21 deletions(-) diff --git a/ext/blockgroup.cpp b/ext/blockgroup.cpp index 2875611f..44cd039a 100644 --- a/ext/blockgroup.cpp +++ b/ext/blockgroup.cpp @@ -68,6 +68,10 @@ BlockGroup::BlockGroup(Filesystem* filesystem, uint32_t group_id) BlockGroup::~BlockGroup() { Sync(); + if ( block_bitmap_chunk ) + block_bitmap_chunk->Unref(); + if ( inode_bitmap_chunk ) + inode_bitmap_chunk->Unref(); if ( data_block ) data_block->Unref(); filesystem->block_groups[group_id] = NULL; diff --git a/ext/fsmarshall.cpp b/ext/fsmarshall.cpp index d9561539..b7f40a6d 100644 --- a/ext/fsmarshall.cpp +++ b/ext/fsmarshall.cpp @@ -171,7 +171,10 @@ void HandleRefer(int chl, struct fsm_req_refer* msg, Filesystem* fs) if ( fs->num_inodes <= msg->ino ) return; if ( Inode* inode = fs->GetInode((uint32_t) msg->ino) ) + { inode->RemoteRefer(); + inode->Unref(); + } } void HandleUnref(int chl, struct fsm_req_unref* msg, Filesystem* fs) @@ -180,7 +183,10 @@ void HandleUnref(int chl, struct fsm_req_unref* msg, Filesystem* fs) if ( fs->num_inodes <= msg->ino ) return; if ( Inode* inode = fs->GetInode((uint32_t) msg->ino) ) + { inode->RemoteUnref(); + inode->Unref(); + } } void HandleSync(int chl, struct fsm_req_sync* msg, Filesystem* fs) @@ -410,6 +416,7 @@ void HandleReadDir(int chl, struct fsm_req_readdirents* msg, Filesystem* fs) } if ( block ) block->Unref(); + inode->Unref(); kernel_entry.d_reclen = sizeof(kernel_entry); RespondReadDir(chl, &kernel_entry); @@ -441,18 +448,16 @@ void HandleUnlink(int chl, struct fsm_req_unlink* msg, Filesystem* fs) memcpy(path, pathraw, msg->namelen); path[msg->namelen] = '\0'; - Inode* result = inode->Unlink(path, false); + bool result = inode->Unlink(path, false); free(path); inode->Unref(); if ( !result ) { RespondError(chl, errno); return; } - result->Unref(); - RespondSuccess(chl); } -void HandleRemoveDir(int chl, struct fsm_req_unlink* msg, Filesystem* fs) +void HandleRemoveDir(int chl, struct fsm_req_rmdir* msg, Filesystem* fs) { if ( fs->num_inodes <= msg->dirino ) { RespondError(chl, EBADF); return; } Inode* inode = fs->GetInode((uint32_t) msg->dirino); @@ -772,6 +777,7 @@ int fsmarshall_main(const char* argv0, { fprintf(stderr, "%s: filesystem server shutting down, syncing...", argv0); fflush(stderr); + // TODO: Need to close all open inodes here, and in the fuse backend too. fs->Sync(); fprintf(stderr, " done.\n"); } diff --git a/ext/fuse.cpp b/ext/fuse.cpp index e4c990b3..607016b7 100644 --- a/ext/fuse.cpp +++ b/ext/fuse.cpp @@ -82,7 +82,7 @@ Inode* ext2_fuse_resolve_path(const char* path) if ( *path == '/' ) { if ( !EXT2_S_ISDIR(inode->Mode()) ) - return errno = ENOTDIR, (Inode*) NULL; + return inode->Unref(), errno = ENOTDIR, (Inode*) NULL; path++; continue; } @@ -113,7 +113,7 @@ Inode* ext2_fuse_parent_dir(const char** path_ptr) if ( *path == '/' ) { if ( !EXT2_S_ISDIR(inode->Mode()) ) - return errno = ENOTDIR, (Inode*) NULL; + return inode->Unref(), errno = ENOTDIR, (Inode*) NULL; path++; continue; } @@ -199,11 +199,10 @@ int ext2_fuse_unlink(const char* path) Inode* inode = ext2_fuse_parent_dir(&path); if ( !inode ) return -errno; - Inode* result = inode->Unlink(path, false); + bool result = inode->Unlink(path, false); inode->Unref(); if ( !result ) return -errno; - result->Unref(); return 0; } @@ -344,6 +343,7 @@ int ext2_fuse_create(const char* path, mode_t mode, struct fuse_file_info* fi) return -errno; fi->fh = (uint64_t) result->inode_id; fi->keep_cache = 1; + result->RemoteRefer(); result->Unref(); return 0; } diff --git a/ext/inode.cpp b/ext/inode.cpp index dee3502e..5e9c8dca 100644 --- a/ext/inode.cpp +++ b/ext/inode.cpp @@ -61,7 +61,7 @@ Inode::Inode(Filesystem* filesystem, uint32_t inode_id) this->data = NULL; this->filesystem = filesystem; this->reference_count = 1; - this->remote_reference_count = 1; + this->remote_reference_count = 0; this->inode_id = inode_id; this->dirty = false; } @@ -274,6 +274,7 @@ Block* Inode::GetBlock(uint64_t offset) goto read_doubly; } + table->Unref(); return NULL; } @@ -595,7 +596,7 @@ bool Inode::Link(const char* elem, Inode* dest, bool directories) return true; } -Inode* Inode::Unlink(const char* elem, bool directories, bool force) +Inode* Inode::UnlinkKeep(const char* elem, bool directories, bool force) { if ( !EXT2_S_ISDIR(Mode()) ) return errno = ENOTDIR, (Inode*) NULL; @@ -701,6 +702,15 @@ Inode* Inode::Unlink(const char* elem, bool directories, bool force) return errno = ENOENT, (Inode*) NULL; } +bool Inode::Unlink(const char* elem, bool directories, bool force) +{ + Inode* result = UnlinkKeep(elem, directories, force); + if ( !result ) + return false; + result->Unref(); + return true; +} + ssize_t Inode::ReadAt(uint8_t* buf, size_t s_count, off_t o_offset) { if ( !EXT2_S_ISREG(Mode()) && !EXT2_S_ISLNK(Mode()) ) @@ -925,24 +935,20 @@ Inode* Inode::CreateDirectory(const char* path, mode_t mode) if ( !Link(path, result, true) ) { error: - result->Truncate(0); - memset(result->data, 0, sizeof(*result->data)); - // TODO: dtime result->Unref(); - filesystem->FreeInode(result_inode_id); return NULL; } if ( !result->Link(".", result, true) ) { - Unlink(path, true); + Unlink(path, true, true); goto error; } if ( !result->Link("..", this, true) ) { - result->Unlink(".", true); - Unlink(path, true); + result->Unlink(".", true, true); + Unlink(path, true, true); goto error; } @@ -951,11 +957,11 @@ Inode* Inode::CreateDirectory(const char* path, mode_t mode) bool Inode::RemoveDirectory(const char* path) { - Inode* result = Unlink(path, true); + Inode* result = UnlinkKeep(path, true); if ( !result ) return false; - result->Unlink("..", true); - result->Unlink(".", true); + result->Unlink("..", true, true); + result->Unlink(".", true, true); result->Truncate(0); // Decrease the directory count statistics. @@ -1035,6 +1041,7 @@ void Inode::Refer() void Inode::Unref() { + assert(0 < reference_count); reference_count--; if ( !reference_count && !remote_reference_count ) { @@ -1051,6 +1058,7 @@ void Inode::RemoteRefer() void Inode::RemoteUnref() { + assert(0 < remote_reference_count); remote_reference_count--; if ( !reference_count && !remote_reference_count ) { diff --git a/ext/inode.h b/ext/inode.h index d96389ba..4ca09a8b 100644 --- a/ext/inode.h +++ b/ext/inode.h @@ -64,7 +64,8 @@ public: Inode* Open(const char* elem, int flags, mode_t mode); bool Link(const char* elem, Inode* dest, bool directories); bool Symlink(const char* elem, const char* dest); - Inode* Unlink(const char* elem, bool directories, bool force=false); + bool Unlink(const char* elem, bool directories, bool force=false); + Inode* UnlinkKeep(const char* elem, bool directories, bool force=false); ssize_t ReadAt(uint8_t* buffer, size_t count, off_t offset); ssize_t WriteAt(const uint8_t* buffer, size_t count, off_t offset); bool UnembedInInode();