static errcode_t check_journals_func(o2fsck_state *ost, ocfs2_cached_inode *ci, struct journal_check_context *jc) { errcode_t err, ret; ocfs2_filesys *fs = ost->ost_fs; uint64_t contig; uint64_t blkno; char *buf = NULL; journal_superblock_t *jsb; struct journal_check_info *ji = &(jc->jc_info[jc->jc_this_slot]); ret = ocfs2_malloc_blocks(fs->fs_io, 1, &buf); if (ret) goto out; err = ocfs2_extent_map_get_blocks(ci, 0, 1, &blkno, &contig, NULL); if (err) { ji->i_error = err; goto out; } ji->i_clusters = ci->ci_inode->i_clusters; err = ocfs2_read_journal_superblock(fs, blkno, buf); if (err) { ji->i_error = err; goto out; } jsb = (journal_superblock_t *)buf; ji->i_features.opt_compat = jsb->s_feature_compat; ji->i_features.opt_ro_compat = jsb->s_feature_ro_compat; ji->i_features.opt_incompat = jsb->s_feature_incompat; if (!ji->i_clusters) { ji->i_error = OCFS2_ET_JOURNAL_TOO_SMALL; goto out; } jc->jc_max_clusters = ocfs2_max(jc->jc_max_clusters, ci->ci_inode->i_clusters); jc->jc_max_features.opt_compat |= jsb->s_feature_compat; jc->jc_max_features.opt_ro_compat |= jsb->s_feature_ro_compat; jc->jc_max_features.opt_incompat |= jsb->s_feature_incompat; ji->i_error = 0; out: if (buf) ocfs2_free(&buf); return ret; }
static errcode_t prep_journal_info(ocfs2_filesys *fs, int slot, struct journal_info *ji) { errcode_t err; err = ocfs2_malloc_blocks(fs->fs_io, 1, &ji->ji_jsb); if (err) com_err(whoami, err, "while allocating space for slot %d's " "journal superblock", slot); err = ocfs2_lookup_system_inode(fs, JOURNAL_SYSTEM_INODE, slot, &ji->ji_ino); if (err) { com_err(whoami, err, "while looking up the journal inode for " "slot %d", slot); goto out; } err = ocfs2_read_cached_inode(fs, ji->ji_ino, &ji->ji_cinode); if (err) { com_err(whoami, err, "while reading cached inode %"PRIu64" " "for slot %d's journal", ji->ji_ino, slot); goto out; } if (!(ji->ji_cinode->ci_inode->id1.journal1.ij_flags & OCFS2_JOURNAL_DIRTY_FL)) goto out; err = lookup_journal_block(fs, ji, 0, &ji->ji_jsb_block, 1); if (err) goto out; /* XXX be smarter about reading in the whole super block if it * spans multiple blocks */ err = ocfs2_read_journal_superblock(fs, ji->ji_jsb_block, (char *)ji->ji_jsb); if (err) { com_err(whoami, err, "while reading block %"PRIu64" as slot " "%d's journal super block", ji->ji_jsb_block, ji->ji_slot); goto out; } ji->ji_replay = 1; verbosef("slot: %d jsb start %u maxlen %u\n", slot, ji->ji_jsb->s_start, ji->ji_jsb->s_maxlen); out: return err; }
errcode_t ocfs2_set_backup_super_list(ocfs2_filesys *fs, uint64_t *blocks, size_t len) { size_t i; errcode_t ret = 0; char *buf = NULL; uint64_t *blkno = blocks; uint32_t cluster, bpc = fs->fs_clustersize / fs->fs_blocksize; if (!len || !blocks || !*blocks) goto bail; len = ocfs2_min(len,(size_t)OCFS2_MAX_BACKUP_SUPERBLOCKS); if (!OCFS2_HAS_COMPAT_FEATURE(OCFS2_RAW_SB(fs->fs_super), OCFS2_FEATURE_COMPAT_BACKUP_SB)) { /* check all the blkno to see whether it is used. */ for (i = 0; i < len; i++, blkno++) { ret = check_cluster(fs, ocfs2_blocks_to_clusters(fs, *blkno)); if (ret) goto bail; } } ret = ocfs2_malloc_blocks(fs->fs_io, bpc, &buf); if (ret) goto bail; memset(buf, 0, fs->fs_clustersize); /* zero all the clusters at first */ blkno = blocks; for (i = 0; i < len; i++, blkno++) { cluster = ocfs2_blocks_to_clusters(fs, *blkno); ret = io_write_block(fs->fs_io, cluster*bpc, bpc, buf); if (ret) goto bail; } ret = ocfs2_refresh_backup_super_list(fs, blocks, len); if (ret) goto bail; /* We just tested the clusters, so the allocation can't fail */ blkno = blocks; for (i = 0; i < len; i++, blkno++) ocfs2_new_specific_cluster(fs, ocfs2_blocks_to_clusters(fs, *blkno)); bail: if (buf) ocfs2_free(&buf); return ret; }
static errcode_t dump_xattr_buckets(FILE *out, ocfs2_filesys *fs, uint64_t blkno, uint32_t clusters, uint64_t *xattrs_bucket, int verbose) { int i; errcode_t ret = 0; char *bucket = NULL; struct ocfs2_xattr_header *xh; int blk_per_bucket = ocfs2_blocks_per_xattr_bucket(fs); uint32_t bpc = ocfs2_xattr_buckets_per_cluster(fs); uint32_t num_buckets = clusters * bpc; ret = ocfs2_malloc_blocks(fs->fs_io, blk_per_bucket, &bucket); if (ret) goto out; fprintf(out, "\tExtended Attributes extent record start at #%"PRIu64 " Has clusters: %u", blkno, clusters); for (i = 0; i < num_buckets; i++, blkno += blk_per_bucket) { ret = ocfs2_read_xattr_bucket(fs, blkno, bucket); if (ret) goto out; xh = (struct ocfs2_xattr_header *)bucket; /* * The real bucket num in this series of blocks is stored * in the 1st bucket. */ if (i == 0) { num_buckets = xh->xh_num_buckets; fprintf(out, " Has buckets: %d\n", num_buckets); } fprintf(out, "\t\tExtended Attributes in bucket #%d: %u\n", i, xh->xh_count); if (verbose) dump_xattr(out, xh); *xattrs_bucket += xh->xh_count; } out: if (bucket) ocfs2_free(&bucket); return ret; }
errcode_t io_init_cache(io_channel *channel, size_t nr_blocks) { int i; struct io_cache *ic; char *dbuf; struct io_cache_block *icb_list; errcode_t ret; ret = ocfs2_malloc0(sizeof(struct io_cache), &ic); if (ret) goto out; ic->ic_nr_blocks = nr_blocks; ic->ic_lookup = RB_ROOT; INIT_LIST_HEAD(&ic->ic_lru); ret = ocfs2_malloc_blocks(channel, nr_blocks, &ic->ic_data_buffer); if (ret) goto out; ic->ic_data_buffer_len = (unsigned long)nr_blocks * channel->io_blksize; ret = ocfs2_malloc0(sizeof(struct io_cache_block) * nr_blocks, &ic->ic_metadata_buffer); if (ret) goto out; ic->ic_metadata_buffer_len = (unsigned long)nr_blocks * sizeof(struct io_cache_block); icb_list = ic->ic_metadata_buffer; dbuf = ic->ic_data_buffer; for (i = 0; i < nr_blocks; i++) { icb_list[i].icb_blkno = UINT64_MAX; icb_list[i].icb_buf = dbuf; dbuf += channel->io_blksize; list_add_tail(&icb_list[i].icb_list, &ic->ic_lru); } ic->ic_use_count = 1; channel->io_cache = ic; out: if (ret) io_free_cache(ic); return ret; }
void o2fsck_dir_block_iterate(o2fsck_state *ost, dirblock_iterator func, void *priv_data) { o2fsck_dirblocks *db = &ost->ost_dirblocks; ocfs2_filesys *fs = ost->ost_fs; o2fsck_dirblock_entry *dbe; struct rb_node *node; unsigned ret; errcode_t err; char *pre_cache_buf = NULL; int pre_cache_blocks = ocfs2_blocks_in_bytes(fs, 1024 * 1024); int cached_blocks = 0; o2fsck_reset_blocks_cached(); if (o2fsck_worth_caching(1)) { err = ocfs2_malloc_blocks(fs->fs_io, pre_cache_blocks, &pre_cache_buf); if (err) verbosef("Unable to allocate dirblock pre-cache " "buffer, %s\n", "ignoring"); } for (node = rb_first(&db->db_root); node; node = rb_next(node)) { if (!cached_blocks && pre_cache_buf) cached_blocks = try_to_cache(fs, node, pre_cache_buf, pre_cache_blocks); dbe = rb_entry(node, o2fsck_dirblock_entry, e_node); ret = func(dbe, priv_data); if (ret & OCFS2_DIRENT_ABORT) break; if (cached_blocks) cached_blocks--; } if (pre_cache_buf) ocfs2_free(&pre_cache_buf); }
/* * Zero the area past i_size but still within an allocated * cluster. This avoids exposing nonzero data on subsequent file * extends. */ static errcode_t ocfs2_zero_tail_for_truncate(ocfs2_cached_inode *ci, uint64_t new_size) { errcode_t ret; char *buf = NULL; ocfs2_filesys *fs = ci->ci_fs; uint64_t start_blk, p_blkno, contig_blocks, start_off; int count, byte_counts, bpc = fs->fs_clustersize /fs->fs_blocksize; uint16_t ext_flags; if (new_size == 0) return 0; start_blk = new_size / fs->fs_blocksize; ret = ocfs2_extent_map_get_blocks(ci, start_blk, 1, &p_blkno, &contig_blocks, &ext_flags); if (ret) goto out; /* Tail is a hole. */ if (!p_blkno) goto out; if (ext_flags & OCFS2_EXT_REFCOUNTED) { uint32_t cpos = ocfs2_blocks_to_clusters(fs, start_blk); ret = ocfs2_refcount_cow(ci, cpos, 1, cpos + 1); if (ret) goto out; ret = ocfs2_extent_map_get_blocks(ci, start_blk, 1, &p_blkno, &contig_blocks, &ext_flags); if (ret) goto out; assert(!(ext_flags & OCFS2_EXT_REFCOUNTED) && p_blkno); } /* calculate the total blocks we need to empty. */ count = bpc - (p_blkno & (bpc - 1)); ret = ocfs2_malloc_blocks(fs->fs_io, count, &buf); if (ret) goto out; ret = ocfs2_read_blocks(fs, p_blkno, count, buf); if (ret) goto out; /* empty the content after the new_size and within the same cluster. */ start_off = new_size % fs->fs_blocksize; byte_counts = count * fs->fs_blocksize - start_off; memset(buf + start_off, 0, byte_counts); ret = io_write_block(fs->fs_io, p_blkno, count, buf); out: if (buf) ocfs2_free(&buf); return ret; }
errcode_t ocfs2_cache_chain_allocator_blocks(ocfs2_filesys *fs, struct ocfs2_dinode *di) { struct io_vec_unit *ivus = NULL; char *buf = NULL; errcode_t ret = 0; int i, j, count; struct ocfs2_chain_list *cl; struct ocfs2_chain_rec *cr; struct ocfs2_group_desc *gd; io_channel *channel = fs->fs_io; int blocksize = fs->fs_blocksize; int64_t group_size; if (!(di->i_flags & OCFS2_CHAIN_FL)) { ret = OCFS2_ET_INODE_NOT_VALID; goto out; } if (!channel) goto out; if (!di->i_clusters) goto out; group_size = (int64_t)di->i_clusters / di->id2.i_chain.cl_cpg; group_size *= blocksize; if (group_size > io_get_cache_size(channel)) goto out; cl = &(di->id2.i_chain); count = cl->cl_next_free_rec; ret = ocfs2_malloc_blocks(channel, count, &buf); if (ret) goto out; memset(buf, 0, count * blocksize); ret = ocfs2_malloc(sizeof(struct io_vec_unit) * count, &ivus); if (ret) goto out; for (i = 0; i < count; ++i) { cr = &(cl->cl_recs[i]); ivus[i].ivu_blkno = cr->c_blkno; ivus[i].ivu_buf = buf + (i * blocksize); ivus[i].ivu_buflen = blocksize; } while (count) { ret = io_vec_read_blocks(channel, ivus, count); if (ret) goto out; for (i = 0, j = 0; i < count; ++i) { gd = (struct ocfs2_group_desc *)ivus[i].ivu_buf; ret = ocfs2_validate_meta_ecc(fs, ivus[i].ivu_buf, &gd->bg_check); if (ret) goto out; if (memcmp(gd->bg_signature, OCFS2_GROUP_DESC_SIGNATURE, strlen(OCFS2_GROUP_DESC_SIGNATURE))) { ret = OCFS2_ET_BAD_GROUP_DESC_MAGIC; goto out; } ocfs2_swap_group_desc_to_cpu(fs, gd); if ((gd->bg_next_group > OCFS2_SUPER_BLOCK_BLKNO) && (gd->bg_next_group < fs->fs_blocks)) { ivus[j].ivu_blkno = gd->bg_next_group; memset(ivus[j].ivu_buf, 0, blocksize); ivus[j].ivu_buflen = blocksize; j++; } } count = j; } out: ocfs2_free(&ivus); ocfs2_free(&buf); return ret; }
/* Try and replay the slots journals if they're dirty. This only returns * a non-zero error if the caller should not continue. */ errcode_t o2fsck_replay_journals(ocfs2_filesys *fs, int *replayed) { errcode_t err = 0, ret = 0; struct journal_info *jis = NULL, *ji; journal_superblock_t *jsb; char *buf = NULL; int journal_trouble = 0; uint16_t i, max_slots; ocfs2_bitmap *used_blocks = NULL; max_slots = OCFS2_RAW_SB(fs->fs_super)->s_max_slots; ret = ocfs2_block_bitmap_new(fs, "journal blocks", &used_blocks); if (ret) { com_err(whoami, ret, "while allocating journal block bitmap"); goto out; } ret = ocfs2_malloc_blocks(fs->fs_io, 1, &buf); if (ret) { com_err(whoami, ret, "while allocating room to read journal " "blocks"); goto out; } ret = ocfs2_malloc0(sizeof(struct journal_info) * max_slots, &jis); if (ret) { com_err(whoami, ret, "while allocating an array of block " "numbers for journal replay"); goto out; } printf("Checking each slot's journal.\n"); for (i = 0, ji = jis; i < max_slots; i++, ji++) { ji->ji_used_blocks = used_blocks; ji->ji_revoke = RB_ROOT; ji->ji_slot = i; /* sets ji->ji_replay */ err = prep_journal_info(fs, i, ji); if (err) { printf("Slot %d seems to have a corrupt journal.\n", i); journal_trouble = 1; continue; } if (!ji->ji_replay) { verbosef("slot %d is clean\n", i); continue; } err = walk_journal(fs, i, ji, buf, 0); if (err) { printf("Slot %d's journal can not be replayed.\n", i); journal_trouble = 1; } } for (i = 0, ji = jis; i < max_slots; i++, ji++) { if (!ji->ji_replay) continue; printf("Replaying slot %d's journal.\n", i); err = walk_journal(fs, i, ji, buf, 1); if (err) { journal_trouble = 1; continue; } jsb = ji->ji_jsb; /* reset the journal */ jsb->s_start = 0; if (ji->ji_set_final_seq) jsb->s_sequence = ji->ji_final_seq + 1; /* we don't write back a clean 'mounted' bit here. That would * have to also include having recovered the orphan dir. we * updated s_start, though, so we won't replay the journal * again. */ err = ocfs2_write_journal_superblock(fs, ji->ji_jsb_block, (char *)ji->ji_jsb); if (err) { com_err(whoami, err, "while writing slot %d's journal " "super block", i); journal_trouble = 1; } else { printf("Slot %d's journal replayed successfully.\n", i); *replayed = 1; } } /* this is awkward, but we want fsck -n to tell us as much as it * can so we don't want to ask to proceed here. */ if (journal_trouble) printf("*** There were problems replaying journals. Be " "careful in telling fsck to make repairs to this " "filesystem.\n"); ret = 0; out: if (jis) { for (i = 0, ji = jis; i < max_slots; i++, ji++) { if (ji->ji_jsb) ocfs2_free(&ji->ji_jsb); if (ji->ji_cinode) ocfs2_free_cached_inode(fs, ji->ji_cinode); revoke_free_all(&ji->ji_revoke); } ocfs2_free(&jis); } if (buf) ocfs2_free(&buf); if (used_blocks) ocfs2_bitmap_free(used_blocks); return ret; }
errcode_t read_journal(ocfs2_filesys *fs, uint64_t blkno, FILE *out) { char *buf = NULL; char *jsb_buf = NULL; char *p; uint64_t blocknum; uint64_t len; uint64_t offset; uint32_t got; uint64_t last_unknown = 0; uint32_t buflen = 1024 * 1024; int buflenbits; ocfs2_cached_inode *ci = NULL; errcode_t ret; journal_superblock_t *jsb; ret = ocfs2_read_cached_inode(fs, blkno, &ci); if (ret) { com_err(gbls.cmd, ret, "while reading inode %"PRIu64, blkno); goto bail; } ret = ocfs2_malloc_block(fs->fs_io, &jsb_buf); if (ret) { com_err(gbls.cmd, ret, "while allocating journal superblock buffer"); goto bail; } buflenbits = buflen >> OCFS2_RAW_SB(gbls.fs->fs_super)->s_blocksize_bits; ret = ocfs2_malloc_blocks(fs->fs_io, buflenbits, &buf); if (ret) { com_err(gbls.cmd, ret, "while allocating %u bytes", buflen); goto bail; } offset = 0; blocknum = 0; jsb = (journal_superblock_t *)jsb_buf; while (1) { ret = ocfs2_file_read(ci, buf, buflen, offset, &got); if (ret) { com_err(gbls.cmd, ret, "while reading journal"); goto bail; }; if (got == 0) break; p = buf; len = got; if (offset == 0) { memcpy(jsb_buf, buf, fs->fs_blocksize); dump_jbd_superblock(out, jsb); ocfs2_swap_journal_superblock(jsb); blocknum++; p += fs->fs_blocksize; len -= fs->fs_blocksize; } scan_journal(out, jsb, p, len, &blocknum, &last_unknown); if (got < buflen) break; offset += got; } if (last_unknown) { dump_jbd_unknown(out, last_unknown, blocknum); last_unknown = 0; } bail: if (jsb_buf) ocfs2_free(&jsb_buf); if (buf) ocfs2_free(&buf); if (ci) ocfs2_free_cached_inode(fs, ci); return ret; }
errcode_t ocfs2_read_whole_file(ocfs2_filesys *fs, uint64_t blkno, char **buf, int *len) { struct read_whole_context ctx; errcode_t retval; char *inode_buf; struct ocfs2_dinode *di; /* So the caller can see nothing was read */ *len = 0; *buf = NULL; retval = ocfs2_malloc_block(fs->fs_io, &inode_buf); if (retval) return retval; retval = ocfs2_read_inode(fs, blkno, inode_buf); if (retval) goto out_free; di = (struct ocfs2_dinode *)inode_buf; /* Arbitrary limit for our malloc */ retval = OCFS2_ET_INVALID_ARGUMENT; if (di->i_size > INT_MAX) goto out_free; retval = ocfs2_malloc_blocks(fs->fs_io, ocfs2_blocks_in_bytes(fs, di->i_size), buf); if (retval) goto out_free; if (di->i_dyn_features & OCFS2_INLINE_DATA_FL) return ocfs2_inline_data_read(di, *buf, di->i_size, 0, (uint32_t *)len); ctx.buf = *buf; ctx.ptr = *buf; ctx.size = di->i_size; ctx.offset = 0; ctx.errcode = 0; retval = ocfs2_block_iterate(fs, blkno, 0, read_whole_func, &ctx); *len = ctx.size; if (ctx.offset < ctx.size) *len = ctx.offset; out_free: ocfs2_free(&inode_buf); if (!(*len)) { ocfs2_free(buf); *buf = NULL; } if (retval) return retval; return ctx.errcode; }
errcode_t ocfs2_malloc_block(io_channel *channel, void *ptr) { return ocfs2_malloc_blocks(channel, 1, ptr); }
/* * allocate ocfs2_image_bitmap_arr and ocfs2 image bitmap blocks. o2image bitmap * block is of size OCFS2_IMAGE_BITMAP_BLOCKSIZE and ocfs2_image_bitmap_arr * tracks the bitmap blocks */ errcode_t ocfs2_image_alloc_bitmap(ocfs2_filesys *ofs) { uint64_t blks, allocsize, leftsize; struct ocfs2_image_state *ost = ofs->ost; int indx, i, n; errcode_t ret; char *buf; ost->ost_bmpblks = ((ost->ost_fsblkcnt - 1) / (OCFS2_IMAGE_BITS_IN_BLOCK)) + 1; ost->ost_bmpblksz = OCFS2_IMAGE_BITMAP_BLOCKSIZE; blks = ost->ost_bmpblks; /* allocate memory for an array to track bitmap blocks */ ret = ocfs2_malloc0((blks * sizeof(ocfs2_image_bitmap_arr)), &ost->ost_bmparr); if (ret) return ret; allocsize = blks * OCFS2_IMAGE_BITMAP_BLOCKSIZE; leftsize = allocsize; indx = 0; /* allocate bitmap blocks and assign blocks to above array */ while (leftsize) { ret = ocfs2_malloc_blocks(ofs->fs_io, allocsize/io_get_blksize(ofs->fs_io), &buf); if (ret && (ret != -ENOMEM)) goto out; if (ret == -ENOMEM) { if (allocsize == OCFS2_IMAGE_BITMAP_BLOCKSIZE) goto out; allocsize >>= 1; if (allocsize % OCFS2_IMAGE_BITMAP_BLOCKSIZE) { allocsize /= OCFS2_IMAGE_BITMAP_BLOCKSIZE; allocsize *= OCFS2_IMAGE_BITMAP_BLOCKSIZE; } continue; } n = allocsize / OCFS2_IMAGE_BITMAP_BLOCKSIZE; for (i = 0; i < n; i++) { ost->ost_bmparr[indx].arr_set_bit_cnt = 0; ost->ost_bmparr[indx].arr_map = ((char *)buf + (i * OCFS2_IMAGE_BITMAP_BLOCKSIZE)); /* remember buf address to free it later */ if (!i) ost->ost_bmparr[indx].arr_self = buf; indx++; } leftsize -= allocsize; if (leftsize <= allocsize) allocsize = leftsize; } out: /* If allocation failed free and return error */ if (leftsize) { for (i = 0; i < indx; i++) if (ost->ost_bmparr[i].arr_self) ocfs2_free(&ost->ost_bmparr[i].arr_self); ocfs2_free(&ost->ost_bmparr); } return ret; }
int main(int argc, char *argv[]) { errcode_t ret; int c; int64_t blkno, count, blksize; char *filename; io_channel *channel; char *blks; /* Some simple defaults */ blksize = 512; blkno = 0; count = 1; initialize_ocfs_error_table(); while((c = getopt(argc, argv, "b:c:B:")) != EOF) { switch (c) { case 'b': blkno = read_number(optarg); if (blkno < 0) { fprintf(stderr, "Invalid blkno: %s\n", optarg); print_usage(); return 1; } break; case 'c': count = read_number(optarg); if (!count) { fprintf(stderr, "Invalid count: %s\n", optarg); print_usage(); return 1; } break; case 'B': blksize = read_number(optarg); if (!blksize) { fprintf(stderr, "Invalid blksize: %s\n", optarg); print_usage(); return 1; } break; default: print_usage(); return 1; break; } } if (blksize % OCFS2_MIN_BLOCKSIZE) { fprintf(stderr, "Invalid blocksize: %"PRId64"\n", blksize); print_usage(); return 1; } if (count < 0) { if (-count > (int64_t)INT_MAX) { fprintf(stderr, "Count is too large: %"PRId64"\n", count); print_usage(); return 1; } count = -count / blksize; } else { if ((count * blksize) > INT_MAX) { fprintf(stderr, "Count is too large: %"PRId64"\n", count); print_usage(); return 1; } } if (optind >= argc) { fprintf(stderr, "Missing filename\n"); print_usage(); return 1; } filename = argv[optind]; ret = io_open(filename, OCFS2_FLAG_RO, &channel); if (ret) { com_err(argv[0], ret, "while opening file \"%s\"", filename); goto out; } ret = ocfs2_malloc_blocks(channel, (int)count, &blks); if (ret) { com_err(argv[0], ret, "while allocating %"PRId64" blocks", count); goto out_channel; } ret = io_read_block(channel, blkno, (int)count, blks); if (ret) { com_err(argv[0], ret, "while reading %"PRId64" blocks at block %"PRId64" (%s)", count, blkno, strerror(io_get_error(channel))); goto out_blocks; } for (c = 0; c < count; c++) dump_block(blkno + c, blksize, blks + (c * blksize)); out_blocks: ocfs2_free(&blks); out_channel: ret = io_close(channel); if (ret) { com_err(argv[0], ret, "while closing file \"%s\"", filename); } out: return 0; }
static errcode_t replay_blocks(ocfs2_filesys *fs, struct journal_info *ji, char *buf, uint64_t seq, uint64_t *next_block) { char *tagp; journal_block_tag_t *tag; size_t i, num; char *io_buf = NULL; errcode_t err, ret = 0; int tag_bytes = ocfs2_journal_tag_bytes(ji->ji_jsb); uint32_t t_flags; uint64_t block64; tagp = buf + sizeof(journal_header_t); num = (ji->ji_jsb->s_blocksize - sizeof(journal_header_t)) / tag_bytes; ret = ocfs2_malloc_blocks(fs->fs_io, 1, &io_buf); if (ret) { com_err(whoami, ret, "while allocating a block buffer"); goto out; } for(i = 0; i < num; i++, tagp += tag_bytes, (*next_block)++) { tag = (journal_block_tag_t *)tagp; t_flags = be32_to_cpu(tag->t_flags); block64 = ocfs2_journal_tag_block(tag, tag_bytes); *next_block = jwrap(ji->ji_jsb, *next_block); verbosef("recovering journal block %"PRIu64" to disk block " "%"PRIu64"\n", *next_block, block64); if (revoke_this_block(&ji->ji_revoke, block64, seq)) goto skip_io; err = read_journal_block(fs, ji, *next_block, io_buf, 1); if (err) { ret = err; goto skip_io; } if (t_flags & JBD2_FLAG_ESCAPE) { uint32_t magic = cpu_to_be32(JBD2_MAGIC_NUMBER); memcpy(io_buf, &magic, sizeof(magic)); } err = io_write_block(fs->fs_io, block64, 1, io_buf); if (err) ret = err; skip_io: if (t_flags & JBD2_FLAG_LAST_TAG) i = num; /* be sure to increment next_block */ if (!(t_flags & JBD2_FLAG_SAME_UUID)) tagp += 16; } out: if (io_buf) ocfs2_free(&io_buf); return ret; }
void mess_up_dup_clusters(ocfs2_filesys *fs, enum fsck_type type, uint64_t blkno) { errcode_t err; char *buf = NULL; uint64_t inode1_blkno, inode2_blkno; struct ocfs2_dinode *di1, *di2; struct ocfs2_extent_list *el1, *el2; err = ocfs2_malloc_blocks(fs->fs_io, 2, &buf); if (err) FSWRK_COM_FATAL(progname, err); create_file(fs, blkno, &inode1_blkno); di1 = (struct ocfs2_dinode *)buf; err = ocfs2_read_inode(fs, inode1_blkno, (char *)di1); if (err) FSWRK_COM_FATAL(progname, err); if (ocfs2_support_inline_data(OCFS2_RAW_SB(fs->fs_super))) { if (di1->i_dyn_features & OCFS2_INLINE_DATA_FL) { di1->i_dyn_features &= ~OCFS2_INLINE_DATA_FL; err = ocfs2_write_inode(fs, inode1_blkno, (char *)di1); if (err) FSWRK_COM_FATAL(progname, err); } } if (type != DUP_CLUSTERS_SYSFILE_CLONE) { create_file(fs, blkno, &inode2_blkno); di2 = (struct ocfs2_dinode *)(buf + fs->fs_blocksize); err = ocfs2_read_inode(fs, inode2_blkno, (char *)di2); if (err) FSWRK_COM_FATAL(progname, err); if (ocfs2_support_inline_data(OCFS2_RAW_SB(fs->fs_super))) { if (di2->i_dyn_features & OCFS2_INLINE_DATA_FL) { di2->i_dyn_features &= ~OCFS2_INLINE_DATA_FL; err = ocfs2_write_inode(fs, inode2_blkno, (char *)di2); if (err) FSWRK_COM_FATAL(progname, err); } } err = ocfs2_extend_allocation(fs, inode2_blkno, 1); if (err) FSWRK_COM_FATAL(progname, err); /* Re-read the inode with the allocation */ err = ocfs2_read_inode(fs, inode2_blkno, (char *)di2); if (err) FSWRK_COM_FATAL(progname, err); /* Set i_size to non-zero so that the allocation is valid */ di2->i_size = fs->fs_clustersize; err = ocfs2_write_inode(fs, inode2_blkno, (char *)di2); if (err) FSWRK_COM_FATAL(progname, err); if (type == DUP_CLUSTERS_CLONE) fprintf(stdout, "DUP_CLUSTERS_CLONE: " "Create two inodes #%"PRIu64" and #%"PRIu64 " by allocating same cluster to them.\n", inode1_blkno, inode2_blkno); else fprintf(stdout, "DUP_CLUSTERS_DELETE: " "Create two inodes #%"PRIu64" and #%"PRIu64 " by allocating same cluster to them.\n", inode1_blkno, inode2_blkno); } else { /* Here use journal file*/ err = ocfs2_lookup_system_inode(fs, JOURNAL_SYSTEM_INODE, 0, &inode2_blkno); if (err) FSWRK_COM_FATAL(progname, err); di2 = (struct ocfs2_dinode *)(buf + fs->fs_blocksize); err = ocfs2_read_inode(fs, inode2_blkno, (char *)di2); if (err) FSWRK_COM_FATAL(progname, err); if (di2->id2.i_list.l_tree_depth) FSWRK_FATAL("Journal inode has non-zero tree " "depth. fswreck can't use it for " "DUP_CLUSTERS_SYSFILE_CLONE\n"); fprintf(stdout, "DUP_CLUSTERS_SYSFILE_CLONE: " "Allocate same cluster to journal file " "#%"PRIu64" and regular file #%"PRIu64".\n", inode1_blkno, inode2_blkno); } el1 = &(di1->id2.i_list); el2 = &(di2->id2.i_list); el1->l_next_free_rec = 1; el1->l_recs[0] = el2->l_recs[0]; di1->i_size = ocfs2_clusters_to_bytes(fs, el1->l_recs[0].e_leaf_clusters); di1->i_clusters = di2->i_clusters; err = ocfs2_write_inode(fs, inode1_blkno, (char *)di1); if (err) FSWRK_COM_FATAL(progname, err); ocfs2_free(&buf); }
int main(int argc, char *argv[]) { errcode_t ret; uint64_t blkno; int c; int walk_blocks = 0, walk_extents = 0; char *filename, *buf, *eb_buf = NULL; ocfs2_filesys *fs; struct ocfs2_dinode *di; struct walk_it wi; struct walk_block wb; blkno = OCFS2_SUPER_BLOCK_BLKNO; initialize_ocfs_error_table(); while ((c = getopt(argc, argv, "bei:")) != EOF) { switch (c) { case 'b': walk_blocks = 1; break; case 'e': walk_extents = 1; break; case 'i': blkno = read_number(optarg); if (blkno <= OCFS2_SUPER_BLOCK_BLKNO) { fprintf(stderr, "Invalid inode block: %s\n", optarg); print_usage(); return 1; } break; default: print_usage(); return 1; break; } } if (optind >= argc) { fprintf(stderr, "Missing filename\n"); print_usage(); return 1; } filename = argv[optind]; if (!(walk_blocks + walk_extents)) { fprintf(stderr, "No operation specified\n"); print_usage(); return 1; } ret = ocfs2_open(filename, OCFS2_FLAG_RO, 0, 0, &fs); if (ret) { com_err(argv[0], ret, "while opening file \"%s\"", filename); goto out; } ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) { com_err(argv[0], ret, "while allocating inode buffer"); goto out_close; } ret = ocfs2_read_inode(fs, blkno, buf); if (ret) { com_err(argv[0], ret, "while reading inode %"PRIu64, blkno); goto out_free; } di = (struct ocfs2_dinode *)buf; fprintf(stdout, "OCFS2 inode %"PRIu64" on \"%s\" has depth %"PRId16"\n", blkno, filename, di->id2.i_list.l_tree_depth); if (walk_extents) { if (di->id2.i_list.l_tree_depth) { ret = ocfs2_malloc_blocks(fs->fs_io, di->id2.i_list.l_tree_depth, &eb_buf); if (ret) { com_err(argv[0], ret, "while allocating eb buffer"); goto out_free; } } wi.di = di; ret = ocfs2_extent_iterate(fs, blkno, 0, eb_buf, walk_extents_func, &wi); if (ret) { com_err(argv[0], ret, "while walking extents"); goto out_free; } } if (walk_blocks) { wb.di = di; wb.run_first_blkno = wb.run_first_bcount = wb.run_prev_blkno = 0; wb.last_block = (wb.di->i_size + (fs->fs_blocksize - 1)) / fs->fs_blocksize; ret = ocfs2_block_iterate(fs, blkno, 0, walk_blocks_func, &wb); if (ret) { com_err(argv[0], ret, "while walking blocks"); goto out_free; } } out_free: if (eb_buf) ocfs2_free(&eb_buf); ocfs2_free(&buf); out_close: ret = ocfs2_close(fs); if (ret) { com_err(argv[0], ret, "while closing file \"%s\"", filename); } out: return 0; }