errcode_t ocfs2_write_group_desc(ocfs2_filesys *fs, uint64_t blkno, char *gd_buf) { errcode_t ret; char *blk; struct ocfs2_group_desc *gd; if (!(fs->fs_flags & OCFS2_FLAG_RW)) return OCFS2_ET_RO_FILESYS; 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; memcpy(blk, gd_buf, fs->fs_blocksize); gd = (struct ocfs2_group_desc *)blk; ocfs2_swap_group_desc_from_cpu(fs, gd); ocfs2_compute_meta_ecc(fs, blk, &gd->bg_check); ret = io_write_block(fs->fs_io, blkno, 1, blk); if (ret) goto out; fs->fs_flags |= OCFS2_FLAG_CHANGED; ret = 0; out: ocfs2_free(&blk); return ret; }
/* * Write super block and backups doesn't need to collaborate with journal, * so we don't need to lock ip_io_mutex and ci doesn't need to bea passed * into this function. */ int ocfs2_write_super_or_backup(struct ocfs2_super *osb, struct buffer_head *bh) { int ret = 0; struct ocfs2_dinode *di = (struct ocfs2_dinode *)bh->b_data; BUG_ON(buffer_jbd(bh)); ocfs2_check_super_or_backup(osb->sb, bh->b_blocknr); if (ocfs2_is_hard_readonly(osb) || ocfs2_is_soft_readonly(osb)) { ret = -EROFS; mlog_errno(ret); goto out; } lock_buffer(bh); set_buffer_uptodate(bh); /* remove from dirty list before I/O. */ clear_buffer_dirty(bh); get_bh(bh); /* for end_buffer_write_sync() */ bh->b_end_io = end_buffer_write_sync; ocfs2_compute_meta_ecc(osb->sb, bh->b_data, &di->i_check); submit_bh(REQ_OP_WRITE, 0, bh); wait_on_buffer(bh); if (!buffer_uptodate(bh)) { ret = -EIO; mlog_errno(ret); } out: return ret; }
errcode_t ocfs2_write_extent_block(ocfs2_filesys *fs, uint64_t blkno, char *eb_buf) { errcode_t ret; char *blk; struct ocfs2_extent_block *eb; if (!(fs->fs_flags & OCFS2_FLAG_RW)) return OCFS2_ET_RO_FILESYS; 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; memcpy(blk, eb_buf, fs->fs_blocksize); eb = (struct ocfs2_extent_block *) blk; ocfs2_swap_extent_block_from_cpu(fs, eb); ocfs2_compute_meta_ecc(fs, blk, &eb->h_check); ret = io_write_block(fs->fs_io, blkno, 1, blk); if (ret) goto out; fs->fs_flags |= OCFS2_FLAG_CHANGED; ret = 0; out: ocfs2_free(&blk); return ret; }
/* * We want to free the bitmap bits outside of any recovery context as * we'll need a cluster lock to do so, but we must clear the local * alloc before giving up the recovered nodes journal. To solve this, * we kmalloc a copy of the local alloc before it's change for the * caller to process with ocfs2_complete_local_alloc_recovery */ int ocfs2_begin_local_alloc_recovery(struct ocfs2_super *osb, int slot_num, struct ocfs2_dinode **alloc_copy) { int status = 0; struct buffer_head *alloc_bh = NULL; struct inode *inode = NULL; struct ocfs2_dinode *alloc; trace_ocfs2_begin_local_alloc_recovery(slot_num); *alloc_copy = NULL; inode = ocfs2_get_system_file_inode(osb, LOCAL_ALLOC_SYSTEM_INODE, slot_num); if (!inode) { status = -EINVAL; mlog_errno(status); goto bail; } inode_lock(inode); status = ocfs2_read_inode_block_full(inode, &alloc_bh, OCFS2_BH_IGNORE_CACHE); if (status < 0) { mlog_errno(status); goto bail; } *alloc_copy = kmalloc(alloc_bh->b_size, GFP_KERNEL); if (!(*alloc_copy)) { status = -ENOMEM; goto bail; } memcpy((*alloc_copy), alloc_bh->b_data, alloc_bh->b_size); alloc = (struct ocfs2_dinode *) alloc_bh->b_data; ocfs2_clear_local_alloc(alloc); ocfs2_compute_meta_ecc(osb->sb, alloc_bh->b_data, &alloc->i_check); status = ocfs2_write_block(osb, alloc_bh, INODE_CACHE(inode)); if (status < 0) mlog_errno(status); bail: if (status < 0) { kfree(*alloc_copy); *alloc_copy = NULL; } brelse(alloc_bh); if (inode) { inode_unlock(inode); iput(inode); } if (status) mlog_errno(status); return status; }
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; }
/* * dump_block_check * */ void dump_block_check(FILE *out, struct ocfs2_block_check *bc, void *block) { struct ocfs2_block_check tmp = *bc; int crc_fail; enum ocfs2_block_type bt = ocfs2_detect_block(block); /* Swap block to little endian for compute_meta_ecc */ switch (bt) { case OCFS2_BLOCK_INODE: case OCFS2_BLOCK_SUPERBLOCK: ocfs2_swap_inode_from_cpu(gbls.fs, block); break; case OCFS2_BLOCK_EXTENT_BLOCK: ocfs2_swap_extent_block_from_cpu(gbls.fs, block); break; case OCFS2_BLOCK_GROUP_DESCRIPTOR: ocfs2_swap_group_desc_from_cpu(gbls.fs, block); break; case OCFS2_BLOCK_DIR_BLOCK: ocfs2_swap_dir_entries_from_cpu(block, gbls.fs->fs_blocksize); break; case OCFS2_BLOCK_XATTR: ocfs2_swap_xattr_block_from_cpu(gbls.fs, block); break; case OCFS2_BLOCK_REFCOUNT: ocfs2_swap_refcount_block_from_cpu(gbls.fs, block); break; case OCFS2_BLOCK_DXROOT: ocfs2_swap_dx_root_from_cpu(gbls.fs, block); break; case OCFS2_BLOCK_DXLEAF: ocfs2_swap_dx_leaf_from_cpu(block); break; default: fprintf(out, "Unable to determine block type"); return; } /* Re-compute based on what we got from disk */ ocfs2_compute_meta_ecc(gbls.fs, block, bc); /* Swap block back to CPU */ switch (bt) { case OCFS2_BLOCK_INODE: case OCFS2_BLOCK_SUPERBLOCK: ocfs2_swap_inode_to_cpu(gbls.fs, block); break; case OCFS2_BLOCK_EXTENT_BLOCK: ocfs2_swap_extent_block_to_cpu(gbls.fs, block); break; case OCFS2_BLOCK_GROUP_DESCRIPTOR: ocfs2_swap_group_desc_to_cpu(gbls.fs, block); break; case OCFS2_BLOCK_DIR_BLOCK: ocfs2_swap_dir_entries_to_cpu(block, gbls.fs->fs_blocksize); break; case OCFS2_BLOCK_XATTR: ocfs2_swap_xattr_block_to_cpu(gbls.fs, block); break; case OCFS2_BLOCK_REFCOUNT: ocfs2_swap_refcount_block_to_cpu(gbls.fs, block); break; case OCFS2_BLOCK_DXROOT: ocfs2_swap_dx_root_to_cpu(gbls.fs, block); break; case OCFS2_BLOCK_DXLEAF: ocfs2_swap_dx_leaf_to_cpu(block); break; default: break; } crc_fail = memcmp(bc, &tmp, sizeof(*bc)); fprintf(out, "\tCRC32: %.8"PRIx32" ECC: %.4"PRIx16"\n", le32_to_cpu(tmp.bc_crc32e), le16_to_cpu(tmp.bc_ecc)); if (crc_fail) fprintf(out, "\t**FAILED CHECKSUM** Computed CRC32: %.8" PRIx32" ECC: %.4"PRIx16"\n", le32_to_cpu(bc->bc_crc32e), le16_to_cpu(bc->bc_ecc)); /* Leave the block as we found it. */ *bc = tmp; }