From c92b18f7074e6d632c555bed5897c5723abde720 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 16 Dec 2012 21:15:07 -0600 Subject: [PATCH] Refactoring/rewrites New function dentry_tree_fix_inodes() to de-duplicate some code in read_metadata_resource() and wimlib_add_image(). In wimlib_export_image(), search through the inode list when looking for lookup table entries to export instead of the dentry tree. In wimlib_mount_image(), search through the inode list when resolving lookup table entries, and update the inode numbers at the same time. --- src/add_image.c | 25 ++----- src/export_image.c | 156 ++++++++++++++++++---------------------- src/hardlink.c | 55 ++++++++++++-- src/lookup_table.c | 60 ++++++++-------- src/lookup_table.h | 2 + src/metadata_resource.c | 12 +--- src/mount_image.c | 17 +++-- src/wim.c | 6 -- src/wimlib_internal.h | 38 +++------- 9 files changed, 175 insertions(+), 196 deletions(-) diff --git a/src/add_image.c b/src/add_image.c index 20b554eb..082c5023 100644 --- a/src/add_image.c +++ b/src/add_image.c @@ -53,7 +53,7 @@ * @sd: The security data for the image. */ int add_new_dentry_tree(WIMStruct *w, struct dentry *root_dentry, - struct wim_security_data *sd) + struct wim_security_data *sd) { struct lookup_table_entry *metadata_lte; struct image_metadata *imd; @@ -87,18 +87,12 @@ int add_new_dentry_tree(WIMStruct *w, struct dentry *root_dentry, new_imd->root_dentry = root_dentry; new_imd->metadata_lte = metadata_lte; new_imd->security_data = sd; - new_imd->modified = true; + new_imd->modified = 1; FREE(w->image_metadata); - w->image_metadata = imd; + w->image_metadata = imd; w->hdr.image_count++; - - /* Change the current image to the new one. There should not be any - * ways for this to fail, since the image is valid and the dentry tree - * is already in memory. */ - ret = select_wim_image(w, w->hdr.image_count); - wimlib_assert(ret == 0); - return ret; + return 0; err_free_imd: FREE(imd); err: @@ -640,7 +634,6 @@ WIMLIBAPI int wimlib_add_image(WIMStruct *w, const char *source, struct dentry *root_dentry = NULL; struct wim_security_data *sd; struct capture_config config; - struct inode_table inode_tab; struct hlist_head inode_list; int ret; @@ -737,16 +730,8 @@ WIMLIBAPI int wimlib_add_image(WIMStruct *w, const char *source, if (ret != 0) goto out_free_dentry_tree; - DEBUG("Inserting dentries into inode table"); - ret = init_inode_table(&inode_tab, 9001); - if (ret != 0) - goto out_destroy_imd; - - for_dentry_in_tree(root_dentry, inode_table_insert, &inode_tab); - DEBUG("Cleaning up the hard link groups"); - ret = fix_inodes(&inode_tab, &inode_list); - destroy_inode_table(&inode_tab); + ret = dentry_tree_fix_inodes(root_dentry, &inode_list); if (ret != 0) goto out_destroy_imd; diff --git a/src/export_image.c b/src/export_image.c index 6d38855d..a24950ad 100644 --- a/src/export_image.c +++ b/src/export_image.c @@ -26,34 +26,22 @@ #include "lookup_table.h" #include "xml.h" -struct wim_pair { - WIMStruct *src_wim; - WIMStruct *dest_wim; - struct list_head lte_list_head; -}; - -static int allocate_lte_if_needed(struct dentry *dentry, void *arg) +static int inode_allocate_needed_ltes(struct inode *inode, + struct lookup_table *src_lookup_table, + struct lookup_table *dest_lookup_table, + struct list_head *lte_list_head) { - const WIMStruct *src_wim, *dest_wim; - struct list_head *lte_list_head; - struct inode *inode; - - src_wim = ((struct wim_pair*)arg)->src_wim; - dest_wim = ((struct wim_pair*)arg)->dest_wim; - lte_list_head = &((struct wim_pair*)arg)->lte_list_head; - inode = dentry->d_inode; + struct lookup_table_entry *src_lte, *dest_lte; + unsigned i; - wimlib_assert(!inode->resolved); - - for (unsigned i = 0; i <= inode->num_ads; i++) { - struct lookup_table_entry *src_lte, *dest_lte; + inode_unresolve_ltes(inode); + for (i = 0; i <= inode->num_ads; i++) { src_lte = inode_stream_lte_unresolved(inode, i, - src_wim->lookup_table); - - if (src_lte && ++src_lte->out_refcnt == 1) { + src_lookup_table); + if (src_lte && src_lte->out_refcnt == 0) { + src_lte->out_refcnt = 1; dest_lte = inode_stream_lte_unresolved(inode, i, - dest_wim->lookup_table); - + dest_lookup_table); if (!dest_lte) { dest_lte = clone_lookup_table_entry(src_lte); if (!dest_lte) @@ -65,57 +53,40 @@ static int allocate_lte_if_needed(struct dentry *dentry, void *arg) return 0; } -/* - * This function takes in a dentry that was previously located only in image(s) - * in @src_wim, but now is being added to @dest_wim. For each stream associated - * with the dentry, if there is already a lookup table entry for that stream in - * the lookup table of the destination WIM file, its reference count is - * incrementej. Otherwise, a new lookup table entry is created that points back - * to the stream in the source WIM file (through the @hash field combined with - * the @wim field of the lookup table entry.) - */ -static int add_lte_to_dest_wim(struct dentry *dentry, void *arg) +static void inode_move_ltes_to_table(struct inode *inode, + struct lookup_table *src_lookup_table, + struct lookup_table *dest_lookup_table, + struct list_head *lte_list_head) { - WIMStruct *src_wim, *dest_wim; - struct inode *inode; - - src_wim = ((struct wim_pair*)arg)->src_wim; - dest_wim = ((struct wim_pair*)arg)->dest_wim; - inode = dentry->d_inode; - - wimlib_assert(!inode->resolved); - - for (unsigned i = 0; i <= inode->num_ads; i++) { - struct lookup_table_entry *src_lte, *dest_lte; - src_lte = inode_stream_lte_unresolved(inode, i, - src_wim->lookup_table); - - if (!src_lte) /* Empty or nonexistent stream. */ - continue; + struct lookup_table_entry *src_lte, *dest_lte; + unsigned i; + struct dentry *dentry; - dest_lte = inode_stream_lte_unresolved(inode, i, - dest_wim->lookup_table); - if (dest_lte) { - dest_lte->refcnt++; - } else { - struct list_head *lte_list_head; - struct list_head *next; - - lte_list_head = &((struct wim_pair*)arg)->lte_list_head; - wimlib_assert(!list_empty(lte_list_head)); + inode_for_each_dentry(dentry, inode) + dentry->refcnt++; - next = lte_list_head->next; - list_del(next); - dest_lte = container_of(next, struct lookup_table_entry, - staging_list); - dest_lte->part_number = 1; - dest_lte->refcnt = 1; - wimlib_assert(hashes_equal(dest_lte->hash, src_lte->hash)); - - lookup_table_insert(dest_wim->lookup_table, dest_lte); + for (i = 0; i <= inode->num_ads; i++) { + src_lte = inode_stream_lte_unresolved(inode, i, src_lookup_table); + if (src_lte) { + dest_lte = inode_stream_lte_unresolved(inode, i, + dest_lookup_table); + if (!dest_lte) { + struct list_head *next; + + wimlib_assert(!list_empty(lte_list_head)); + next = lte_list_head->next; + list_del(next); + dest_lte = container_of(next, + struct lookup_table_entry, + staging_list); + dest_lte->part_number = 1; + dest_lte->refcnt = 0; + wimlib_assert(hashes_equal(dest_lte->hash, src_lte->hash)); + lookup_table_insert(dest_lookup_table, dest_lte); + } + dest_lte->refcnt += inode->link_count; } } - return 0; } /* @@ -131,12 +102,13 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim, unsigned num_additional_swms, wimlib_progress_func_t progress_func) { - int i; int ret; - struct dentry *root; - struct wim_pair wims; struct wim_security_data *sd; struct lookup_table *joined_tab, *src_wim_tab_save; + struct image_metadata *src_imd; + struct hlist_node *cur_node; + struct list_head lte_list_head; + struct inode *inode; if (dest_wim->hdr.total_parts != 1) { ERROR("Exporting an image to a split WIM is " @@ -168,7 +140,7 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim, "multiple images"); return WIMLIB_ERR_INVALID_PARAM; } - for (i = 1; i <= src_wim->hdr.image_count; i++) { + for (int i = 1; i <= src_wim->hdr.image_count; i++) { int new_flags = export_flags; if (i != src_wim->hdr.boot_idx) @@ -236,15 +208,18 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim, /* Pre-allocate the new lookup table entries that will be needed. This * way, it's not possible to run out of memory part-way through * modifying the lookup table of the destination WIM. */ - wims.src_wim = src_wim; - wims.dest_wim = dest_wim; - INIT_LIST_HEAD(&wims.lte_list_head); + INIT_LIST_HEAD(<e_list_head); for_lookup_table_entry(src_wim->lookup_table, lte_zero_out_refcnt, NULL); - root = wim_root_dentry(src_wim); - for_dentry_in_tree(root, dentry_unresolve_ltes, NULL); - ret = for_dentry_in_tree(root, allocate_lte_if_needed, &wims); - if (ret != 0) - goto out_free_ltes; + src_imd = wim_get_current_image_metadata(src_wim); + + hlist_for_each_entry(inode, cur_node, &src_imd->inode_list, hlist) { + ret = inode_allocate_needed_ltes(inode, + src_wim->lookup_table, + dest_wim->lookup_table, + <e_list_head); + if (ret != 0) + goto out_free_ltes; + } ret = xml_export_image(src_wim->wim_info, src_image, &dest_wim->wim_info, dest_name, @@ -252,21 +227,26 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim, if (ret != 0) goto out_free_ltes; - sd = wim_security_data(src_wim); - ret = add_new_dentry_tree(dest_wim, root, sd); + sd = src_imd->security_data; + ret = add_new_dentry_tree(dest_wim, src_imd->root_dentry, sd); if (ret != 0) goto out_xml_delete_image; + dest_wim->image_metadata[ + dest_wim->hdr.image_count - 1].inode_list = src_imd->inode_list; /* All memory allocations have been taken care of, so it's no longer * possible for this function to fail. Go ahead and increment the * reference counts of the dentry tree and security data, then update * the lookup table of the destination WIM and the boot index, if * needed. */ - for_dentry_in_tree(root, increment_dentry_refcnt, NULL); sd->refcnt++; - for_dentry_in_tree(root, add_lte_to_dest_wim, &wims); - wimlib_assert(list_empty(&wims.lte_list_head)); + hlist_for_each_entry(inode, cur_node, &src_imd->inode_list, hlist) { + inode_move_ltes_to_table(inode, + src_wim->lookup_table, + dest_wim->lookup_table, + <e_list_head); + } if (export_flags & WIMLIB_EXPORT_FLAG_BOOT) wimlib_set_boot_idx(dest_wim, dest_wim->hdr.image_count); @@ -278,7 +258,7 @@ out_xml_delete_image: out_free_ltes: { struct lookup_table_entry *lte, *tmp; - list_for_each_entry_safe(lte, tmp, &wims.lte_list_head, staging_list) + list_for_each_entry_safe(lte, tmp, <e_list_head, staging_list) free_lookup_table_entry(lte); } diff --git a/src/hardlink.c b/src/hardlink.c index e3f9e27a..7603670d 100644 --- a/src/hardlink.c +++ b/src/hardlink.c @@ -51,8 +51,34 @@ * ----------------- */ +/* Hash table to find inodes, identified by their inode ID. + * */ +struct inode_table { + /* Fields for the hash table */ + struct hlist_head *array; + u64 num_entries; + u64 capacity; + + /* + * Linked list of "extra" inodes. These may be: + * + * - inodes with link count 1, which are all allowed to have 0 for their + * inode number, meaning we cannot insert them into the hash table + * before calling assign_inode_numbers(). + * + * - Groups we create ourselves by splitting a nominal inode due to + * inconsistencies in the dentries. These inodes will share a inode + * ID with some other inode until assign_inode_numbers() is called. + */ + struct hlist_head extra_inodes; +}; + +static inline void destroy_inode_table(struct inode_table *table) +{ + FREE(table->array); +} -int init_inode_table(struct inode_table *table, size_t capacity) +static int init_inode_table(struct inode_table *table, size_t capacity) { table->array = CALLOC(capacity, sizeof(table->array[0])); if (!table->array) { @@ -65,7 +91,6 @@ int init_inode_table(struct inode_table *table, size_t capacity) return 0; } - static inline size_t inode_link_count(const struct inode *inode) { const struct list_head *cur; @@ -90,7 +115,7 @@ static inline size_t inode_link_count(const struct inode *inode) * we keep a linked list of the single dentries, and assign them inode * numbers later. */ -int inode_table_insert(struct dentry *dentry, void *__table) +static int inode_table_insert(struct dentry *dentry, void *__table) { struct inode_table *table = __table; struct inode *d_inode = dentry->d_inode; @@ -279,8 +304,8 @@ static int fix_true_inode(struct inode *inode, struct hlist_head *inode_list) * inodes'. There will be just one `struct inode' for each hard link group * remaining. */ -static int -fix_nominal_inode(struct inode *inode, struct hlist_head *inode_list) +static int fix_nominal_inode(struct inode *inode, + struct hlist_head *inode_list) { struct dentry *dentry; struct hlist_node *cur, *tmp; @@ -413,7 +438,7 @@ next_dentry_2: * split inodes as well as the inodes that were good before, is returned in the * list @inode_list. */ -int fix_inodes(struct inode_table *table, struct hlist_head *inode_list) +static int fix_inodes(struct inode_table *table, struct hlist_head *inode_list) { struct inode *inode; struct hlist_node *cur, *tmp; @@ -430,3 +455,21 @@ int fix_inodes(struct inode_table *table, struct hlist_head *inode_list) hlist_add_head(cur, inode_list); return 0; } + +int dentry_tree_fix_inodes(struct dentry *root, struct hlist_head *inode_list) +{ + struct inode_table inode_tab; + int ret; + + DEBUG("Inserting dentries into inode table"); + ret = init_inode_table(&inode_tab, 9001); + if (ret != 0) + return ret; + + for_dentry_in_tree(root, inode_table_insert, &inode_tab); + + DEBUG("Cleaning up the hard link groups"); + ret = fix_inodes(&inode_tab, inode_list); + destroy_inode_table(&inode_tab); + return ret; +} diff --git a/src/lookup_table.c b/src/lookup_table.c index f0359961..67ce92a3 100644 --- a/src/lookup_table.c +++ b/src/lookup_table.c @@ -633,39 +633,40 @@ out: void inode_resolve_ltes(struct inode *inode, struct lookup_table *table) { - struct lookup_table_entry *lte; - - wimlib_assert(!inode->resolved); - /* Resolve the default file stream */ - lte = __lookup_resource(table, inode->hash); - inode->lte = lte; - inode->resolved = 1; - - /* Resolve the alternate data streams */ - for (u16 i = 0; i < inode->num_ads; i++) { - struct ads_entry *cur_entry = &inode->ads_entries[i]; - lte = __lookup_resource(table, cur_entry->hash); - cur_entry->lte = lte; + if (!inode->resolved) { + struct lookup_table_entry *lte; + /* Resolve the default file stream */ + lte = __lookup_resource(table, inode->hash); + inode->lte = lte; + inode->resolved = 1; + + /* Resolve the alternate data streams */ + for (u16 i = 0; i < inode->num_ads; i++) { + struct ads_entry *cur_entry = &inode->ads_entries[i]; + lte = __lookup_resource(table, cur_entry->hash); + cur_entry->lte = lte; + } } } -static void inode_unresolve_ltes(struct inode *inode) +void inode_unresolve_ltes(struct inode *inode) { - wimlib_assert(inode->resolved); - if (inode->lte) - copy_hash(inode->hash, inode->lte->hash); - else - zero_out_hash(inode->hash); - - for (u16 i = 0; i < inode->num_ads; i++) { - if (inode->ads_entries[i].lte) - copy_hash(inode->ads_entries[i].hash, - inode->ads_entries[i].lte->hash); + if (inode->resolved) { + if (inode->lte) + copy_hash(inode->hash, inode->lte->hash); else - zero_out_hash(inode->ads_entries[i].hash); + zero_out_hash(inode->hash); + + for (u16 i = 0; i < inode->num_ads; i++) { + if (inode->ads_entries[i].lte) + copy_hash(inode->ads_entries[i].hash, + inode->ads_entries[i].lte->hash); + else + zero_out_hash(inode->ads_entries[i].hash); + } + inode->resolved = 0; } - inode->resolved = 0; } /* Resolve a dentry's lookup table entries @@ -679,15 +680,14 @@ static void inode_unresolve_ltes(struct inode *inode) */ int dentry_resolve_ltes(struct dentry *dentry, void *table) { - if (!dentry->d_inode->resolved) - inode_resolve_ltes(dentry->d_inode, table); + wimlib_assert(dentry->refcnt == 1); + inode_resolve_ltes(dentry->d_inode, table); return 0; } int dentry_unresolve_ltes(struct dentry *dentry, void *ignore) { - if (dentry->d_inode->resolved) - inode_unresolve_ltes(dentry->d_inode); + inode_unresolve_ltes(dentry->d_inode); return 0; } diff --git a/src/lookup_table.h b/src/lookup_table.h index 7038cc5d..05ffbe6e 100644 --- a/src/lookup_table.h +++ b/src/lookup_table.h @@ -288,6 +288,8 @@ extern void inode_resolve_ltes(struct inode *inode, struct lookup_table *table); extern int dentry_resolve_ltes(struct dentry *dentry, void *__table); + +extern void inode_unresolve_ltes(struct inode *inode); extern int dentry_unresolve_ltes(struct dentry *dentry, void *ignore); int write_lookup_table(struct lookup_table *table, FILE *out, diff --git a/src/metadata_resource.c b/src/metadata_resource.c index 4f8be141..19723269 100644 --- a/src/metadata_resource.c +++ b/src/metadata_resource.c @@ -48,7 +48,6 @@ int read_metadata_resource(WIMStruct *w, struct image_metadata *imd) u32 dentry_offset; int ret; struct dentry *dentry; - struct inode_table inode_tab; const struct lookup_table_entry *metadata_lte; u64 metadata_len; struct hlist_head inode_list; @@ -157,16 +156,7 @@ int read_metadata_resource(WIMStruct *w, struct image_metadata *imd) goto out_free_dentry_tree; /* Build hash table that maps hard link group IDs to dentry sets */ - DEBUG("Building link group table"); - ret = init_inode_table(&inode_tab, 9001); - if (ret != 0) - goto out_free_dentry_tree; - - for_dentry_in_tree(dentry, inode_table_insert, &inode_tab); - - DEBUG("Fixing inconsistencies in the hard link groups"); - ret = fix_inodes(&inode_tab, &inode_list); - destroy_inode_table(&inode_tab); + ret = dentry_tree_fix_inodes(dentry, &inode_list); if (ret != 0) goto out_free_dentry_tree; diff --git a/src/mount_image.c b/src/mount_image.c index d3021a53..4add2a5e 100644 --- a/src/mount_image.c +++ b/src/mount_image.c @@ -1939,6 +1939,8 @@ WIMLIBAPI int wimlib_mount_image(WIMStruct *wim, int image, const char *dir, struct lookup_table *joined_tab, *wim_tab_save; struct image_metadata *imd; struct wimfs_context ctx; + struct hlist_node *cur_node; + struct inode *inode; DEBUG("Mount: wim = %p, image = %d, dir = %s, flags = %d, ", wim, image, dir, mount_flags); @@ -2072,15 +2074,18 @@ WIMLIBAPI int wimlib_mount_image(WIMStruct *wim, int image, const char *dir, imd->has_been_mounted_rw = 1; } - /* Resolve all the lookup table entries of the dentry tree */ - DEBUG("Resolving lookup table entries"); - for_dentry_in_tree(imd->root_dentry, dentry_resolve_ltes, - wim->lookup_table); + /* Resolve the lookup table entries for every inode in the image, and + * assign inode numbers */ + DEBUG("Resolving lookup table entries and assigning inode numbers"); - ctx.next_ino = assign_inode_numbers(&imd->inode_list); + ctx.next_ino = 1; + hlist_for_each_entry(inode, cur_node, &imd->inode_list, hlist) { + inode_resolve_ltes(inode, wim->lookup_table); + inode->ino = ctx.next_ino++; + } + /*ctx.next_ino = assign_inode_numbers(&imd->inode_list);*/ DEBUG("(next_ino = %"PRIu64")", ctx.next_ino); - DEBUG("Calling fuse_main()"); ret = fuse_main(argc, argv, &wimfs_operations, &ctx); diff --git a/src/wim.c b/src/wim.c index af5098cb..5a38688b 100644 --- a/src/wim.c +++ b/src/wim.c @@ -43,12 +43,6 @@ #include "lookup_table.h" #include "xml.h" -static inline struct image_metadata * -wim_get_current_image_metadata(WIMStruct *w) -{ - return &w->image_metadata[w->current_image - 1]; -} - static int print_metadata(WIMStruct *w) { DEBUG("Printing metadata for image %d", w->current_image); diff --git a/src/wimlib_internal.h b/src/wimlib_internal.h index 7f2ee178..458cacef 100644 --- a/src/wimlib_internal.h +++ b/src/wimlib_internal.h @@ -320,6 +320,12 @@ wim_const_security_data(const WIMStruct *w) return w->image_metadata[w->current_image - 1].security_data; } +static inline struct image_metadata * +wim_get_current_image_metadata(WIMStruct *w) +{ + return &w->image_metadata[w->current_image - 1]; +} + /* Nonzero if a struct resource_entry indicates a compressed resource. */ static inline int resource_is_compressed(const struct resource_entry *entry) { @@ -358,36 +364,10 @@ extern int add_new_dentry_tree(WIMStruct *dest_wim, struct dentry *root, /* hardlink.c */ -/* Hash table to find inodes, identified by their inode ID. - * */ -struct inode_table { - /* Fields for the hash table */ - struct hlist_head *array; - u64 num_entries; - u64 capacity; - - /* - * Linked list of "extra" inodes. These may be: - * - * - inodes with link count 1, which are all allowed to have 0 for their - * inode number, meaning we cannot insert them into the hash table - * before calling assign_inode_numbers(). - * - * - Groups we create ourselves by splitting a nominal inode due to - * inconsistencies in the dentries. These inodes will share a inode - * ID with some other inode until assign_inode_numbers() is called. - */ - struct hlist_head extra_inodes; -}; - -extern int init_inode_table(struct inode_table *table, size_t capacity); -static inline void destroy_inode_table(struct inode_table *table) -{ - FREE(table->array); -} -extern int inode_table_insert(struct dentry *dentry, void *__table); extern u64 assign_inode_numbers(struct hlist_head *inode_list); -extern int fix_inodes(struct inode_table *table, struct hlist_head *inode_list); + +extern int dentry_tree_fix_inodes(struct dentry *root, + struct hlist_head *inode_list); /* header.c */ extern int read_header(FILE *fp, struct wim_header *hdr, int split_ok); -- 2.43.0