static int ocfs2_validate_group_descriptor(struct super_block *sb, struct buffer_head *bh) { int rc; struct ocfs2_group_desc *gd = (struct ocfs2_group_desc *)bh->b_data; trace_ocfs2_validate_group_descriptor( (unsigned long long)bh->b_blocknr); BUG_ON(!buffer_uptodate(bh)); /* * If the ecc fails, we return the error but otherwise * leave the filesystem running. We know any error is * local to this block. */ rc = ocfs2_validate_meta_ecc(sb, bh->b_data, &gd->bg_check); if (rc) return rc; /* * Errors after here are fatal. */ return ocfs2_validate_gd_self(sb, bh, 0); }
/* * This version only prints errors. It does not fail the filesystem, and * exists only for resize. */ int ocfs2_check_group_descriptor(struct super_block *sb, struct ocfs2_dinode *di, struct buffer_head *bh) { int rc; struct ocfs2_group_desc *gd = (struct ocfs2_group_desc *)bh->b_data; BUG_ON(!buffer_uptodate(bh)); /* * If the ecc fails, we return the error but otherwise * leave the filesystem running. We know any error is * local to this block. */ rc = ocfs2_validate_meta_ecc(sb, bh->b_data, &gd->bg_check); if (rc) { mlog(ML_ERROR, "Checksum failed for group descriptor %llu\n", (unsigned long long)bh->b_blocknr); } else rc = ocfs2_validate_gd_self(sb, bh, 1); if (!rc) rc = ocfs2_validate_gd_parent(sb, di, bh, 1); return rc; }
errcode_t ocfs2_read_extent_block_nocheck(ocfs2_filesys *fs, uint64_t blkno, char *eb_buf) { errcode_t ret; char *blk; struct ocfs2_extent_block *eb; if ((blkno < OCFS2_SUPER_BLOCK_BLKNO) || (blkno > fs->fs_blocks)) return OCFS2_ET_BAD_BLKNO; ret = ocfs2_malloc_block(fs->fs_io, &blk); if (ret) return ret; ret = ocfs2_read_blocks(fs, blkno, 1, blk); if (ret) goto out; eb = (struct ocfs2_extent_block *)blk; ret = ocfs2_validate_meta_ecc(fs, blk, &eb->h_check); if (ret) goto out; if (memcmp(eb->h_signature, OCFS2_EXTENT_BLOCK_SIGNATURE, strlen(OCFS2_EXTENT_BLOCK_SIGNATURE))) { ret = OCFS2_ET_BAD_EXTENT_BLOCK_MAGIC; goto out; } memcpy(eb_buf, blk, fs->fs_blocksize); eb = (struct ocfs2_extent_block *) eb_buf; ocfs2_swap_extent_block_to_cpu(fs, eb); out: ocfs2_free(&blk); return ret; }
errcode_t ocfs2_read_group_desc(ocfs2_filesys *fs, uint64_t blkno, char *gd_buf) { errcode_t ret; char *blk; struct ocfs2_group_desc *gd; if ((blkno < OCFS2_SUPER_BLOCK_BLKNO) || (blkno > fs->fs_blocks)) return OCFS2_ET_BAD_BLKNO; ret = ocfs2_malloc_block(fs->fs_io, &blk); if (ret) return ret; ret = ocfs2_read_blocks(fs, blkno, 1, blk); if (ret) goto out; gd = (struct ocfs2_group_desc *)blk; ret = ocfs2_validate_meta_ecc(fs, blk, &gd->bg_check); if (ret) goto out; ret = OCFS2_ET_BAD_GROUP_DESC_MAGIC; if (memcmp(gd->bg_signature, OCFS2_GROUP_DESC_SIGNATURE, strlen(OCFS2_GROUP_DESC_SIGNATURE))) goto out; memcpy(gd_buf, blk, fs->fs_blocksize); gd = (struct ocfs2_group_desc *)gd_buf; ocfs2_swap_group_desc_to_cpu(fs, gd); ret = 0; out: ocfs2_free(&blk); return ret; }
errcode_t ocfs2_read_super(ocfs2_filesys *fs, uint64_t superblock, char *sb) { errcode_t ret; char *blk, *swapblk; struct ocfs2_dinode *di, *orig_super; int orig_blocksize; int blocksize = io_get_blksize(fs->fs_io); ret = ocfs2_malloc_block(fs->fs_io, &blk); if (ret) return ret; ret = ocfs2_read_blocks(fs, superblock, 1, blk); if (ret) goto out_blk; di = (struct ocfs2_dinode *)blk; ret = OCFS2_ET_BAD_MAGIC; if (memcmp(di->i_signature, OCFS2_SUPER_BLOCK_SIGNATURE, strlen(OCFS2_SUPER_BLOCK_SIGNATURE))) goto out_blk; /* * We want to use the latest superblock to validate. We need * a local-endian copy in fs->fs_super, and the unswapped copy to * check in blk. ocfs2_validate_meta_ecc() uses fs->fs_super and * fs->fs_blocksize. */ ret = ocfs2_malloc_block(fs->fs_io, &swapblk); if (ret) goto out_blk; memcpy(swapblk, blk, blocksize); orig_super = fs->fs_super; orig_blocksize = fs->fs_blocksize; fs->fs_super = (struct ocfs2_dinode *)swapblk; fs->fs_blocksize = blocksize; ocfs2_swap_inode_to_cpu(fs, fs->fs_super); ret = ocfs2_validate_meta_ecc(fs, blk, &di->i_check); fs->fs_super = orig_super; fs->fs_blocksize = orig_blocksize; ocfs2_free(&swapblk); if (ret) goto out_blk; ocfs2_swap_inode_to_cpu(fs, di); if (!sb) fs->fs_super = di; else { memcpy(sb, blk, fs->fs_blocksize); ocfs2_free(&blk); } return 0; out_blk: ocfs2_free(&blk); return ret; }
int ocfs2_validate_inode_block(struct super_block *sb, struct buffer_head *bh) { int rc; struct ocfs2_dinode *di = (struct ocfs2_dinode *)bh->b_data; trace_ocfs2_validate_inode_block((unsigned long long)bh->b_blocknr); BUG_ON(!buffer_uptodate(bh)); /* * If the ecc fails, we return the error but otherwise * leave the filesystem running. We know any error is * local to this block. */ rc = ocfs2_validate_meta_ecc(sb, bh->b_data, &di->i_check); if (rc) { mlog(ML_ERROR, "Checksum failed for dinode %llu\n", (unsigned long long)bh->b_blocknr); goto bail; } /* * Errors after here are fatal. */ rc = -EINVAL; if (!OCFS2_IS_VALID_DINODE(di)) { ocfs2_error(sb, "Invalid dinode #%llu: signature = %.*s\n", (unsigned long long)bh->b_blocknr, 7, di->i_signature); goto bail; } if (le64_to_cpu(di->i_blkno) != bh->b_blocknr) { ocfs2_error(sb, "Invalid dinode #%llu: i_blkno is %llu\n", (unsigned long long)bh->b_blocknr, (unsigned long long)le64_to_cpu(di->i_blkno)); goto bail; } if (!(di->i_flags & cpu_to_le32(OCFS2_VALID_FL))) { ocfs2_error(sb, "Invalid dinode #%llu: OCFS2_VALID_FL not set\n", (unsigned long long)bh->b_blocknr); goto bail; } if (le32_to_cpu(di->i_fs_generation) != OCFS2_SB(sb)->fs_generation) { ocfs2_error(sb, "Invalid dinode #%llu: fs_generation is %u\n", (unsigned long long)bh->b_blocknr, le32_to_cpu(di->i_fs_generation)); goto bail; } rc = 0; bail: return rc; }
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; }
static int ocfs2_filecheck_repair_inode_block(struct super_block *sb, struct buffer_head *bh) { int changed = 0; struct ocfs2_dinode *di = (struct ocfs2_dinode *)bh->b_data; if (!ocfs2_filecheck_validate_inode_block(sb, bh)) return 0; trace_ocfs2_filecheck_repair_inode_block( (unsigned long long)bh->b_blocknr); if (ocfs2_is_hard_readonly(OCFS2_SB(sb)) || ocfs2_is_soft_readonly(OCFS2_SB(sb))) { mlog(ML_ERROR, "Filecheck: cannot repair dinode #%llu " "on readonly filesystem\n", (unsigned long long)bh->b_blocknr); return -OCFS2_FILECHECK_ERR_READONLY; } if (buffer_jbd(bh)) { mlog(ML_ERROR, "Filecheck: cannot repair dinode #%llu, " "its buffer is in jbd\n", (unsigned long long)bh->b_blocknr); return -OCFS2_FILECHECK_ERR_INJBD; } if (!OCFS2_IS_VALID_DINODE(di)) { /* Cannot fix invalid inode block */ return -OCFS2_FILECHECK_ERR_INVALIDINO; } if (!(di->i_flags & cpu_to_le32(OCFS2_VALID_FL))) { /* Cannot just add VALID_FL flag back as a fix, * need more things to check here. */ return -OCFS2_FILECHECK_ERR_VALIDFLAG; } if (le64_to_cpu(di->i_blkno) != bh->b_blocknr) { di->i_blkno = cpu_to_le64(bh->b_blocknr); changed = 1; mlog(ML_ERROR, "Filecheck: reset dinode #%llu: i_blkno to %llu\n", (unsigned long long)bh->b_blocknr, (unsigned long long)le64_to_cpu(di->i_blkno)); } if (le32_to_cpu(di->i_fs_generation) != OCFS2_SB(sb)->fs_generation) { di->i_fs_generation = cpu_to_le32(OCFS2_SB(sb)->fs_generation); changed = 1; mlog(ML_ERROR, "Filecheck: reset dinode #%llu: fs_generation to %u\n", (unsigned long long)bh->b_blocknr, le32_to_cpu(di->i_fs_generation)); } if (changed || ocfs2_validate_meta_ecc(sb, bh->b_data, &di->i_check)) { ocfs2_compute_meta_ecc(sb, bh->b_data, &di->i_check); mark_buffer_dirty(bh); mlog(ML_ERROR, "Filecheck: reset dinode #%llu: compute meta ecc\n", (unsigned long long)bh->b_blocknr); } return 0; }
static int ocfs2_filecheck_validate_inode_block(struct super_block *sb, struct buffer_head *bh) { int rc = 0; struct ocfs2_dinode *di = (struct ocfs2_dinode *)bh->b_data; trace_ocfs2_filecheck_validate_inode_block( (unsigned long long)bh->b_blocknr); BUG_ON(!buffer_uptodate(bh)); /* * Call ocfs2_validate_meta_ecc() first since it has ecc repair * function, but we should not return error immediately when ecc * validation fails, because the reason is quite likely the invalid * inode number inputed. */ rc = ocfs2_validate_meta_ecc(sb, bh->b_data, &di->i_check); if (rc) { mlog(ML_ERROR, "Filecheck: checksum failed for dinode %llu\n", (unsigned long long)bh->b_blocknr); rc = -OCFS2_FILECHECK_ERR_BLOCKECC; } if (!OCFS2_IS_VALID_DINODE(di)) { mlog(ML_ERROR, "Filecheck: invalid dinode #%llu: signature = %.*s\n", (unsigned long long)bh->b_blocknr, 7, di->i_signature); rc = -OCFS2_FILECHECK_ERR_INVALIDINO; goto bail; } else if (rc) goto bail; if (le64_to_cpu(di->i_blkno) != bh->b_blocknr) { mlog(ML_ERROR, "Filecheck: invalid dinode #%llu: i_blkno is %llu\n", (unsigned long long)bh->b_blocknr, (unsigned long long)le64_to_cpu(di->i_blkno)); rc = -OCFS2_FILECHECK_ERR_BLOCKNO; goto bail; } if (!(di->i_flags & cpu_to_le32(OCFS2_VALID_FL))) { mlog(ML_ERROR, "Filecheck: invalid dinode #%llu: OCFS2_VALID_FL " "not set\n", (unsigned long long)bh->b_blocknr); rc = -OCFS2_FILECHECK_ERR_VALIDFLAG; goto bail; } if (le32_to_cpu(di->i_fs_generation) != OCFS2_SB(sb)->fs_generation) { mlog(ML_ERROR, "Filecheck: invalid dinode #%llu: fs_generation is %u\n", (unsigned long long)bh->b_blocknr, le32_to_cpu(di->i_fs_generation)); rc = -OCFS2_FILECHECK_ERR_GENERATION; } bail: return rc; }