Fix extfs reference counts.

This commit is contained in:
Jonas 'Sortie' Termansen 2015-07-08 22:38:40 +02:00
parent 21c82e4467
commit 5deb51eeae
5 changed files with 40 additions and 21 deletions

View File

@ -68,6 +68,10 @@ BlockGroup::BlockGroup(Filesystem* filesystem, uint32_t group_id)
BlockGroup::~BlockGroup() BlockGroup::~BlockGroup()
{ {
Sync(); Sync();
if ( block_bitmap_chunk )
block_bitmap_chunk->Unref();
if ( inode_bitmap_chunk )
inode_bitmap_chunk->Unref();
if ( data_block ) if ( data_block )
data_block->Unref(); data_block->Unref();
filesystem->block_groups[group_id] = NULL; filesystem->block_groups[group_id] = NULL;

View File

@ -171,7 +171,10 @@ void HandleRefer(int chl, struct fsm_req_refer* msg, Filesystem* fs)
if ( fs->num_inodes <= msg->ino ) if ( fs->num_inodes <= msg->ino )
return; return;
if ( Inode* inode = fs->GetInode((uint32_t) msg->ino) ) if ( Inode* inode = fs->GetInode((uint32_t) msg->ino) )
{
inode->RemoteRefer(); inode->RemoteRefer();
inode->Unref();
}
} }
void HandleUnref(int chl, struct fsm_req_unref* msg, Filesystem* fs) 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 ) if ( fs->num_inodes <= msg->ino )
return; return;
if ( Inode* inode = fs->GetInode((uint32_t) msg->ino) ) if ( Inode* inode = fs->GetInode((uint32_t) msg->ino) )
{
inode->RemoteUnref(); inode->RemoteUnref();
inode->Unref();
}
} }
void HandleSync(int chl, struct fsm_req_sync* msg, Filesystem* fs) 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 ) if ( block )
block->Unref(); block->Unref();
inode->Unref();
kernel_entry.d_reclen = sizeof(kernel_entry); kernel_entry.d_reclen = sizeof(kernel_entry);
RespondReadDir(chl, &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); memcpy(path, pathraw, msg->namelen);
path[msg->namelen] = '\0'; path[msg->namelen] = '\0';
Inode* result = inode->Unlink(path, false); bool result = inode->Unlink(path, false);
free(path); free(path);
inode->Unref(); inode->Unref();
if ( !result ) { RespondError(chl, errno); return; } if ( !result ) { RespondError(chl, errno); return; }
result->Unref();
RespondSuccess(chl); 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; } if ( fs->num_inodes <= msg->dirino ) { RespondError(chl, EBADF); return; }
Inode* inode = fs->GetInode((uint32_t) msg->dirino); 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); fprintf(stderr, "%s: filesystem server shutting down, syncing...", argv0);
fflush(stderr); fflush(stderr);
// TODO: Need to close all open inodes here, and in the fuse backend too.
fs->Sync(); fs->Sync();
fprintf(stderr, " done.\n"); fprintf(stderr, " done.\n");
} }

View File

@ -82,7 +82,7 @@ Inode* ext2_fuse_resolve_path(const char* path)
if ( *path == '/' ) if ( *path == '/' )
{ {
if ( !EXT2_S_ISDIR(inode->Mode()) ) if ( !EXT2_S_ISDIR(inode->Mode()) )
return errno = ENOTDIR, (Inode*) NULL; return inode->Unref(), errno = ENOTDIR, (Inode*) NULL;
path++; path++;
continue; continue;
} }
@ -113,7 +113,7 @@ Inode* ext2_fuse_parent_dir(const char** path_ptr)
if ( *path == '/' ) if ( *path == '/' )
{ {
if ( !EXT2_S_ISDIR(inode->Mode()) ) if ( !EXT2_S_ISDIR(inode->Mode()) )
return errno = ENOTDIR, (Inode*) NULL; return inode->Unref(), errno = ENOTDIR, (Inode*) NULL;
path++; path++;
continue; continue;
} }
@ -199,11 +199,10 @@ int ext2_fuse_unlink(const char* path)
Inode* inode = ext2_fuse_parent_dir(&path); Inode* inode = ext2_fuse_parent_dir(&path);
if ( !inode ) if ( !inode )
return -errno; return -errno;
Inode* result = inode->Unlink(path, false); bool result = inode->Unlink(path, false);
inode->Unref(); inode->Unref();
if ( !result ) if ( !result )
return -errno; return -errno;
result->Unref();
return 0; return 0;
} }
@ -344,6 +343,7 @@ int ext2_fuse_create(const char* path, mode_t mode, struct fuse_file_info* fi)
return -errno; return -errno;
fi->fh = (uint64_t) result->inode_id; fi->fh = (uint64_t) result->inode_id;
fi->keep_cache = 1; fi->keep_cache = 1;
result->RemoteRefer();
result->Unref(); result->Unref();
return 0; return 0;
} }

