From 260a45ace7787128b9b9748fcb9ffd003af00a5d Mon Sep 17 00:00:00 2001 From: Michael Vrable Date: Tue, 31 Aug 2010 15:00:09 -0700 Subject: [PATCH] Fix some resource leaks in journal replay. --- bluesky/bluesky-private.h | 2 ++ bluesky/inode.c | 75 +++++++++++++++++++++++---------------- bluesky/log.c | 1 + 3 files changed, 48 insertions(+), 30 deletions(-) diff --git a/bluesky/bluesky-private.h b/bluesky/bluesky-private.h index fcdba98..3cfec78 100644 --- a/bluesky/bluesky-private.h +++ b/bluesky/bluesky-private.h @@ -33,6 +33,8 @@ extern int bluesky_watermark_high_total; /* TODO: Make this go away entirely. */ BlueSkyFS *bluesky_new_fs(gchar *name); +void bluesky_inode_free_resources(BlueSkyInode *inode); + /* Linked list update functions for LRU lists. */ void bluesky_list_unlink(GList *head, GList *item); GList *bluesky_list_prepend(GList *head, BlueSkyInode *inode); diff --git a/bluesky/inode.c b/bluesky/inode.c index 9878559..7560010 100644 --- a/bluesky/inode.c +++ b/bluesky/inode.c @@ -141,6 +141,50 @@ void bluesky_inode_ref(BlueSkyInode *inode) g_atomic_int_inc(&inode->refcount); } +/* Free most of the resources used by an inode structure, but do not free the + * inode itself. Can be used if the inode data will be reloaded from + * serialized form to clear out old information first. */ +void bluesky_inode_free_resources(BlueSkyInode *inode) +{ + switch (inode->type) { + case BLUESKY_REGULAR: + if (inode->blocks != NULL) { + for (int i = 0; i < inode->blocks->len; i++) { + BlueSkyBlock *b = &g_array_index(inode->blocks, + BlueSkyBlock, i); + if (b->type == BLUESKY_BLOCK_DIRTY) { + g_error("Deleting an inode with dirty file data!"); + } + bluesky_cloudlog_unref(b->ref); + bluesky_string_unref(b->dirty); + } + g_array_unref(inode->blocks); + inode->blocks = NULL; + } + break; + + case BLUESKY_DIRECTORY: + if (inode->dirhash != NULL) + g_hash_table_destroy(inode->dirhash); + inode->dirhash = NULL; + if (inode->dirhash_folded != NULL) + g_hash_table_destroy(inode->dirhash_folded); + inode->dirhash_folded = NULL; + if (inode->dirents != NULL) + g_sequence_free(inode->dirents); + inode->dirents = NULL; + break; + + case BLUESKY_SYMLINK: + g_free(inode->symlink_contents); + inode->symlink_contents = NULL; + break; + + default: + break; + } +} + void bluesky_inode_unref(BlueSkyInode *inode) { if (g_atomic_int_dec_and_test(&inode->refcount)) { @@ -167,38 +211,9 @@ void bluesky_inode_unref(BlueSkyInode *inode) bluesky_list_unlink(&inode->fs->unlogged_list, inode->unlogged_list); g_mutex_unlock(inode->fs->lock); - /* Free file type specific data. It should be an error for there to be - * dirty data to commit when the reference count has reaches zero. */ - switch (inode->type) { - case BLUESKY_REGULAR: - for (int i = 0; i < inode->blocks->len; i++) { - BlueSkyBlock *b = &g_array_index(inode->blocks, - BlueSkyBlock, i); - if (b->type == BLUESKY_BLOCK_DIRTY) { - g_error("Deleting an inode with dirty file data!"); - } - bluesky_cloudlog_unref(b->ref); - bluesky_string_unref(b->dirty); - } - g_array_unref(inode->blocks); - break; - - case BLUESKY_DIRECTORY: - g_hash_table_destroy(inode->dirhash); - g_hash_table_destroy(inode->dirhash_folded); - g_sequence_free(inode->dirents); - break; - - case BLUESKY_SYMLINK: - g_free(inode->symlink_contents); - break; - - default: - break; - } + bluesky_inode_free_resources(inode); g_mutex_free(inode->lock); - g_free(inode); } } diff --git a/bluesky/log.c b/bluesky/log.c index f8062cf..c94794c 100644 --- a/bluesky/log.c +++ b/bluesky/log.c @@ -757,6 +757,7 @@ static void bluesky_replay_scan_journal2(BlueSkyFS *fs, GList **objects, bluesky_insert_inode(fs, inode); } g_mutex_lock(inode->lock); + bluesky_inode_free_resources(inode); if (!bluesky_deserialize_inode(inode, log_item)) g_print("Error deserializing inode %"PRIu64"\n", inum); fs->next_inum = MAX(fs->next_inum, inum + 1); -- 2.20.1