diff options
-rw-r--r-- | ubifs-utils/fsck.ubifs/extract_files.c | 2 | ||||
-rw-r--r-- | ubifs-utils/fsck.ubifs/fsck.ubifs.c | 25 | ||||
-rw-r--r-- | ubifs-utils/fsck.ubifs/fsck.ubifs.h | 13 | ||||
-rw-r--r-- | ubifs-utils/fsck.ubifs/load_fs.c | 27 | ||||
-rw-r--r-- | ubifs-utils/fsck.ubifs/rebuild_fs.c | 42 | ||||
-rw-r--r-- | ubifs-utils/libubifs/tnc.c | 64 | ||||
-rw-r--r-- | ubifs-utils/libubifs/ubifs.h | 2 |
7 files changed, 122 insertions, 53 deletions
diff --git a/ubifs-utils/fsck.ubifs/extract_files.c b/ubifs-utils/fsck.ubifs/extract_files.c index b8777f6..c3ab2b7 100644 --- a/ubifs-utils/fsck.ubifs/extract_files.c +++ b/ubifs-utils/fsck.ubifs/extract_files.c @@ -1234,7 +1234,7 @@ int check_and_correct_files(struct ubifs_info *c) int err; struct rb_node *node; struct scanned_file *file; - struct rb_root *tree = &FSCK(c)->rebuild->scanned_files; + struct rb_root *tree = &FSCK(c)->scanned_files; for (node = rb_first(tree); node; node = rb_next(node)) { file = rb_entry(node, struct scanned_file, rb); diff --git a/ubifs-utils/fsck.ubifs/fsck.ubifs.c b/ubifs-utils/fsck.ubifs/fsck.ubifs.c index 616ed81..59080d8 100644 --- a/ubifs-utils/fsck.ubifs/fsck.ubifs.c +++ b/ubifs-utils/fsck.ubifs/fsck.ubifs.c @@ -404,6 +404,31 @@ static void destroy_fsck_info(struct ubifs_info *c) c->dev_name = NULL; } +void handle_error(const struct ubifs_info *c, int reason_set) +{ + bool handled = false; + unsigned int reason = get_failure_reason_callback(c); + + clear_failure_reason_callback(c); + if ((reason_set & HAS_DATA_CORRUPTED) && (reason & FR_DATA_CORRUPTED)) { + handled = true; + reason &= ~FR_DATA_CORRUPTED; + if (fix_problem(c, LOG_CORRUPTED, NULL)) + FSCK(c)->try_rebuild = true; + } + if ((reason_set & HAS_TNC_CORRUPTED) && (reason & FR_TNC_CORRUPTED)) { + ubifs_assert(c, !handled); + handled = true; + reason &= ~FR_TNC_CORRUPTED; + if (fix_problem(c, TNC_CORRUPTED, NULL)) + FSCK(c)->try_rebuild = true; + } + + ubifs_assert(c, reason == 0); + if (!handled) + exit_code |= FSCK_ERROR; +} + /* * do_fsck - Check & repair the filesystem. */ diff --git a/ubifs-utils/fsck.ubifs/fsck.ubifs.h b/ubifs-utils/fsck.ubifs/fsck.ubifs.h index a1c64e3..db43ccc 100644 --- a/ubifs-utils/fsck.ubifs/fsck.ubifs.h +++ b/ubifs-utils/fsck.ubifs/fsck.ubifs.h @@ -40,6 +40,8 @@ enum { NORMAL_MODE = 0, SAFE_MODE, DANGER_MODE0, enum { SB_CORRUPTED = 0, MST_CORRUPTED, LOG_CORRUPTED, BUD_CORRUPTED, TNC_CORRUPTED, TNC_DATA_CORRUPTED, ORPHAN_CORRUPTED }; +enum { HAS_DATA_CORRUPTED = 1, HAS_TNC_CORRUPTED = 2 }; + struct scanned_file; /** @@ -181,18 +183,14 @@ struct scanned_file { /** * ubifs_rebuild_info - UBIFS rebuilding information. - * @used_lebs: a bitmap used for recording used lebs * @lpts: lprops table - * @scanned_files: tree of all scanned files * @write_buf: write buffer for LEB @head_lnum * @head_lnum: current writing LEB number * @head_offs: current writing position in LEB @head_lnum * @need_update_lpt: whether to update lpt while writing index nodes */ struct ubifs_rebuild_info { - unsigned long *used_lebs; struct ubifs_lprops *lpts; - struct rb_root scanned_files; void *write_buf; int head_lnum; int head_offs; @@ -205,6 +203,8 @@ struct ubifs_rebuild_info { * @failure_reason: reasons for failed operations * @lpt_status: the status of lpt, could be: %0(OK), %FR_LPT_CORRUPTED or * %FR_LPT_INCORRECT + * @scanned_files: tree of all scanned files + * @used_lebs: a bitmap used for recording used lebs * @try_rebuild: %true means that try to rebuild fs when fsck failed * @rebuild: rebuilding-related information */ @@ -212,6 +212,8 @@ struct ubifs_fsck_info { int mode; unsigned int failure_reason; unsigned int lpt_status; + struct rb_root scanned_files; + unsigned long *used_lebs; bool try_rebuild; struct ubifs_rebuild_info *rebuild; }; @@ -259,6 +261,9 @@ static inline const char *mode_name(const struct ubifs_info *c) /* Exit code for fsck program. */ extern int exit_code; +/* fsck.ubifs.c */ +void handle_error(const struct ubifs_info *c, int reason_set); + /* problem.c */ bool fix_problem(const struct ubifs_info *c, int problem_type, const void *priv); diff --git a/ubifs-utils/fsck.ubifs/load_fs.c b/ubifs-utils/fsck.ubifs/load_fs.c index 5854054..04208a1 100644 --- a/ubifs-utils/fsck.ubifs/load_fs.c +++ b/ubifs-utils/fsck.ubifs/load_fs.c @@ -17,33 +17,6 @@ #include "misc.h" #include "fsck.ubifs.h" -enum { HAS_DATA_CORRUPTED = 1, HAS_TNC_CORRUPTED = 2 }; - -static void handle_error(const struct ubifs_info *c, int reason_set) -{ - bool handled = false; - unsigned int reason = get_failure_reason_callback(c); - - clear_failure_reason_callback(c); - if ((reason_set & HAS_DATA_CORRUPTED) && (reason & FR_DATA_CORRUPTED)) { - handled = true; - reason &= ~FR_DATA_CORRUPTED; - if (fix_problem(c, LOG_CORRUPTED, NULL)) - FSCK(c)->try_rebuild = true; - } - if ((reason_set & HAS_TNC_CORRUPTED) && (reason & FR_TNC_CORRUPTED)) { - ubifs_assert(c, !handled); - handled = true; - reason &= ~FR_TNC_CORRUPTED; - if (fix_problem(c, TNC_CORRUPTED, NULL)) - FSCK(c)->try_rebuild = true; - } - - ubifs_assert(c, reason == 0); - if (!handled) - exit_code |= FSCK_ERROR; -} - int ubifs_load_filesystem(struct ubifs_info *c) { int err; diff --git a/ubifs-utils/fsck.ubifs/rebuild_fs.c b/ubifs-utils/fsck.ubifs/rebuild_fs.c index 382687b..f190517 100644 --- a/ubifs-utils/fsck.ubifs/rebuild_fs.c +++ b/ubifs-utils/fsck.ubifs/rebuild_fs.c @@ -73,10 +73,10 @@ static int init_rebuild_info(struct ubifs_info *c) log_err(c, errno, "can not allocate rebuild info"); 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) { + FSCK(c)->scanned_files = RB_ROOT; + FSCK(c)->used_lebs = kcalloc(BITS_TO_LONGS(c->main_lebs), + sizeof(unsigned long), GFP_KERNEL); + if (!FSCK(c)->used_lebs) { err = -ENOMEM; log_err(c, errno, "can not allocate bitmap of used lebs"); goto free_rebuild; @@ -100,7 +100,7 @@ static int init_rebuild_info(struct ubifs_info *c) free_lpts: kfree(FSCK(c)->rebuild->lpts); free_used_lebs: - kfree(FSCK(c)->rebuild->used_lebs); + kfree(FSCK(c)->used_lebs); free_rebuild: kfree(FSCK(c)->rebuild); free_sbuf: @@ -112,7 +112,7 @@ static void destroy_rebuild_info(struct ubifs_info *c) { vfree(FSCK(c)->rebuild->write_buf); kfree(FSCK(c)->rebuild->lpts); - kfree(FSCK(c)->rebuild->used_lebs); + kfree(FSCK(c)->used_lebs); kfree(FSCK(c)->rebuild); vfree(c->sbuf); } @@ -313,7 +313,7 @@ static int process_scanned_node(struct ubifs_info *c, int lnum, return 1; } - tree = &FSCK(c)->rebuild->scanned_files; + tree = &FSCK(c)->scanned_files; return insert_or_update_file(c, tree, sn, key_type(c, key), inum); } @@ -331,7 +331,7 @@ static void destroy_scanned_info(struct ubifs_info *c, struct scanned_info *si) struct scanned_dent_node *dent_node; struct rb_node *this; - destroy_file_tree(c, &FSCK(c)->rebuild->scanned_files); + destroy_file_tree(c, &FSCK(c)->scanned_files); this = rb_first(&si->valid_inos); while (this) { @@ -377,7 +377,7 @@ static void destroy_scanned_info(struct ubifs_info *c, struct scanned_info *si) * * This function scans nodes from flash, all ino/dent nodes are split * into valid tree and deleted tree, all trun/data nodes are collected - * into file, the file is inserted into @FSCK(c)->rebuild->scanned_files. + * into file, the file is inserted into @FSCK(c)->scanned_files. */ static int scan_nodes(struct ubifs_info *c, struct scanned_info *si) { @@ -495,7 +495,7 @@ static void update_lpt(struct ubifs_info *c, struct scanned_node *sn, int index = sn->lnum - c->main_first; int pos = sn->offs + ALIGN(sn->len, 8); - set_bit(index, FSCK(c)->rebuild->used_lebs); + set_bit(index, FSCK(c)->used_lebs); FSCK(c)->rebuild->lpts[index].end = max_t(int, FSCK(c)->rebuild->lpts[index].end, pos); @@ -572,7 +572,7 @@ static int add_valid_nodes_into_file(struct ubifs_info *c, struct scanned_ino_node *ino_node; struct scanned_dent_node *dent_node; struct rb_node *this; - struct rb_root *tree = &FSCK(c)->rebuild->scanned_files; + struct rb_root *tree = &FSCK(c)->scanned_files; this = rb_first(&si->valid_inos); while (this) { @@ -621,7 +621,7 @@ static void filter_invalid_files(struct ubifs_info *c) { struct rb_node *node; struct scanned_file *file; - struct rb_root *tree = &FSCK(c)->rebuild->scanned_files; + struct rb_root *tree = &FSCK(c)->scanned_files; LIST_HEAD(tmp_list); /* Add all xattr files into a list. */ @@ -678,7 +678,7 @@ static void extract_dentry_tree(struct ubifs_info *c) { struct rb_node *node; struct scanned_file *file; - struct rb_root *tree = &FSCK(c)->rebuild->scanned_files; + struct rb_root *tree = &FSCK(c)->scanned_files; LIST_HEAD(unreachable); for (node = rb_first(tree); node; node = rb_next(node)) { @@ -731,7 +731,7 @@ static void init_root_ino(struct ubifs_info *c, struct ubifs_ino_node *ino) } /** - * get_free_leb - get a free LEB according to @FSCK(c)->rebuild->used_lebs. + * get_free_leb - get a free LEB according to @FSCK(c)->used_lebs. * @c: UBIFS file-system description object * * This function tries to find a free LEB, lnum is returned if found, otherwise @@ -741,12 +741,12 @@ static int get_free_leb(struct ubifs_info *c) { int lnum; - lnum = find_next_zero_bit(FSCK(c)->rebuild->used_lebs, c->main_lebs, 0); + lnum = find_next_zero_bit(FSCK(c)->used_lebs, c->main_lebs, 0); if (lnum >= c->main_lebs) { ubifs_err(c, "No space left."); return -ENOSPC; } - set_bit(lnum, FSCK(c)->rebuild->used_lebs); + set_bit(lnum, FSCK(c)->used_lebs); lnum += c->main_first; return lnum; @@ -897,8 +897,8 @@ static int create_root(struct ubifs_info *c) file->calc_xnms = file->ino.xnms = le32_to_cpu(ino->xattr_names); file->calc_size = file->ino.size = le64_to_cpu(ino->size); - rb_link_node(&file->rb, NULL, &FSCK(c)->rebuild->scanned_files.rb_node); - rb_insert_color(&file->rb, &FSCK(c)->rebuild->scanned_files); + rb_link_node(&file->rb, NULL, &FSCK(c)->scanned_files.rb_node); + rb_insert_color(&file->rb, &FSCK(c)->scanned_files); out: kfree(ino); @@ -1188,7 +1188,7 @@ static int traverse_files_and_nodes(struct ubifs_info *c) int i, err = 0, idx_cnt = 0; struct rb_node *node; struct scanned_file *file; - struct rb_root *tree = &FSCK(c)->rebuild->scanned_files; + struct rb_root *tree = &FSCK(c)->scanned_files; struct idx_entry *ie, *tmp_ie; LIST_HEAD(idx_list); @@ -1214,7 +1214,7 @@ static int traverse_files_and_nodes(struct ubifs_info *c) for (i = 0; i < c->main_lebs; ++i) { int lnum, len, end; - if (!test_bit(i, FSCK(c)->rebuild->used_lebs)) + if (!test_bit(i, FSCK(c)->used_lebs)) continue; lnum = i + c->main_first; @@ -1268,7 +1268,7 @@ static int build_lpt(struct ubifs_info *c) /* Update LPT. */ for (i = 0; i < c->main_lebs; i++) { - if (!test_bit(i, FSCK(c)->rebuild->used_lebs) || + if (!test_bit(i, FSCK(c)->used_lebs) || c->gc_lnum == i + c->main_first) { free = c->leb_size; dirty = 0; diff --git a/ubifs-utils/libubifs/tnc.c b/ubifs-utils/libubifs/tnc.c index cd1013d..9277062 100644 --- a/ubifs-utils/libubifs/tnc.c +++ b/ubifs-utils/libubifs/tnc.c @@ -2457,6 +2457,70 @@ int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum) } /** + * ubifs_tnc_remove_node - remove an index entry of a node by given position. + * @c: UBIFS file-system description object + * @key: key of node + * @lnum: LEB number of node + * @offs: node offset + * + * Returns %0 on success or negative error code on failure. + */ +int ubifs_tnc_remove_node(struct ubifs_info *c, const union ubifs_key *key, + int lnum, int offs) +{ + int found, n, err = 0; + struct ubifs_znode *znode; + + mutex_lock(&c->tnc_mutex); + dbg_tnck(key, "pos %d:%d, key ", lnum, offs); + found = lookup_level0_dirty(c, key, &znode, &n); + if (found < 0) { + err = found; + goto out_unlock; + } + if (found == 1) { + struct ubifs_zbranch *zbr = &znode->zbranch[n]; + + if (zbr->lnum == lnum && zbr->offs == offs) { + err = tnc_delete(c, znode, n); + } else if (is_hash_key(c, key)) { + found = resolve_collision_directly(c, key, &znode, &n, + lnum, offs); + if (found < 0) { + err = found; + goto out_unlock; + } + + if (found) { + /* Ensure the znode is dirtied */ + if (znode->cnext || !ubifs_zn_dirty(znode)) { + znode = dirty_cow_bottom_up(c, znode); + if (IS_ERR(znode)) { + err = PTR_ERR(znode); + goto out_unlock; + } + } + err = tnc_delete(c, znode, n); + } else { + goto not_found; + } + } else { + goto not_found; + } + } else { +not_found: + /* Impossible, the node has been found before being deleted. */ + ubifs_assert(c, 0); + } + if (!err) + err = dbg_check_tnc(c, 0); + +out_unlock: + mutex_unlock(&c->tnc_mutex); + return err; +} + +/** * ubifs_tnc_next_ent - walk directory or extended attribute entries. * @c: UBIFS file-system description object * @key: key of last entry diff --git a/ubifs-utils/libubifs/ubifs.h b/ubifs-utils/libubifs/ubifs.h index 8a506a8..03150cd 100644 --- a/ubifs-utils/libubifs/ubifs.h +++ b/ubifs-utils/libubifs/ubifs.h @@ -1661,6 +1661,8 @@ int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key, int ubifs_tnc_remove_range(struct ubifs_info *c, union ubifs_key *from_key, union ubifs_key *to_key); int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum); +int ubifs_tnc_remove_node(struct ubifs_info *c, const union ubifs_key *key, + int lnum, int offs); struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c, union ubifs_key *key, const struct fscrypt_name *nm); |