View File

@ -61,7 +61,7 @@ Inode::Inode(Filesystem* filesystem, uint32_t inode_id)
this->data = NULL; this->data = NULL;
this->filesystem = filesystem; this->filesystem = filesystem;
this->reference_count = 1; this->reference_count = 1;
this->remote_reference_count = 1; this->remote_reference_count = 0;
this->inode_id = inode_id; this->inode_id = inode_id;
this->dirty = false; this->dirty = false;
} }
@ -274,6 +274,7 @@ Block* Inode::GetBlock(uint64_t offset)
goto read_doubly; goto read_doubly;
} }
table->Unref();
return NULL; return NULL;
} }
@ -595,7 +596,7 @@ bool Inode::Link(const char* elem, Inode* dest, bool directories)
return true; 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()) ) if ( !EXT2_S_ISDIR(Mode()) )
return errno = ENOTDIR, (Inode*) NULL; return errno = ENOTDIR, (Inode*) NULL;
@ -701,6 +702,15 @@ Inode* Inode::Unlink(const char* elem, bool directories, bool force)
return errno = ENOENT, (Inode*) NULL; 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) ssize_t Inode::ReadAt(uint8_t* buf, size_t s_count, off_t o_offset)
{ {
if ( !EXT2_S_ISREG(Mode()) && !EXT2_S_ISLNK(Mode()) ) 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) ) if ( !Link(path, result, true) )
{ {
error: error:
result->Truncate(0);
memset(result->data, 0, sizeof(*result->data));
// TODO: dtime
result->Unref(); result->Unref();
filesystem->FreeInode(result_inode_id);
return NULL; return NULL;
} }
if ( !result->Link(".", result, true) ) if ( !result->Link(".", result, true) )
{ {
Unlink(path, true); Unlink(path, true, true);
goto error; goto error;
} }
if ( !result->Link("..", this, true) ) if ( !result->Link("..", this, true) )
{ {
result->Unlink(".", true); result->Unlink(".", true, true);
Unlink(path, true); Unlink(path, true, true);
goto error; goto error;
} }
@ -951,11 +957,11 @@ Inode* Inode::CreateDirectory(const char* path, mode_t mode)
bool Inode::RemoveDirectory(const char* path) bool Inode::RemoveDirectory(const char* path)
{ {
Inode* result = Unlink(path, true); Inode* result = UnlinkKeep(path, true);
if ( !result ) if ( !result )
return false; return false;
result->Unlink("..", true); result->Unlink("..", true, true);
result->Unlink(".", true); result->Unlink(".", true, true);
result->Truncate(0); result->Truncate(0);
// Decrease the directory count statistics. // Decrease the directory count statistics.
@ -1035,6 +1041,7 @@ void Inode::Refer()
void Inode::Unref() void Inode::Unref()
{ {
assert(0 < reference_count);
reference_count--; reference_count--;
if ( !reference_count && !remote_reference_count ) if ( !reference_count && !remote_reference_count )
{ {
@ -1051,6 +1058,7 @@ void Inode::RemoteRefer()
void Inode::RemoteUnref() void Inode::RemoteUnref()
{ {
assert(0 < remote_reference_count);
remote_reference_count--; remote_reference_count--;
if ( !reference_count && !remote_reference_count ) if ( !reference_count && !remote_reference_count )
{ {

View File

@ -64,7 +64,8 @@ public:
Inode* Open(const char* elem, int flags, mode_t mode); Inode* Open(const char* elem, int flags, mode_t mode);
bool Link(const char* elem, Inode* dest, bool directories); bool Link(const char* elem, Inode* dest, bool directories);
bool Symlink(const char* elem, const char* dest); 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 ReadAt(uint8_t* buffer, size_t count, off_t offset);
ssize_t WriteAt(const uint8_t* buffer, size_t count, off_t offset); ssize_t WriteAt(const uint8_t* buffer, size_t count, off_t offset);
bool UnembedInInode(); bool UnembedInInode();