static int walk_chain_func(ocfs2_filesys *fs, uint64_t gd_blkno, int chain_num, void *priv_data) { struct walk_it *wi = priv_data; struct ocfs2_group_desc *gd; errcode_t ret; if (wi->last_chain != chain_num) { fprintf(stdout, "CHAIN[%02d]: %d/%d\n", chain_num, wi->di->id2.i_chain.cl_recs[chain_num].c_free, wi->di->id2.i_chain.cl_recs[chain_num].c_total); wi->last_chain = chain_num; wi->count_free = wi->count_total = 0; } ret = ocfs2_read_group_desc(fs, gd_blkno, wi->gd_buf); if (ret) return OCFS2_CHAIN_ERROR; gd = (struct ocfs2_group_desc *)wi->gd_buf; wi->count_free += gd->bg_free_bits_count; wi->count_total += gd->bg_bits; fprintf(stdout, " %16"PRIu64": %05d/%05d = %05d/%05d\n", gd->bg_blkno, gd->bg_free_bits_count, gd->bg_bits, wi->count_free, wi->count_total); return 0; }
static int chain_iterate_gd(struct ocfs2_chain_rec *c_rec, int chain_num, struct chain_context *ctxt) { int iret = 0; uint64_t blkno; struct ocfs2_group_desc *gd; blkno = c_rec->c_blkno; while (blkno) { iret = (*ctxt->func)(ctxt->fs, blkno, chain_num, ctxt->priv_data); if (iret & OCFS2_CHAIN_ABORT) break; ctxt->errcode = ocfs2_read_group_desc(ctxt->fs, blkno, ctxt->gd_buf); if (ctxt->errcode) { iret |= OCFS2_CHAIN_ERROR; break; } gd = (struct ocfs2_group_desc *)ctxt->gd_buf; if ((gd->bg_blkno != blkno) || (gd->bg_chain != chain_num)) { ctxt->errcode = OCFS2_ET_CORRUPT_GROUP_DESC; iret |= OCFS2_CHAIN_ERROR; break; } blkno = gd->bg_next_group; } return iret; }
/* * This function will iterate the chain_rec and do the following modifications: * 1. record all the groups in the chains. * 2. for every group, do: * 1) modify Sub Alloc Slot in extent block/inodes accordingly. * 2) change the GROUP_PARENT according to its future owner. * 3) link the group to the new slot files. */ static errcode_t move_chain_rec(ocfs2_filesys *fs, struct relink_ctxt *ctxt) { errcode_t ret = 0; int i, start, end = 1; uint64_t blkno, gd_blkno = ctxt->cr->c_blkno; struct ocfs2_group_desc *gd = NULL; struct moved_group *group = NULL, *group_head = NULL; if (gd_blkno == 0) goto bail; /* Record the group in the relink_ctxt. * * We record the group in a reverse order, so the first group * will be at the end of the group list. This is useful for * fsck.ocfs2 when any error happens during the move of groups * and we can safely move the group also. */ while (gd_blkno) { ret = ocfs2_malloc0(sizeof(struct moved_group), &group); if (ret) goto bail; memset(group, 0, sizeof(struct moved_group)); /* We insert the group first in case of any further error * will not cause memory leak. */ group->next = group_head; group_head = group; ret = ocfs2_malloc_block(fs->fs_io, &group->gd_buf); if (ret) goto bail; ret = ocfs2_read_group_desc(fs, gd_blkno, group->gd_buf); if (ret) goto bail; group->blkno = gd_blkno; gd = (struct ocfs2_group_desc *)group->gd_buf; gd_blkno = gd->bg_next_group; } group = group_head; while (group) { gd = (struct ocfs2_group_desc *)group->gd_buf; end = 1; /* Modify the "Sub Alloc Slot" in the extent block/inodes. */ while (end < gd->bg_bits) { start = ocfs2_find_next_bit_set(gd->bg_bitmap, gd->bg_bits, end); if (start >= gd->bg_bits) break; end = ocfs2_find_next_bit_clear(gd->bg_bitmap, gd->bg_bits, start); for (i = start; i < end; i++) { blkno = group->blkno + i; ret = change_sub_alloc_slot(fs, blkno, ctxt); if (ret) goto bail; } } /* move the group to the new slots. */ ret = move_group(fs, ctxt, group); if (ret) goto bail; group = group->next; } bail: group = group_head; while (group) { group_head = group->next; if (group->gd_buf) ocfs2_free(&group->gd_buf); ocfs2_free(&group); group = group_head; } return ret; }
static void mess_up_sys_file(ocfs2_filesys *fs, uint64_t blkno, enum fsck_type type) { errcode_t ret; char *buf = NULL, *bufgroup = NULL; struct ocfs2_dinode *di; struct ocfs2_chain_list *cl; struct ocfs2_chain_rec *cr; uint64_t oldblkno; struct ocfs2_group_desc *bg = NULL; ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) FSWRK_COM_FATAL(progname, ret); ret = ocfs2_read_inode(fs, blkno, buf); if (ret) FSWRK_COM_FATAL(progname, ret); di = (struct ocfs2_dinode *)buf; if (!(di->i_flags & OCFS2_BITMAP_FL)) FSWRK_COM_FATAL(progname, ret); if (!(di->i_flags & OCFS2_CHAIN_FL)) FSWRK_COM_FATAL(progname, ret); cl = &(di->id2.i_chain); /* for CHAIN_EMPTY, CHAIN_HEAD_LINK_RANGE, CHAIN_LINK_RANGE, * CHAIN_BITS, CHAIN_LINK_GEN, CHAIN_LINK_MAGIC, * we need to corrupt some chain rec, so check it first. */ if (type == CHAIN_EMPTY || type == CHAIN_HEAD_LINK_RANGE || type == CHAIN_LINK_RANGE || type == CHAIN_BITS || type == CHAIN_LINK_GEN || type == CHAIN_LINK_MAGIC) if (!cl->cl_next_free_rec) { FSWRK_WARN("No chain record found at block#%"PRIu64 ",so can't corrupt it for type[%d].\n", blkno, type); goto bail; } switch (type) { case CHAIN_COUNT: fprintf(stdout, "Corrupt CHAIN_COUNT: " "Modified cl_count " "in block#%"PRIu64" from %u to %u\n", blkno, cl->cl_count, (cl->cl_count + 100)); cl->cl_count += 100; break; case CHAIN_NEXT_FREE: fprintf(stdout, "Corrupt CHAIN_NEXT_FREE:" " Modified cl_next_free_rec " "in block#%"PRIu64" from %u to %u\n", blkno, cl->cl_next_free_rec, (cl->cl_count + 10)); cl->cl_next_free_rec = cl->cl_count + 10; break; case CHAIN_EMPTY: cr = cl->cl_recs; fprintf(stdout, "Corrupt CHAIN_EMPTY:" " Modified e_blkno " "in block#%"PRIu64" from %"PRIu64" to 0\n", blkno, (uint64_t)cr->c_blkno); cr->c_blkno = 0; break; case CHAIN_I_CLUSTERS: fprintf(stdout, "Corrupt CHAIN_I_CLUSTERS:" "change i_clusters in block#%"PRIu64" from %u to %u\n", blkno, di->i_clusters, (di->i_clusters + 10)); di->i_clusters += 10; break; case CHAIN_I_SIZE: fprintf(stdout, "Corrupt CHAIN_I_SIZE:" "change i_size " "in block#%"PRIu64" from %"PRIu64" to %"PRIu64"\n", blkno, (uint64_t)di->i_size, ((uint64_t)di->i_size + 10)); di->i_size += 10; break; case CHAIN_GROUP_BITS: fprintf(stdout, "Corrupt CHAIN_GROUP_BITS:" "change i_used of bitmap " "in block#%"PRIu64" from %u to %u\n", blkno, di->id1.bitmap1.i_used, (di->id1.bitmap1.i_used + 10)); di->id1.bitmap1.i_used += 10; break; case CHAIN_HEAD_LINK_RANGE: cr = cl->cl_recs; oldblkno = cr->c_blkno; cr->c_blkno = ocfs2_clusters_to_blocks(fs, fs->fs_clusters) + 10; fprintf(stdout, "Corrupt CHAIN_HEAD_LINK_RANGE:" "change " "in block#%"PRIu64" from %"PRIu64" to %"PRIu64"\n", blkno, oldblkno, (uint64_t)cr->c_blkno); break; case CHAIN_LINK_GEN: case CHAIN_LINK_MAGIC: case CHAIN_LINK_RANGE: ret = ocfs2_malloc_block(fs->fs_io, &bufgroup); if (ret) FSWRK_COM_FATAL(progname, ret); bg = (struct ocfs2_group_desc *)bufgroup; cr = cl->cl_recs; ret = ocfs2_read_group_desc(fs, cr->c_blkno, (char *)bg); if (ret) FSWRK_COM_FATAL(progname, ret); if (type == CHAIN_LINK_GEN) { fprintf(stdout, "Corrupt CHAIN_LINK_GEN: " "change generation num from %u to 0x1234\n", bg->bg_generation); bg->bg_generation = 0x1234; } else if (type == CHAIN_LINK_MAGIC) { fprintf(stdout, "Corrupt CHAIN_LINK_MAGIC: " "change signature to '1234'\n"); sprintf((char *)bg->bg_signature,"1234"); } else { oldblkno = bg->bg_next_group; bg->bg_next_group = ocfs2_clusters_to_blocks(fs, fs->fs_clusters) + 10; fprintf(stdout, "Corrupt CHAIN_LINK_RANGE: " "change next group from %"PRIu64" to %"PRIu64 " \n", oldblkno, (uint64_t)bg->bg_next_group); } ret = ocfs2_write_group_desc(fs, cr->c_blkno, (char *)bg); if (ret) FSWRK_COM_FATAL(progname, ret); break; case CHAIN_BITS: cr = cl->cl_recs; fprintf(stdout, "Corrupt CHAIN_BITS:" "change inode#%"PRIu64" c_total from %u to %u\n", blkno, cr->c_total, (cr->c_total + 10)); cr->c_total += 10; break; case CHAIN_CPG: fprintf(stdout, "Corrupt CHAIN_CPG: " "change cl_cpg of global_bitmap from %u to %u.\n", cl->cl_cpg, (cl->cl_cpg + 16)); cl->cl_cpg += 16; cl->cl_next_free_rec = 1; break; default: FSWRK_FATAL("Unknown fsck_type[%d]\n", type); } ret = ocfs2_write_inode(fs, blkno, buf); if (ret) FSWRK_COM_FATAL(progname, ret); bail: if (bufgroup) ocfs2_free(&bufgroup); if (buf) ocfs2_free(&buf); return ; }