static void recovery_xdata_block(struct hmfs_sb_info *sbi, seg_t src_segno, int src_off, struct hmfs_summary *src_sum) { struct gc_move_arg arg; struct hmfs_node *last = NULL, *this = NULL; struct hmfs_cm_info *cm_i = CM_I(sbi); block_t addr_in_par; bool modify_vb = false; int x_tag; prepare_move_argument(&arg, sbi, src_segno, src_off, src_sum, TYPE_DATA); while (1) { this = __get_node(sbi, arg.cp_i, arg.nid); if (IS_ERR(this)) break; if (this == last) goto next; x_tag = le64_to_cpu(XATTR_HDR(arg.src)->h_magic); addr_in_par = XBLOCK_ADDR(this, x_tag); if (addr_in_par != arg.src_addr && is_valid_address(sbi, addr_in_par)) { break; } if (addr_in_par != arg.src_addr) { hmfs_memcpy_atomic(JUMP(this, x_tag), &arg.src_addr, 8); if (!modify_vb) { arg.dest_sum = get_summary_by_addr(sbi, addr_in_par); clear_summary_valid_bit(arg.dest_sum); modify_vb = true; } } last = this; next: if (arg.cp_i == cm_i->last_cp_i) break; arg.cp_i = get_next_checkpoint_info(sbi, arg.cp_i); } }
static void recovery_gc_segment(struct hmfs_sb_info *sbi, seg_t segno) { int off = 0; struct hmfs_cm_info *cm_i = CM_I(sbi); bool is_current; struct hmfs_summary *sum; block_t seg_addr; seg_addr = __cal_page_addr(sbi, segno, 0); sum = get_summary_by_addr(sbi, seg_addr); for (off = 0; off < HMFS_PAGE_PER_SEG; ++off, sum++) { is_current = get_summary_start_version(sum) == cm_i->new_version; if ((!get_summary_valid_bit(sum) && !is_current) || is_current) continue; switch (get_summary_type(sum)) { case SUM_TYPE_DATA: recovery_data_block(sbi, segno, off, sum); break; case SUM_TYPE_XDATA: recovery_xdata_block(sbi, segno, off, sum); break; case SUM_TYPE_INODE: case SUM_TYPE_DN: case SUM_TYPE_IDN: recovery_node_block(sbi, segno, off, sum); break; case SUM_TYPE_NATN: case SUM_TYPE_NATD: recovery_nat_block(sbi, segno, off, sum); break; case SUM_TYPE_ORPHAN: recovery_orphan_block(sbi, segno, off, sum); break; case SUM_TYPE_CP: recovery_checkpoint_block(sbi, segno, off, sum); break; default: hmfs_bug_on(sbi, 1); } } }
static void setup_summary_of_delete_block(struct hmfs_sb_info *sbi, block_t blk_addr) { struct hmfs_summary *sum; struct hmfs_cm_info *cm_i = CM_I(sbi); int count; sum = get_summary_by_addr(sbi, blk_addr); count = get_summary_count(sum) - 1; set_summary_count(sum, count); #ifdef CONFIG_DEBUG BUG_ON(count < 0); #endif if (!count) { set_summary_dead_version(sum, cm_i->new_version); invalidate_block_after_dc(sbi, blk_addr); } }
static void recovery_node_block(struct hmfs_sb_info *sbi, seg_t src_segno, unsigned int src_off, struct hmfs_summary *src_sum) { struct hmfs_nat_block *last = NULL, *this = NULL; struct gc_move_arg args; block_t addr_in_par; bool modify_vb = false; prepare_move_argument(&args, sbi, src_segno, src_off, src_sum, TYPE_NODE); while (1) { this = get_nat_entry_block(sbi, args.cp_i->version, args.nid); if (IS_ERR(this)) break; if (this == last) goto next; addr_in_par = le64_to_cpu(this->entries[args.ofs_in_node].block_addr); /* Src node has been COW or removed */ if (addr_in_par != args.src_addr && is_valid_address(sbi, addr_in_par)) { break; } if (addr_in_par != args.src_addr) { hmfs_memcpy_atomic(&this->entries[args.ofs_in_node].block_addr, &args.src_addr, 8); if (!modify_vb) { args.dest_sum = get_summary_by_addr(sbi, addr_in_par); clear_summary_valid_bit(args.dest_sum); modify_vb = true; } } last = this; next: if (args.cp_i == CM_I(sbi)->last_cp_i) break; args.cp_i = get_next_checkpoint_info(sbi, args.cp_i); } }
static void recovery_nat_block(struct hmfs_sb_info *sbi, seg_t src_segno, int src_off, struct hmfs_summary *src_sum) { void *last = NULL, *this = NULL; struct hmfs_checkpoint *hmfs_cp = NULL; struct hmfs_nat_node *nat_node = NULL; struct gc_move_arg args; bool modify_vb = false; nid_t par_nid; block_t addr_in_par; prepare_move_argument(&args, sbi, src_segno, src_off, src_sum, TYPE_NODE); while (1) { if (IS_NAT_ROOT(args.nid)) this = args.cp_i->cp; else { par_nid = MAKE_NAT_NODE_NID(GET_NAT_NODE_HEIGHT(args.nid) - 1, GET_NAT_NODE_OFS(args.nid)); this = get_nat_node(sbi, args.cp_i->version, par_nid); } hmfs_bug_on(sbi, !this); if (this == last) goto next; if (IS_NAT_ROOT(args.nid)) { hmfs_cp = HMFS_CHECKPOINT(this); addr_in_par = le64_to_cpu(hmfs_cp->nat_addr); } else { nat_node = HMFS_NAT_NODE(this); addr_in_par = le64_to_cpu(nat_node->addr[args.ofs_in_node]); } if (addr_in_par != args.src_addr && is_valid_address(sbi, addr_in_par)) { break; } if (addr_in_par != args.src_addr) { if (IS_NAT_ROOT(args.nid)) { hmfs_memcpy_atomic(&hmfs_cp->nat_addr, &args.src_addr, 8); } else { hmfs_memcpy_atomic(&nat_node->addr[args.ofs_in_node], &args.src_addr, 8); } if (!modify_vb) { args.dest_sum = get_summary_by_addr(sbi, addr_in_par); clear_summary_valid_bit(args.dest_sum); modify_vb = true; } } last = this; next: if (args.cp_i == CM_I(sbi)->last_cp_i) break; args.cp_i = get_next_checkpoint_info(sbi, args.cp_i); } }
static void recovery_data_block(struct hmfs_sb_info *sbi, seg_t src_segno, int src_off, struct hmfs_summary *src_sum) { struct gc_move_arg args; struct hmfs_node *last = NULL, *this = NULL; struct hmfs_summary *par_sum; struct hmfs_cm_info *cm_i = CM_I(sbi); bool modify_vb = false; block_t addr_in_par; int par_type; prepare_move_argument(&args, sbi, src_segno, src_off, src_sum, TYPE_DATA); while (1) { this = __get_node(sbi, args.cp_i, args.nid); par_sum = get_summary_by_addr(sbi, L_ADDR(sbi, this)); if (IS_ERR(this)) { /* the node(args.nid) has been deleted */ break; } if (this == last) goto next; par_type = get_summary_type(par_sum); if (par_type == SUM_TYPE_INODE) { addr_in_par = le64_to_cpu(this->i.i_addr[args.ofs_in_node]); } else { addr_in_par = le64_to_cpu(this->dn.addr[args.ofs_in_node]); } /* * In recovery, the address stored in parent node would be * arg.src_addr or an invalid address. Because GC might terminate * in the loop change this address. * Condition addr_in_par != args.src_addr is not sufficient * to terminate recovery. For example, we delete a node in a * checkpoint and reuse it later. And address in reused node * is not equal to args.src_addr but we could not modify it. * Luckly, the child block in that node is valid and we could * judge this case by the value of address. */ if (addr_in_par != args.src_addr && is_valid_address(sbi, addr_in_par)) break; if (addr_in_par != args.src_addr) { /* Recover address in parent node */ if (par_type == SUM_TYPE_INODE) { hmfs_memcpy_atomic(&this->i.i_addr[args.ofs_in_node], &args.src_addr, 8); } else { hmfs_memcpy_atomic(&this->dn.addr[args.ofs_in_node], &args.src_addr, 8); } if (!modify_vb) { args.dest_sum = get_summary_by_addr(sbi, addr_in_par); clear_summary_valid_bit(args.dest_sum); modify_vb = true; } } last = this; next: if (args.cp_i == cm_i->last_cp_i) break; args.cp_i = get_next_checkpoint_info(sbi, args.cp_i); } }