diff options
Diffstat (limited to 'ubifs-utils/fsck.ubifs')
-rw-r--r-- | ubifs-utils/fsck.ubifs/fsck.ubifs.h | 2 | ||||
-rw-r--r-- | ubifs-utils/fsck.ubifs/rebuild_fs.c | 116 |
2 files changed, 115 insertions, 3 deletions
diff --git a/ubifs-utils/fsck.ubifs/fsck.ubifs.h b/ubifs-utils/fsck.ubifs/fsck.ubifs.h index bb5d1c4..a3b755b 100644 --- a/ubifs-utils/fsck.ubifs/fsck.ubifs.h +++ b/ubifs-utils/fsck.ubifs/fsck.ubifs.h @@ -180,9 +180,11 @@ struct scanned_file { /** * ubifs_rebuild_info - UBIFS rebuilding information. + * @used_lebs: a bitmap used for recording used lebs * @scanned_files: tree of all scanned files */ struct ubifs_rebuild_info { + unsigned long *used_lebs; struct rb_root scanned_files; }; diff --git a/ubifs-utils/fsck.ubifs/rebuild_fs.c b/ubifs-utils/fsck.ubifs/rebuild_fs.c index ecf6b0c..3be0844 100644 --- a/ubifs-utils/fsck.ubifs/rebuild_fs.c +++ b/ubifs-utils/fsck.ubifs/rebuild_fs.c @@ -48,19 +48,29 @@ static int init_rebuild_info(struct ubifs_info *c) if (!FSCK(c)->rebuild) { err = -ENOMEM; log_err(c, errno, "can not allocate rebuild info"); - goto out; + goto free_sbuf; } FSCK(c)->rebuild->scanned_files = RB_ROOT; + FSCK(c)->rebuild->used_lebs = kcalloc(BITS_TO_LONGS(c->main_lebs), + sizeof(unsigned long), GFP_KERNEL); + if (!FSCK(c)->rebuild->used_lebs) { + err = -ENOMEM; + log_err(c, errno, "can not allocate bitmap of used lebs"); + goto free_rebuild; + } return 0; -out: +free_rebuild: + kfree(FSCK(c)->rebuild); +free_sbuf: vfree(c->sbuf); return err; } static void destroy_rebuild_info(struct ubifs_info *c) { + kfree(FSCK(c)->rebuild->used_lebs); kfree(FSCK(c)->rebuild); vfree(c->sbuf); } @@ -451,6 +461,9 @@ static void remove_del_nodes(struct ubifs_info *c, struct scanned_info *si) valid_ino_node = lookup_valid_ino_node(c, si, del_ino_node); if (valid_ino_node) { + int lnum = del_ino_node->header.lnum; + + set_bit(lnum - c->main_first, FSCK(c)->rebuild->used_lebs); rb_erase(&valid_ino_node->rb, &si->valid_inos); kfree(valid_ino_node); } @@ -466,6 +479,9 @@ static void remove_del_nodes(struct ubifs_info *c, struct scanned_info *si) valid_dent_node = lookup_valid_dent_node(c, si, del_dent_node); if (valid_dent_node) { + int lnum = del_dent_node->header.lnum; + + set_bit(lnum - c->main_first, FSCK(c)->rebuild->used_lebs); rb_erase(&valid_dent_node->rb, &si->valid_dents); kfree(valid_dent_node); } @@ -627,6 +643,94 @@ static void extract_dentry_tree(struct ubifs_info *c) } } +static const char *get_file_name(struct ubifs_info *c, struct scanned_file *file) +{ + static char name[UBIFS_MAX_NLEN + 1]; + struct rb_node *node; + struct scanned_dent_node *dent_node; + + node = rb_first(&file->dent_nodes); + if (!node) { + ubifs_assert(c, file->inum == UBIFS_ROOT_INO); + return "/"; + } + + if (c->encrypted && !file->ino.is_xattr) + /* Encrypted file name. */ + return "<encrypted>"; + + /* Get name from any one dentry. */ + dent_node = rb_entry(node, struct scanned_dent_node, rb); + memcpy(name, dent_node->name, dent_node->nlen); + /* @dent->name could be non '\0' terminated. */ + name[dent_node->nlen] = '\0'; + return name; +} + +static void record_file_used_lebs(struct ubifs_info *c, + struct scanned_file *file) +{ + int lnum; + struct rb_node *node; + struct scanned_file *xattr_file; + struct scanned_dent_node *dent_node; + struct scanned_data_node *data_node; + + dbg_fsck("recovered file(inum:%lu name:%s type:%s), in %s", + file->inum, get_file_name(c, file), + file->ino.is_xattr ? "xattr" : + ubifs_get_type_name(ubifs_get_dent_type(file->ino.mode)), + c->dev_name); + + lnum = file->ino.header.lnum; + set_bit(lnum - c->main_first, FSCK(c)->rebuild->used_lebs); + + if (file->trun.header.exist) { + lnum = file->trun.header.lnum; + set_bit(lnum - c->main_first, FSCK(c)->rebuild->used_lebs); + } + + for (node = rb_first(&file->data_nodes); node; node = rb_next(node)) { + data_node = rb_entry(node, struct scanned_data_node, rb); + + lnum = data_node->header.lnum; + set_bit(lnum - c->main_first, FSCK(c)->rebuild->used_lebs); + } + + for (node = rb_first(&file->dent_nodes); node; node = rb_next(node)) { + dent_node = rb_entry(node, struct scanned_dent_node, rb); + + lnum = dent_node->header.lnum; + set_bit(lnum - c->main_first, FSCK(c)->rebuild->used_lebs); + } + + for (node = rb_first(&file->xattr_files); node; node = rb_next(node)) { + xattr_file = rb_entry(node, struct scanned_file, rb); + + record_file_used_lebs(c, xattr_file); + } +} + +/** + * record_used_lebs - record used LEBs. + * @c: UBIFS file-system description object + * + * This function records all used LEBs which may hold useful nodes, then left + * unused LEBs could be taken for storing new index tree. + */ +static void record_used_lebs(struct ubifs_info *c) +{ + struct rb_node *node; + struct scanned_file *file; + struct rb_root *tree = &FSCK(c)->rebuild->scanned_files; + + for (node = rb_first(tree); node; node = rb_next(node)) { + file = rb_entry(node, struct scanned_file, rb); + + record_file_used_lebs(c, file); + } +} + /** * ubifs_rebuild_filesystem - Rebuild filesystem. * @c: UBIFS file-system description object @@ -680,8 +784,14 @@ int ubifs_rebuild_filesystem(struct ubifs_info *c) /* Step 6: Check & correct files' information. */ log_out(c, "Check & correct file information"); err = check_and_correct_files(c); - if (err) + if (err) { exit_code |= FSCK_ERROR; + goto out; + } + + /* Step 7: Record used LEBs. */ + log_out(c, "Record used LEBs"); + record_used_lebs(c); out: destroy_scanned_info(c, &si); |