Add metadata_csum feature support.
Reviewed by: pfg (mentor) Approved by: pfg (mentor) MFC after: 6 months Differential Revision: https://reviews.freebsd.org/D13810
This commit is contained in:
parent
9eec64c0aa
commit
512f29d141
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=327977
@ -898,13 +898,21 @@ ext2_alloccg(struct inode *ip, int cg, daddr_t bpref, int size)
|
||||
EXT2_LOCK(ump);
|
||||
return (0);
|
||||
}
|
||||
if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM)) {
|
||||
if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM) ||
|
||||
EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) {
|
||||
error = ext2_cg_block_bitmap_init(fs, cg, bp);
|
||||
if (error) {
|
||||
brelse(bp);
|
||||
EXT2_LOCK(ump);
|
||||
return (0);
|
||||
}
|
||||
ext2_gd_b_bitmap_csum_set(fs, cg, bp);
|
||||
}
|
||||
error = ext2_gd_b_bitmap_csum_verify(fs, cg, bp);
|
||||
if (error) {
|
||||
brelse(bp);
|
||||
EXT2_LOCK(ump);
|
||||
return (0);
|
||||
}
|
||||
if (e2fs_gd_get_nbfree(&fs->e2fs_gd[cg]) == 0) {
|
||||
/*
|
||||
@ -1008,6 +1016,7 @@ ext2_alloccg(struct inode *ip, int cg, daddr_t bpref, int size)
|
||||
e2fs_gd_get_nbfree(&fs->e2fs_gd[cg]) - 1);
|
||||
fs->e2fs_fmod = 1;
|
||||
EXT2_UNLOCK(ump);
|
||||
ext2_gd_b_bitmap_csum_set(fs, cg, bp);
|
||||
bdwrite(bp);
|
||||
return (((uint64_t)cg) * fs->e2fs->e2fs_fpg + fs->e2fs->e2fs_first_dblock + bno);
|
||||
}
|
||||
@ -1187,11 +1196,13 @@ ext2_nodealloccg(struct inode *ip, int cg, daddr_t ipref, int mode)
|
||||
EXT2_LOCK(ump);
|
||||
return (0);
|
||||
}
|
||||
if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM)) {
|
||||
if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM) ||
|
||||
EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) {
|
||||
if (fs->e2fs_gd[cg].ext4bgd_flags & EXT2_BG_INODE_UNINIT) {
|
||||
memset(bp->b_data, 0, fs->e2fs_bsize);
|
||||
fs->e2fs_gd[cg].ext4bgd_flags &= ~EXT2_BG_INODE_UNINIT;
|
||||
}
|
||||
ext2_gd_i_bitmap_csum_set(fs, cg, bp);
|
||||
error = ext2_zero_inode_table(ip, cg);
|
||||
if (error) {
|
||||
brelse(bp);
|
||||
@ -1199,6 +1210,12 @@ ext2_nodealloccg(struct inode *ip, int cg, daddr_t ipref, int mode)
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
error = ext2_gd_i_bitmap_csum_verify(fs, cg, bp);
|
||||
if (error) {
|
||||
brelse(bp);
|
||||
EXT2_LOCK(ump);
|
||||
return (0);
|
||||
}
|
||||
if (e2fs_gd_get_nifree(&fs->e2fs_gd[cg]) == 0) {
|
||||
/*
|
||||
* Another thread allocated the last i-node in this
|
||||
@ -1234,7 +1251,8 @@ ext2_nodealloccg(struct inode *ip, int cg, daddr_t ipref, int mode)
|
||||
EXT2_LOCK(ump);
|
||||
e2fs_gd_set_nifree(&fs->e2fs_gd[cg],
|
||||
e2fs_gd_get_nifree(&fs->e2fs_gd[cg]) - 1);
|
||||
if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM))
|
||||
if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM) ||
|
||||
EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
|
||||
e2fs_gd_set_i_unused(&fs->e2fs_gd[cg],
|
||||
e2fs_gd_get_i_unused(&fs->e2fs_gd[cg]) - 1);
|
||||
fs->e2fs->e2fs_ficount--;
|
||||
@ -1245,6 +1263,7 @@ ext2_nodealloccg(struct inode *ip, int cg, daddr_t ipref, int mode)
|
||||
fs->e2fs_total_dir++;
|
||||
}
|
||||
EXT2_UNLOCK(ump);
|
||||
ext2_gd_i_bitmap_csum_set(fs, cg, bp);
|
||||
bdwrite(bp);
|
||||
return ((uint64_t)cg * fs->e2fs_ipg + ipref + 1);
|
||||
}
|
||||
@ -1293,6 +1312,7 @@ ext2_blkfree(struct inode *ip, e4fs_daddr_t bno, long size)
|
||||
e2fs_gd_get_nbfree(&fs->e2fs_gd[cg]) + 1);
|
||||
fs->e2fs_fmod = 1;
|
||||
EXT2_UNLOCK(ump);
|
||||
ext2_gd_b_bitmap_csum_set(fs, cg, bp);
|
||||
bdwrite(bp);
|
||||
}
|
||||
|
||||
@ -1338,7 +1358,8 @@ ext2_vfree(struct vnode *pvp, ino_t ino, int mode)
|
||||
fs->e2fs->e2fs_ficount++;
|
||||
e2fs_gd_set_nifree(&fs->e2fs_gd[cg],
|
||||
e2fs_gd_get_nifree(&fs->e2fs_gd[cg]) + 1);
|
||||
if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM))
|
||||
if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM) ||
|
||||
EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
|
||||
e2fs_gd_set_i_unused(&fs->e2fs_gd[cg],
|
||||
e2fs_gd_get_i_unused(&fs->e2fs_gd[cg]) + 1);
|
||||
if ((mode & IFMT) == IFDIR) {
|
||||
@ -1348,6 +1369,7 @@ ext2_vfree(struct vnode *pvp, ino_t ino, int mode)
|
||||
}
|
||||
fs->e2fs_fmod = 1;
|
||||
EXT2_UNLOCK(ump);
|
||||
ext2_gd_i_bitmap_csum_set(fs, cg, bp);
|
||||
bdwrite(bp);
|
||||
return (0);
|
||||
}
|
||||
|
@ -43,9 +43,576 @@
|
||||
|
||||
#include <fs/ext2fs/fs.h>
|
||||
#include <fs/ext2fs/ext2fs.h>
|
||||
#include <fs/ext2fs/ext2_dinode.h>
|
||||
#include <fs/ext2fs/inode.h>
|
||||
#include <fs/ext2fs/ext2_dir.h>
|
||||
#include <fs/ext2fs/htree.h>
|
||||
#include <fs/ext2fs/ext2_extattr.h>
|
||||
#include <fs/ext2fs/ext2_extern.h>
|
||||
|
||||
#define EXT2_BG_INODE_BITMAP_CSUM_HI_END \
|
||||
(offsetof(struct ext2_gd, ext4bgd_i_bmap_csum_hi) + \
|
||||
sizeof(uint16_t))
|
||||
|
||||
#define EXT2_INODE_CSUM_HI_EXTRA_END \
|
||||
(offsetof(struct ext2fs_dinode, e2di_chksum_hi) + sizeof(uint16_t) - \
|
||||
E2FS_REV0_INODE_SIZE)
|
||||
|
||||
#define EXT2_BG_BLOCK_BITMAP_CSUM_HI_LOCATION \
|
||||
(offsetof(struct ext2_gd, ext4bgd_b_bmap_csum_hi) + \
|
||||
sizeof(uint16_t))
|
||||
|
||||
void
|
||||
ext2_sb_csum_set_seed(struct m_ext2fs *fs)
|
||||
{
|
||||
|
||||
if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_CSUM_SEED))
|
||||
fs->e2fs_csum_seed = fs->e2fs->e4fs_chksum_seed;
|
||||
else if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) {
|
||||
fs->e2fs_csum_seed = calculate_crc32c(~0, fs->e2fs->e2fs_uuid,
|
||||
sizeof(fs->e2fs->e2fs_uuid));
|
||||
}
|
||||
else
|
||||
fs->e2fs_csum_seed = 0;
|
||||
}
|
||||
|
||||
int
|
||||
ext2_sb_csum_verify(struct m_ext2fs *fs)
|
||||
{
|
||||
|
||||
if (fs->e2fs->e4fs_chksum_type != EXT4_CRC32C_CHKSUM) {
|
||||
printf(
|
||||
"WARNING: mount of %s denied due bad sb csum type\n", fs->e2fs_fsmnt);
|
||||
return (EINVAL);
|
||||
}
|
||||
if (fs->e2fs->e4fs_sbchksum !=
|
||||
calculate_crc32c(~0, (const char *)fs->e2fs,
|
||||
offsetof(struct ext2fs, e4fs_sbchksum))) {
|
||||
printf(
|
||||
"WARNING: mount of %s denied due bad sb csum=0x%x, expected=0x%x - run fsck\n",
|
||||
fs->e2fs_fsmnt, fs->e2fs->e4fs_sbchksum, calculate_crc32c(~0,
|
||||
(const char *)fs->e2fs, offsetof(struct ext2fs, e4fs_sbchksum)));
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
ext2_sb_csum_set(struct m_ext2fs *fs)
|
||||
{
|
||||
|
||||
fs->e2fs->e4fs_sbchksum = calculate_crc32c(~0, (const char *)fs->e2fs,
|
||||
offsetof(struct ext2fs, e4fs_sbchksum));
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
ext2_extattr_blk_csum(struct inode *ip, uint64_t facl,
|
||||
struct ext2fs_extattr_header *header)
|
||||
{
|
||||
struct m_ext2fs *fs;
|
||||
uint32_t crc, old_crc;
|
||||
|
||||
fs = ip->i_e2fs;
|
||||
|
||||
old_crc = header->h_checksum;
|
||||
|
||||
header->h_checksum = 0;
|
||||
crc = calculate_crc32c(fs->e2fs_csum_seed, (uint8_t *)&facl, sizeof(facl));
|
||||
crc = calculate_crc32c(crc, (uint8_t *)header, fs->e2fs_bsize);
|
||||
header->h_checksum = old_crc;
|
||||
|
||||
return (crc);
|
||||
}
|
||||
|
||||
int
|
||||
ext2_extattr_blk_csum_verify(struct inode *ip, struct buf *bp)
|
||||
{
|
||||
struct ext2fs_extattr_header *header;
|
||||
|
||||
header = (struct ext2fs_extattr_header *)bp->b_data;
|
||||
|
||||
if (EXT2_HAS_RO_COMPAT_FEATURE(ip->i_e2fs, EXT2F_ROCOMPAT_METADATA_CKSUM) &&
|
||||
(header->h_checksum != ext2_extattr_blk_csum(ip, ip->i_facl, header))) {
|
||||
printf("WARNING: bad extattr csum detected, ip=%lu - run fsck\n",
|
||||
(unsigned long)ip->i_number);
|
||||
return (EIO);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
ext2_extattr_blk_csum_set(struct inode *ip, struct buf *bp)
|
||||
{
|
||||
struct ext2fs_extattr_header *header;
|
||||
|
||||
if (!EXT2_HAS_RO_COMPAT_FEATURE(ip->i_e2fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
|
||||
return;
|
||||
|
||||
header = (struct ext2fs_extattr_header *)bp->b_data;
|
||||
header->h_checksum = ext2_extattr_blk_csum(ip, ip->i_facl, header);
|
||||
}
|
||||
|
||||
static struct ext2fs_direct_tail *
|
||||
ext2_get_dirent_tail(struct inode *ip, struct ext2fs_direct_2 *ep)
|
||||
{
|
||||
struct ext2fs_direct_tail *tp;
|
||||
|
||||
tp = EXT2_DIRENT_TAIL(ep, ip->i_e2fs->e2fs_bsize);
|
||||
if (tp->e2dt_reserved_zero1 ||
|
||||
tp->e2dt_rec_len != sizeof(struct ext2fs_direct_tail) ||
|
||||
tp->e2dt_reserved_zero2 ||
|
||||
tp->e2dt_reserved_ft != EXT2_FT_DIR_CSUM)
|
||||
return (NULL);
|
||||
|
||||
return (tp);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
ext2_dirent_csum(struct inode *ip, struct ext2fs_direct_2 *ep, int size)
|
||||
{
|
||||
struct m_ext2fs *fs;
|
||||
char *buf;
|
||||
uint32_t inum, gen, crc;
|
||||
|
||||
fs = ip->i_e2fs;
|
||||
|
||||
buf = (char *)ep;
|
||||
|
||||
inum = ip->i_number;
|
||||
gen = ip->i_gen;
|
||||
crc = calculate_crc32c(fs->e2fs_csum_seed, (uint8_t *)&inum, sizeof(inum));
|
||||
crc = calculate_crc32c(crc, (uint8_t *)&gen, sizeof(gen));
|
||||
crc = calculate_crc32c(crc, (uint8_t *)buf, size);
|
||||
|
||||
return (crc);
|
||||
}
|
||||
|
||||
static int
|
||||
ext2_dirent_csum_verify(struct inode *ip, struct ext2fs_direct_2 *ep)
|
||||
{
|
||||
uint32_t calculated;
|
||||
struct ext2fs_direct_tail *tp;
|
||||
|
||||
tp = ext2_get_dirent_tail(ip, ep);
|
||||
if (tp == NULL)
|
||||
return (0);
|
||||
|
||||
calculated = ext2_dirent_csum(ip, ep, (char *)tp - (char *)ep);
|
||||
if (calculated != tp->e2dt_checksum)
|
||||
return (EIO);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static struct ext2fs_htree_count *
|
||||
ext2_get_dx_count(struct inode *ip, struct ext2fs_direct_2 *ep, int *offset)
|
||||
{
|
||||
struct ext2fs_direct_2 *dp;
|
||||
struct ext2fs_htree_root_info *root;
|
||||
int count_offset;
|
||||
|
||||
if (ep->e2d_reclen == EXT2_BLOCK_SIZE(ip->i_e2fs))
|
||||
count_offset = 8;
|
||||
else if (ep->e2d_reclen == 12) {
|
||||
dp = (struct ext2fs_direct_2 *)(((char *)ep) + 12);
|
||||
if (dp->e2d_reclen != EXT2_BLOCK_SIZE(ip->i_e2fs) - 12)
|
||||
return (NULL);
|
||||
|
||||
root = (struct ext2fs_htree_root_info *)(((char *)dp + 12));
|
||||
if (root->h_reserved1 ||
|
||||
root->h_info_len != sizeof(struct ext2fs_htree_root_info))
|
||||
return (NULL);
|
||||
|
||||
count_offset = 32;
|
||||
} else
|
||||
return (NULL);
|
||||
|
||||
if (offset)
|
||||
*offset = count_offset;
|
||||
|
||||
return ((struct ext2fs_htree_count *)(((char *)ep) + count_offset));
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
ext2_dx_csum(struct inode *ip, struct ext2fs_direct_2 *ep, int count_offset,
|
||||
int count, struct ext2fs_htree_tail *tp)
|
||||
{
|
||||
struct m_ext2fs *fs;
|
||||
char *buf;
|
||||
int size;
|
||||
uint32_t inum, old_csum, gen, crc;
|
||||
|
||||
fs = ip->i_e2fs;
|
||||
|
||||
buf = (char *)ep;
|
||||
|
||||
size = count_offset + (count * sizeof(struct ext2fs_htree_entry));
|
||||
old_csum = tp->ht_checksum;
|
||||
tp->ht_checksum = 0;
|
||||
|
||||
inum = ip->i_number;
|
||||
gen = ip->i_gen;
|
||||
crc = calculate_crc32c(fs->e2fs_csum_seed, (uint8_t *)&inum, sizeof(inum));
|
||||
crc = calculate_crc32c(crc, (uint8_t *)&gen, sizeof(gen));
|
||||
crc = calculate_crc32c(crc, (uint8_t *)buf, size);
|
||||
crc = calculate_crc32c(crc, (uint8_t *)tp, sizeof(struct ext2fs_htree_tail));
|
||||
tp->ht_checksum = old_csum;
|
||||
|
||||
return (crc);
|
||||
}
|
||||
|
||||
static int
|
||||
ext2_dx_csum_verify(struct inode *ip, struct ext2fs_direct_2 *ep)
|
||||
{
|
||||
uint32_t calculated;
|
||||
struct ext2fs_htree_count *cp;
|
||||
struct ext2fs_htree_tail *tp;
|
||||
int count_offset, limit, count;
|
||||
|
||||
cp = ext2_get_dx_count(ip, ep, &count_offset);
|
||||
if (cp == NULL)
|
||||
return (0);
|
||||
|
||||
limit = cp->h_entries_max;
|
||||
count = cp->h_entries_num;
|
||||
if (count_offset + (limit * sizeof(struct ext2fs_htree_entry)) >
|
||||
ip->i_e2fs->e2fs_bsize - sizeof(struct ext2fs_htree_tail))
|
||||
return (EIO);
|
||||
|
||||
tp = (struct ext2fs_htree_tail *)(((struct ext2fs_htree_entry *)cp) + limit);
|
||||
calculated = ext2_dx_csum(ip, ep, count_offset, count, tp);
|
||||
|
||||
if (tp->ht_checksum != calculated)
|
||||
return (EIO);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
ext2_dir_blk_csum_verify(struct inode *ip, struct buf *bp)
|
||||
{
|
||||
struct m_ext2fs *fs;
|
||||
struct ext2fs_direct_2 *ep;
|
||||
int error = 0;
|
||||
|
||||
fs = ip->i_e2fs;
|
||||
|
||||
if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
|
||||
return (error);
|
||||
|
||||
ep = (struct ext2fs_direct_2 *)bp->b_data;
|
||||
|
||||
if (ext2_get_dirent_tail(ip, ep) != NULL)
|
||||
error = ext2_dirent_csum_verify(ip, ep);
|
||||
else if (ext2_get_dx_count(ip, ep, NULL) != NULL)
|
||||
error = ext2_dx_csum_verify(ip, ep);
|
||||
|
||||
if (error)
|
||||
printf("WARNING: bad directory csum detected, ip=%lu"
|
||||
" - run fsck\n", (unsigned long)ip->i_number);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static void
|
||||
ext2_dirent_csum_set(struct inode *ip, struct ext2fs_direct_2 *ep)
|
||||
{
|
||||
struct ext2fs_direct_tail *tp;
|
||||
|
||||
tp = ext2_get_dirent_tail(ip, ep);
|
||||
if (tp == NULL)
|
||||
return;
|
||||
|
||||
tp->e2dt_checksum =
|
||||
ext2_dirent_csum(ip, ep, (char *)tp - (char *)ep);
|
||||
}
|
||||
|
||||
static void
|
||||
ext2_dx_csum_set(struct inode *ip, struct ext2fs_direct_2 *ep)
|
||||
{
|
||||
struct ext2fs_htree_count *cp;
|
||||
struct ext2fs_htree_tail *tp;
|
||||
int count_offset, limit, count;
|
||||
|
||||
cp = ext2_get_dx_count(ip, ep, &count_offset);
|
||||
if (cp == NULL)
|
||||
return;
|
||||
|
||||
limit = cp->h_entries_max;
|
||||
count = cp->h_entries_num;
|
||||
if (count_offset + (limit * sizeof(struct ext2fs_htree_entry)) >
|
||||
ip->i_e2fs->e2fs_bsize - sizeof(struct ext2fs_htree_tail))
|
||||
return;
|
||||
|
||||
tp = (struct ext2fs_htree_tail *)(((struct ext2fs_htree_entry *)cp) + limit);
|
||||
tp->ht_checksum = ext2_dx_csum(ip, ep, count_offset, count, tp);
|
||||
}
|
||||
|
||||
void
|
||||
ext2_dir_blk_csum_set_mem(struct inode *ip, char *buf, int size)
|
||||
{
|
||||
struct m_ext2fs *fs;
|
||||
struct ext2fs_direct_2 *ep;
|
||||
|
||||
fs = ip->i_e2fs;
|
||||
|
||||
if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
|
||||
return;
|
||||
|
||||
ep = (struct ext2fs_direct_2 *)buf;
|
||||
|
||||
if (ext2_htree_has_idx(ip)) {
|
||||
if (ext2_get_dx_count(ip, ep, NULL) != NULL)
|
||||
ext2_dx_csum_set(ip, ep);
|
||||
} else {
|
||||
if (ext2_get_dirent_tail(ip, ep) != NULL)
|
||||
ext2_dirent_csum_set(ip, ep);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ext2_dir_blk_csum_set(struct inode *ip, struct buf *bp)
|
||||
{
|
||||
|
||||
ext2_dir_blk_csum_set_mem(ip, bp->b_data, bp->b_bufsize);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
ext2_extent_blk_csum(struct inode *ip, struct ext4_extent_header *ehp)
|
||||
{
|
||||
struct m_ext2fs *fs;
|
||||
size_t size;
|
||||
uint32_t inum, gen, crc;
|
||||
|
||||
fs = ip->i_e2fs;
|
||||
|
||||
size = EXT4_EXTENT_TAIL_OFFSET(ehp) +
|
||||
offsetof(struct ext4_extent_tail, et_checksum);
|
||||
|
||||
inum = ip->i_number;
|
||||
gen = ip->i_gen;
|
||||
crc = calculate_crc32c(fs->e2fs_csum_seed, (uint8_t *)&inum, sizeof(inum));
|
||||
crc = calculate_crc32c(crc, (uint8_t *)&gen, sizeof(gen));
|
||||
crc = calculate_crc32c(crc, (uint8_t *)ehp, size);
|
||||
|
||||
return (crc);
|
||||
}
|
||||
|
||||
int
|
||||
ext2_extent_blk_csum_verify(struct inode *ip, void *data)
|
||||
{
|
||||
struct m_ext2fs *fs;
|
||||
struct ext4_extent_header *ehp;
|
||||
struct ext4_extent_tail *etp;
|
||||
uint32_t provided, calculated;
|
||||
|
||||
fs = ip->i_e2fs;
|
||||
|
||||
if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
|
||||
return (0);
|
||||
|
||||
ehp = (struct ext4_extent_header *)data;
|
||||
etp = (struct ext4_extent_tail *)(((char *)ehp) +
|
||||
EXT4_EXTENT_TAIL_OFFSET(ehp));
|
||||
|
||||
provided = etp->et_checksum;
|
||||
calculated = ext2_extent_blk_csum(ip, ehp);
|
||||
|
||||
if (provided != calculated) {
|
||||
printf("WARNING: bad extent csum detected, ip=%lu - run fsck\n",
|
||||
(unsigned long)ip->i_number);
|
||||
return (EIO);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
ext2_extent_blk_csum_set(struct inode *ip, void *data)
|
||||
{
|
||||
struct m_ext2fs *fs;
|
||||
struct ext4_extent_header *ehp;
|
||||
struct ext4_extent_tail *etp;
|
||||
|
||||
fs = ip->i_e2fs;
|
||||
|
||||
if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
|
||||
return;
|
||||
|
||||
ehp = (struct ext4_extent_header *)data;
|
||||
etp = (struct ext4_extent_tail *)(((char *)data) +
|
||||
EXT4_EXTENT_TAIL_OFFSET(ehp));
|
||||
|
||||
etp->et_checksum = ext2_extent_blk_csum(ip,
|
||||
(struct ext4_extent_header *)data);
|
||||
}
|
||||
|
||||
int
|
||||
ext2_gd_i_bitmap_csum_verify(struct m_ext2fs *fs, int cg, struct buf *bp)
|
||||
{
|
||||
uint32_t hi, provided, calculated;
|
||||
|
||||
if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
|
||||
return (0);
|
||||
|
||||
provided = fs->e2fs_gd[cg].ext4bgd_i_bmap_csum;
|
||||
calculated = calculate_crc32c(fs->e2fs_csum_seed, bp->b_data,
|
||||
fs->e2fs->e2fs_ipg / 8);
|
||||
if (fs->e2fs->e3fs_desc_size >= EXT2_BG_INODE_BITMAP_CSUM_HI_END) {
|
||||
hi = fs->e2fs_gd[cg].ext4bgd_i_bmap_csum_hi;
|
||||
provided |= (hi << 16);
|
||||
} else
|
||||
calculated &= 0xFFFF;
|
||||
|
||||
if (provided != calculated) {
|
||||
printf("WARNING: bad inode bitmap csum detected, "
|
||||
"cg=%d - run fsck\n", cg);
|
||||
return (EIO);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
ext2_gd_i_bitmap_csum_set(struct m_ext2fs *fs, int cg, struct buf *bp)
|
||||
{
|
||||
uint32_t csum;
|
||||
|
||||
if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
|
||||
return;
|
||||
|
||||
csum = calculate_crc32c(fs->e2fs_csum_seed, bp->b_data,
|
||||
fs->e2fs->e2fs_ipg / 8);
|
||||
fs->e2fs_gd[cg].ext4bgd_i_bmap_csum = csum & 0xFFFF;
|
||||
if (fs->e2fs->e3fs_desc_size >= EXT2_BG_INODE_BITMAP_CSUM_HI_END)
|
||||
fs->e2fs_gd[cg].ext4bgd_i_bmap_csum_hi = csum >> 16;
|
||||
}
|
||||
|
||||
int
|
||||
ext2_gd_b_bitmap_csum_verify(struct m_ext2fs *fs, int cg, struct buf *bp)
|
||||
{
|
||||
uint32_t hi, provided, calculated, size;
|
||||
|
||||
if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
|
||||
return (0);
|
||||
|
||||
size = fs->e2fs_fpg / 8;
|
||||
provided = fs->e2fs_gd[cg].ext4bgd_b_bmap_csum;
|
||||
calculated = calculate_crc32c(fs->e2fs_csum_seed, bp->b_data, size);
|
||||
if (fs->e2fs->e3fs_desc_size >= EXT2_BG_BLOCK_BITMAP_CSUM_HI_LOCATION) {
|
||||
hi = fs->e2fs_gd[cg].ext4bgd_b_bmap_csum_hi;
|
||||
provided |= (hi << 16);
|
||||
} else
|
||||
calculated &= 0xFFFF;
|
||||
|
||||
if (provided != calculated) {
|
||||
printf("WARNING: bad block bitmap csum detected, "
|
||||
"cg=%d - run fsck\n", cg);
|
||||
return (EIO);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
ext2_gd_b_bitmap_csum_set(struct m_ext2fs *fs, int cg, struct buf *bp)
|
||||
{
|
||||
uint32_t csum, size;
|
||||
|
||||
if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
|
||||
return;
|
||||
|
||||
size = fs->e2fs_fpg / 8;
|
||||
csum = calculate_crc32c(fs->e2fs_csum_seed, bp->b_data, size);
|
||||
fs->e2fs_gd[cg].ext4bgd_b_bmap_csum = csum & 0xFFFF;
|
||||
if (fs->e2fs->e3fs_desc_size >= EXT2_BG_BLOCK_BITMAP_CSUM_HI_LOCATION)
|
||||
fs->e2fs_gd[cg].ext4bgd_b_bmap_csum_hi = csum >> 16;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
ext2_ei_csum(struct inode *ip, struct ext2fs_dinode *ei)
|
||||
{
|
||||
struct m_ext2fs *fs;
|
||||
uint16_t old_lo, old_hi;
|
||||
uint32_t inum, gen, crc;
|
||||
|
||||
fs = ip->i_e2fs;
|
||||
|
||||
old_lo = ei->e2di_chksum_lo;
|
||||
ei->e2di_chksum_lo = 0;
|
||||
if ((EXT2_INODE_SIZE(ip->i_e2fs) > E2FS_REV0_INODE_SIZE &&
|
||||
ei->e2di_extra_isize >= EXT2_INODE_CSUM_HI_EXTRA_END)) {
|
||||
old_hi = ei->e2di_chksum_hi;
|
||||
ei->e2di_chksum_hi = 0;
|
||||
}
|
||||
|
||||
inum = ip->i_number;
|
||||
gen = ip->i_gen;
|
||||
|
||||
crc = calculate_crc32c(fs->e2fs_csum_seed, (uint8_t *)&inum, sizeof(inum));
|
||||
crc = calculate_crc32c(crc, (uint8_t *)&gen, sizeof(gen));
|
||||
crc = calculate_crc32c(crc, (uint8_t *)ei, fs->e2fs->e2fs_inode_size);
|
||||
|
||||
if ((EXT2_INODE_SIZE(fs) > E2FS_REV0_INODE_SIZE &&
|
||||
ei->e2di_extra_isize >= EXT2_INODE_CSUM_HI_EXTRA_END))
|
||||
ei->e2di_chksum_hi = old_hi;
|
||||
|
||||
return (crc);
|
||||
}
|
||||
|
||||
int
|
||||
ext2_ei_csum_verify(struct inode *ip, struct ext2fs_dinode *ei)
|
||||
{
|
||||
struct m_ext2fs *fs;
|
||||
const static struct ext2fs_dinode ei_zero;
|
||||
uint32_t hi, provided, calculated;
|
||||
|
||||
fs = ip->i_e2fs;
|
||||
|
||||
if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
|
||||
return (0);
|
||||
|
||||
/* Check case, when dinode was not initialized */
|
||||
if (!memcmp(ei, &ei_zero, sizeof(struct ext2fs_dinode)))
|
||||
return (0);
|
||||
|
||||
provided = ei->e2di_chksum_lo;
|
||||
calculated = ext2_ei_csum(ip, ei);
|
||||
|
||||
if ((EXT2_INODE_SIZE(fs) > E2FS_REV0_INODE_SIZE &&
|
||||
ei->e2di_extra_isize >= EXT2_INODE_CSUM_HI_EXTRA_END)) {
|
||||
hi = ei->e2di_chksum_hi;
|
||||
provided |= hi << 16;
|
||||
} else
|
||||
calculated &= 0xFFFF;
|
||||
|
||||
if (provided != calculated)
|
||||
return (EIO);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
ext2_ei_csum_set(struct inode *ip, struct ext2fs_dinode *ei)
|
||||
{
|
||||
struct m_ext2fs *fs;
|
||||
uint32_t crc;
|
||||
|
||||
fs = ip->i_e2fs;
|
||||
|
||||
if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
|
||||
return;
|
||||
|
||||
crc = ext2_ei_csum(ip, ei);
|
||||
|
||||
ei->e2di_chksum_lo = crc & 0xFFFF;
|
||||
if ((EXT2_INODE_SIZE(fs) > E2FS_REV0_INODE_SIZE &&
|
||||
ei->e2di_extra_isize >= EXT2_INODE_CSUM_HI_EXTRA_END))
|
||||
ei->e2di_chksum_hi = crc >> 16;
|
||||
}
|
||||
|
||||
static uint16_t
|
||||
ext2_crc16(uint16_t crc, const void *buffer, unsigned int len)
|
||||
{
|
||||
@ -96,11 +663,26 @@ static uint16_t
|
||||
ext2_gd_csum(struct m_ext2fs *fs, uint32_t block_group, struct ext2_gd *gd)
|
||||
{
|
||||
size_t offset;
|
||||
uint16_t crc;
|
||||
uint32_t csum32;
|
||||
uint16_t crc, dummy_csum;
|
||||
|
||||
offset = offsetof(struct ext2_gd, ext4bgd_csum);
|
||||
|
||||
if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM)) {
|
||||
if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) {
|
||||
csum32 = calculate_crc32c(fs->e2fs_csum_seed,
|
||||
(uint8_t *)&block_group, sizeof(block_group));
|
||||
csum32 = calculate_crc32c(csum32, (uint8_t *)gd, offset);
|
||||
dummy_csum = 0;
|
||||
csum32 = calculate_crc32c(csum32, (uint8_t *)&dummy_csum,
|
||||
sizeof(dummy_csum));
|
||||
offset += sizeof(dummy_csum);
|
||||
if (offset < fs->e2fs->e3fs_desc_size)
|
||||
csum32 = calculate_crc32c(csum32, (uint8_t *)gd + offset,
|
||||
fs->e2fs->e3fs_desc_size - offset);
|
||||
|
||||
crc = csum32 & 0xFFFF;
|
||||
return (crc);
|
||||
} else if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM)) {
|
||||
crc = ext2_crc16(~0, fs->e2fs->e2fs_uuid,
|
||||
sizeof(fs->e2fs->e2fs_uuid));
|
||||
crc = ext2_crc16(crc, (uint8_t *)&block_group,
|
||||
@ -130,7 +712,7 @@ ext2_gd_csum_verify(struct m_ext2fs *fs, struct cdev *dev)
|
||||
"WARNING: mount of %s denied due bad gd=%d csum=0x%x, expected=0x%x - run fsck\n",
|
||||
devtoname(dev), i, fs->e2fs_gd[i].ext4bgd_csum,
|
||||
ext2_gd_csum(fs, i, &fs->e2fs_gd[i]));
|
||||
error = EINVAL;
|
||||
error = EIO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -72,6 +72,20 @@ struct ext2fs_direct_2 {
|
||||
* length<=EXT2FS_MAXNAMLEN */
|
||||
};
|
||||
|
||||
struct ext2fs_direct_tail {
|
||||
uint32_t e2dt_reserved_zero1; /* pretend to be unused */
|
||||
uint16_t e2dt_rec_len; /* 12 */
|
||||
uint8_t e2dt_reserved_zero2; /* zero name length */
|
||||
uint8_t e2dt_reserved_ft; /* 0xDE, fake file type */
|
||||
uint32_t e2dt_checksum; /* crc32c(uuid+inum+dirblock) */
|
||||
};
|
||||
|
||||
#define EXT2_FT_DIR_CSUM 0xDE
|
||||
|
||||
#define EXT2_DIRENT_TAIL(data, blocksize) \
|
||||
((struct ext2fs_direct_tail *)(((char *)(data)) + \
|
||||
(blocksize) - sizeof(struct ext2fs_direct_tail)))
|
||||
|
||||
/*
|
||||
* Maximal count of links to a file
|
||||
*/
|
||||
|
@ -165,6 +165,22 @@ ext2_extattr_check(struct ext2fs_extattr_entry *entry, char *end)
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
ext2_extattr_block_check(struct inode *ip, struct buf *bp)
|
||||
{
|
||||
struct ext2fs_extattr_header *header;
|
||||
int error;
|
||||
|
||||
header = (struct ext2fs_extattr_header *)bp->b_data;
|
||||
|
||||
error = ext2_extattr_check(EXT2_IFIRST(header),
|
||||
bp->b_data + bp->b_bufsize);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
return (ext2_extattr_blk_csum_verify(ip, bp));
|
||||
}
|
||||
|
||||
int
|
||||
ext2_extattr_inode_list(struct inode *ip, int attrnamespace,
|
||||
struct uio *uio, size_t *size)
|
||||
@ -267,7 +283,7 @@ ext2_extattr_block_list(struct inode *ip, int attrnamespace,
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
error = ext2_extattr_check(EXT2_FIRST_ENTRY(bp), bp->b_data + bp->b_bufsize);
|
||||
error = ext2_extattr_block_check(ip, bp);
|
||||
if (error) {
|
||||
brelse(bp);
|
||||
return (error);
|
||||
@ -408,7 +424,7 @@ ext2_extattr_block_get(struct inode *ip, int attrnamespace,
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
error = ext2_extattr_check(EXT2_FIRST_ENTRY(bp), bp->b_data + bp->b_bufsize);
|
||||
error = ext2_extattr_block_check(ip, bp);
|
||||
if (error) {
|
||||
brelse(bp);
|
||||
return (error);
|
||||
@ -668,7 +684,7 @@ ext2_extattr_block_delete(struct inode *ip, int attrnamespace, const char *name)
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
error = ext2_extattr_check(EXT2_FIRST_ENTRY(bp), bp->b_data + bp->b_bufsize);
|
||||
error = ext2_extattr_block_check(ip, bp);
|
||||
if (error) {
|
||||
brelse(bp);
|
||||
return (error);
|
||||
@ -1061,8 +1077,7 @@ ext2_extattr_block_set(struct inode *ip, int attrnamespace,
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
error = ext2_extattr_check(EXT2_FIRST_ENTRY(bp),
|
||||
bp->b_data + bp->b_bufsize);
|
||||
error = ext2_extattr_block_check(ip, bp);
|
||||
if (error) {
|
||||
brelse(bp);
|
||||
return (error);
|
||||
@ -1130,6 +1145,7 @@ ext2_extattr_block_set(struct inode *ip, int attrnamespace,
|
||||
}
|
||||
|
||||
ext2_extattr_rehash(header, entry);
|
||||
ext2_extattr_blk_csum_set(ip, bp);
|
||||
|
||||
return (bwrite(bp));
|
||||
}
|
||||
@ -1177,6 +1193,7 @@ ext2_extattr_block_set(struct inode *ip, int attrnamespace,
|
||||
}
|
||||
|
||||
ext2_extattr_rehash(header, entry);
|
||||
ext2_extattr_blk_csum_set(ip, bp);
|
||||
|
||||
return (bwrite(bp));
|
||||
}
|
||||
@ -1207,7 +1224,8 @@ int ext2_extattr_free(struct inode *ip)
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
error = ext2_extattr_check(EXT2_FIRST_ENTRY(bp), bp->b_data + bp->b_bufsize);
|
||||
error = ext2_extattr_check(EXT2_FIRST_ENTRY(bp),
|
||||
bp->b_data + bp->b_bufsize);
|
||||
if (error) {
|
||||
brelse(bp);
|
||||
return (error);
|
||||
|
@ -59,7 +59,9 @@ struct ext2fs_extattr_header {
|
||||
int32_t h_refcount; /* reference count */
|
||||
int32_t h_blocks; /* number of disk blocks used */
|
||||
int32_t h_hash; /* hash value of all attributes */
|
||||
uint32_t h_reserved[4]; /* zero right now */
|
||||
int32_t h_checksum; /* crc32c(uuid+id+xattrblock) */
|
||||
/* id = inum if refcount=1, blknum otherwise */
|
||||
uint32_t h_reserved[3]; /* zero right now */
|
||||
};
|
||||
|
||||
struct ext2fs_extattr_dinode_header {
|
||||
|
@ -425,9 +425,11 @@ ext4_ext_find_extent(struct inode *ip, daddr_t block,
|
||||
bqrelse(bp);
|
||||
|
||||
eh = ext4_ext_block_header(path[ppos].ep_data);
|
||||
error = ext4_ext_check_header(ip, eh);
|
||||
if (error)
|
||||
if (ext4_ext_check_header(ip, eh) ||
|
||||
ext2_extent_blk_csum_verify(ip, path[ppos].ep_data)) {
|
||||
error = EIO;
|
||||
goto error;
|
||||
}
|
||||
|
||||
path[ppos].ep_header = eh;
|
||||
|
||||
@ -622,6 +624,7 @@ ext4_ext_dirty(struct inode *ip, struct ext4_extent_path *path)
|
||||
if (!bp)
|
||||
return (EIO);
|
||||
ext4_ext_fill_path_buf(path, bp);
|
||||
ext2_extent_blk_csum_set(ip, bp->b_data);
|
||||
error = bwrite(bp);
|
||||
} else {
|
||||
ip->i_flag |= IN_CHANGE | IN_UPDATE;
|
||||
@ -791,6 +794,7 @@ ext4_ext_split(struct inode *ip, struct ext4_extent_path *path,
|
||||
neh->eh_ecount = neh->eh_ecount + m;
|
||||
}
|
||||
|
||||
ext2_extent_blk_csum_set(ip, bp->b_data);
|
||||
bwrite(bp);
|
||||
bp = NULL;
|
||||
|
||||
@ -838,6 +842,7 @@ ext4_ext_split(struct inode *ip, struct ext4_extent_path *path,
|
||||
neh->eh_ecount = neh->eh_ecount + m;
|
||||
}
|
||||
|
||||
ext2_extent_blk_csum_set(ip, bp->b_data);
|
||||
bwrite(bp);
|
||||
bp = NULL;
|
||||
|
||||
@ -905,6 +910,7 @@ ext4_ext_grow_indepth(struct inode *ip, struct ext4_extent_path *path,
|
||||
else
|
||||
neh->eh_max = ext4_ext_space_block(ip);
|
||||
|
||||
ext2_extent_blk_csum_set(ip, bp->b_data);
|
||||
error = bwrite(bp);
|
||||
if (error)
|
||||
goto out;
|
||||
|
@ -42,6 +42,13 @@
|
||||
#define EXT4_EXT_CACHE_GAP 1
|
||||
#define EXT4_EXT_CACHE_IN 2
|
||||
|
||||
/*
|
||||
* Ext4 extent tail with csum
|
||||
*/
|
||||
struct ext4_extent_tail {
|
||||
uint32_t et_checksum; /* crc32c(uuid+inum+extent_block) */
|
||||
};
|
||||
|
||||
/*
|
||||
* Ext4 file system extent on disk.
|
||||
*/
|
||||
|
@ -66,7 +66,7 @@ int ext4_bmapext(struct vnode *, int32_t, int64_t *, int *, int *);
|
||||
void ext2_clusteracct(struct m_ext2fs *, char *, int, e4fs_daddr_t, int);
|
||||
void ext2_dirbad(struct inode *ip, doff_t offset, char *how);
|
||||
void ext2_fserr(struct m_ext2fs *, uid_t, char *);
|
||||
void ext2_ei2i(struct ext2fs_dinode *, struct inode *);
|
||||
int ext2_ei2i(struct ext2fs_dinode *, struct inode *);
|
||||
int ext2_getlbns(struct vnode *, daddr_t, struct indir *, int *);
|
||||
int ext2_i2ei(struct inode *, struct ext2fs_dinode *);
|
||||
void ext2_itimes(struct vnode *vp);
|
||||
@ -103,9 +103,25 @@ int ext2_htree_lookup(struct inode *, const char *, int, struct buf **,
|
||||
int ext2_search_dirblock(struct inode *, void *, int *, const char *, int,
|
||||
int *, doff_t *, doff_t *, doff_t *, struct ext2fs_searchslot *);
|
||||
uint32_t e2fs_gd_get_ndirs(struct ext2_gd *gd);
|
||||
uint64_t e2fs_gd_get_i_tables(struct ext2_gd *gd);
|
||||
int ext2_gd_csum_verify(struct m_ext2fs *fs, struct cdev *dev);
|
||||
void ext2_gd_csum_set(struct m_ext2fs *fs);
|
||||
uint64_t e2fs_gd_get_i_tables(struct ext2_gd *);
|
||||
void ext2_sb_csum_set_seed(struct m_ext2fs *);
|
||||
int ext2_sb_csum_verify(struct m_ext2fs *);
|
||||
void ext2_sb_csum_set(struct m_ext2fs *);
|
||||
int ext2_extattr_blk_csum_verify(struct inode *, struct buf *);
|
||||
void ext2_extattr_blk_csum_set(struct inode *, struct buf *);
|
||||
int ext2_dir_blk_csum_verify(struct inode *, struct buf *);
|
||||
void ext2_dir_blk_csum_set(struct inode *, struct buf *);
|
||||
void ext2_dir_blk_csum_set_mem(struct inode *, char *, int);
|
||||
int ext2_extent_blk_csum_verify(struct inode *, void *);
|
||||
void ext2_extent_blk_csum_set(struct inode *, void *);
|
||||
int ext2_gd_i_bitmap_csum_verify(struct m_ext2fs *, int, struct buf *);
|
||||
void ext2_gd_i_bitmap_csum_set(struct m_ext2fs *, int, struct buf *);
|
||||
int ext2_gd_b_bitmap_csum_verify(struct m_ext2fs *, int, struct buf *);
|
||||
void ext2_gd_b_bitmap_csum_set(struct m_ext2fs *, int, struct buf *);
|
||||
int ext2_ei_csum_verify(struct inode *, struct ext2fs_dinode *);
|
||||
void ext2_ei_csum_set(struct inode *, struct ext2fs_dinode *);
|
||||
int ext2_gd_csum_verify(struct m_ext2fs *, struct cdev *);
|
||||
void ext2_gd_csum_set(struct m_ext2fs *);
|
||||
|
||||
|
||||
/* Flags to low-level allocation routines.
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <fs/ext2fs/ext2fs.h>
|
||||
#include <fs/ext2fs/fs.h>
|
||||
#include <fs/ext2fs/inode.h>
|
||||
#include <fs/ext2fs/ext2fs.h>
|
||||
@ -86,9 +87,11 @@ ext2_print_inode(struct inode *in)
|
||||
/*
|
||||
* raw ext2 inode to inode
|
||||
*/
|
||||
void
|
||||
int
|
||||
ext2_ei2i(struct ext2fs_dinode *ei, struct inode *ip)
|
||||
{
|
||||
const static struct ext2fs_dinode ei_zero;
|
||||
|
||||
ip->i_nlink = ei->e2di_nlink;
|
||||
/*
|
||||
* Godmar thinks - if the link count is zero, then the inode is
|
||||
@ -131,6 +134,11 @@ ext2_ei2i(struct ext2fs_dinode *ei, struct inode *ip)
|
||||
ip->i_gid |= (uint32_t)ei->e2di_gid_high << 16;
|
||||
|
||||
memcpy(ip->i_data, ei->e2di_blocks, sizeof(ei->e2di_blocks));
|
||||
|
||||
if (memcmp(ei, &ei_zero, sizeof(struct ext2fs_dinode)))
|
||||
return (ext2_ei_csum_verify(ip, ei));
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -191,5 +199,8 @@ ext2_i2ei(struct inode *ip, struct ext2fs_dinode *ei)
|
||||
|
||||
memcpy(ei->e2di_blocks, ip->i_data, sizeof(ei->e2di_blocks));
|
||||
|
||||
/* Set inode csum */
|
||||
ext2_ei_csum_set(ip, ei);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
@ -63,6 +63,7 @@
|
||||
#include <fs/ext2fs/ext2_dinode.h>
|
||||
#include <fs/ext2fs/ext2_dir.h>
|
||||
#include <fs/ext2fs/ext2_extern.h>
|
||||
#include <fs/ext2fs/fs.h>
|
||||
|
||||
#ifdef INVARIANTS
|
||||
static int dirchk = 1;
|
||||
@ -866,8 +867,7 @@ ext2_direnter(struct inode *ip, struct vnode *dvp, struct componentname *cnp)
|
||||
{
|
||||
struct inode *dp;
|
||||
struct ext2fs_direct_2 newdir;
|
||||
struct iovec aiov;
|
||||
struct uio auio;
|
||||
struct buf *bp;
|
||||
int error, newentrysize;
|
||||
int DIRBLKSIZ = ip->i_e2fs->e2fs_bsize;
|
||||
|
||||
@ -917,26 +917,25 @@ ext2_direnter(struct inode *ip, struct vnode *dvp, struct componentname *cnp)
|
||||
*/
|
||||
if (dp->i_offset & (DIRBLKSIZ - 1))
|
||||
panic("ext2_direnter: newblk");
|
||||
auio.uio_offset = dp->i_offset;
|
||||
|
||||
newdir.e2d_reclen = DIRBLKSIZ;
|
||||
auio.uio_resid = newentrysize;
|
||||
aiov.iov_len = newentrysize;
|
||||
aiov.iov_base = (caddr_t)&newdir;
|
||||
auio.uio_iov = &aiov;
|
||||
auio.uio_iovcnt = 1;
|
||||
auio.uio_rw = UIO_WRITE;
|
||||
auio.uio_segflg = UIO_SYSSPACE;
|
||||
auio.uio_td = (struct thread *)0;
|
||||
error = VOP_WRITE(dvp, &auio, IO_SYNC, cnp->cn_cred);
|
||||
if (DIRBLKSIZ >
|
||||
VFSTOEXT2(dvp->v_mount)->um_mountp->mnt_stat.f_bsize)
|
||||
/* XXX should grow with balloc() */
|
||||
panic("ext2_direnter: frag size");
|
||||
else if (!error) {
|
||||
dp->i_size = roundup2(dp->i_size, DIRBLKSIZ);
|
||||
dp->i_flag |= IN_CHANGE;
|
||||
}
|
||||
return (error);
|
||||
|
||||
bp = getblk(ip->i_devvp, lblkno(dp->i_e2fs, dp->i_offset),
|
||||
DIRBLKSIZ, 0, 0, 0);
|
||||
if (!bp)
|
||||
return (EIO);
|
||||
|
||||
memcpy(bp->b_data, &newdir, sizeof(struct ext2fs_direct_2));
|
||||
|
||||
ext2_dir_blk_csum_set(dp, bp);
|
||||
error = bwrite(bp);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
dp->i_size = roundup2(dp->i_size, DIRBLKSIZ);
|
||||
dp->i_flag |= IN_CHANGE;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
error = ext2_add_entry(dvp, &newdir);
|
||||
@ -1028,6 +1027,7 @@ ext2_add_entry(struct vnode *dvp, struct ext2fs_direct_2 *entry)
|
||||
ep = (struct ext2fs_direct_2 *)((char *)ep + dsize);
|
||||
}
|
||||
bcopy((caddr_t)entry, (caddr_t)ep, (u_int)newentrysize);
|
||||
ext2_dir_blk_csum_set(dp, bp);
|
||||
if (DOINGASYNC(dvp)) {
|
||||
bdwrite(bp);
|
||||
error = 0;
|
||||
@ -1085,6 +1085,7 @@ ext2_dirremove(struct vnode *dvp, struct componentname *cnp)
|
||||
else
|
||||
rep = (struct ext2fs_direct_2 *)((char *)ep + ep->e2d_reclen);
|
||||
ep->e2d_reclen += rep->e2d_reclen;
|
||||
ext2_dir_blk_csum_set(dp, bp);
|
||||
if (DOINGASYNC(dvp) && dp->i_count != 0)
|
||||
bdwrite(bp);
|
||||
else
|
||||
@ -1115,6 +1116,7 @@ ext2_dirrewrite(struct inode *dp, struct inode *ip, struct componentname *cnp)
|
||||
ep->e2d_type = DTTOFT(IFTODT(ip->i_mode));
|
||||
else
|
||||
ep->e2d_type = EXT2_FT_UNKNOWN;
|
||||
ext2_dir_blk_csum_set(dp, bp);
|
||||
error = bwrite(bp);
|
||||
dp->i_flag |= IN_CHANGE | IN_UPDATE;
|
||||
return (error);
|
||||
|
@ -79,6 +79,11 @@ ext2_blkatoff(struct vnode *vp, off_t offset, char **res, struct buf **bpp)
|
||||
brelse(bp);
|
||||
return (error);
|
||||
}
|
||||
error = ext2_dir_blk_csum_verify(ip, bp);
|
||||
if (error != 0) {
|
||||
brelse(bp);
|
||||
return (error);
|
||||
}
|
||||
if (res)
|
||||
*res = (char *)bp->b_data + blkoff(fs, offset);
|
||||
|
||||
|
@ -372,6 +372,12 @@ compute_sb_data(struct vnode *devvp, struct ext2fs *es,
|
||||
printf("ext2fs: no space for extra inode timestamps\n");
|
||||
return (EINVAL);
|
||||
}
|
||||
/* Check checksum features */
|
||||
if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM) &&
|
||||
EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) {
|
||||
printf("ext2fs: incorrect checksum features combination\n");
|
||||
return (EINVAL);
|
||||
}
|
||||
/* Check for group descriptor size */
|
||||
if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT) &&
|
||||
(es->e3fs_desc_size != sizeof(struct ext2_gd))) {
|
||||
@ -430,8 +436,11 @@ compute_sb_data(struct vnode *devvp, struct ext2fs *es,
|
||||
brelse(bp);
|
||||
bp = NULL;
|
||||
}
|
||||
/* Verify cg csum */
|
||||
if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM)) {
|
||||
/* Precompute checksum seed for all metadata */
|
||||
ext2_sb_csum_set_seed(fs);
|
||||
/* Verfy cg csum */
|
||||
if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM) ||
|
||||
EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) {
|
||||
error = ext2_gd_csum_verify(fs, devvp->v_rdev);
|
||||
if (error)
|
||||
return (error);
|
||||
@ -439,7 +448,7 @@ compute_sb_data(struct vnode *devvp, struct ext2fs *es,
|
||||
/* Initialization for the ext2 Orlov allocator variant. */
|
||||
fs->e2fs_total_dir = 0;
|
||||
for (i = 0; i < fs->e2fs_gcount; i++)
|
||||
fs->e2fs_total_dir += fs->e2fs_gd[i].ext2bgd_ndirs;
|
||||
fs->e2fs_total_dir += e2fs_gd_get_ndirs(&fs->e2fs_gd[i]);
|
||||
|
||||
if (es->e2fs_rev == E2FS_REV0 ||
|
||||
!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_LARGEFILE))
|
||||
@ -459,8 +468,10 @@ compute_sb_data(struct vnode *devvp, struct ext2fs *es,
|
||||
es->e4fs_flags |= E2FS_SIGNED_HASH;
|
||||
#endif
|
||||
}
|
||||
if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
|
||||
error = ext2_sb_csum_verify(fs);
|
||||
|
||||
return (0);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -993,8 +1004,16 @@ ext2_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp)
|
||||
return (error);
|
||||
}
|
||||
/* convert ext2 inode to dinode */
|
||||
ext2_ei2i((struct ext2fs_dinode *)((char *)bp->b_data + EXT2_INODE_SIZE(fs) *
|
||||
ino_to_fsbo(fs, ino)), ip);
|
||||
error = ext2_ei2i((struct ext2fs_dinode *)((char *)bp->b_data +
|
||||
EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ino)), ip);
|
||||
if (error) {
|
||||
printf("ext2fs: Bad inode %lu csum - run fsck\n",
|
||||
(unsigned long)ino);
|
||||
brelse(bp);
|
||||
vput(vp);
|
||||
*vpp = NULL;
|
||||
return (error);
|
||||
}
|
||||
ip->i_block_group = ino_to_cg(fs, ino);
|
||||
ip->i_next_alloc_block = 0;
|
||||
ip->i_next_alloc_goal = 0;
|
||||
@ -1099,6 +1118,9 @@ ext2_sbupdate(struct ext2mount *mp, int waitfor)
|
||||
es->e4fs_fbcount_hi = fs->e2fs_fbcount >> 32;
|
||||
}
|
||||
|
||||
if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
|
||||
ext2_sb_csum_set(fs);
|
||||
|
||||
bp = getblk(mp->um_devvp, SBLOCK, SBSIZE, 0, 0, 0);
|
||||
bcopy((caddr_t)es, bp->b_data, (u_int)sizeof(struct ext2fs));
|
||||
if (waitfor == MNT_WAIT)
|
||||
@ -1123,7 +1145,8 @@ ext2_cgupdate(struct ext2mount *mp, int waitfor)
|
||||
allerror = ext2_sbupdate(mp, waitfor);
|
||||
|
||||
/* Update gd csums */
|
||||
if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM))
|
||||
if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM) ||
|
||||
EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
|
||||
ext2_gd_csum_set(fs);
|
||||
|
||||
for (i = 0; i < fs->e2fs_gdbcount; i++) {
|
||||
|
@ -784,7 +784,7 @@ ext2_rename(struct vop_rename_args *ap)
|
||||
struct componentname *tcnp = ap->a_tcnp;
|
||||
struct componentname *fcnp = ap->a_fcnp;
|
||||
struct inode *ip, *xp, *dp;
|
||||
struct dirtemplate dirbuf;
|
||||
struct dirtemplate *dirbuf;
|
||||
int doingdirectory = 0, oldparent = 0, newparent = 0;
|
||||
int error = 0;
|
||||
u_char namlen;
|
||||
@ -1071,23 +1071,31 @@ ext2_rename(struct vop_rename_args *ap)
|
||||
if (doingdirectory && newparent) {
|
||||
ext2_dec_nlink(dp);
|
||||
dp->i_flag |= IN_CHANGE;
|
||||
error = vn_rdwr(UIO_READ, fvp, (caddr_t)&dirbuf,
|
||||
sizeof(struct dirtemplate), (off_t)0,
|
||||
dirbuf = malloc(dp->i_e2fs->e2fs_bsize, M_TEMP, M_WAITOK | M_ZERO);
|
||||
if (!dirbuf) {
|
||||
error = ENOMEM;
|
||||
goto bad;
|
||||
}
|
||||
error = vn_rdwr(UIO_READ, fvp, (caddr_t)dirbuf,
|
||||
ip->i_e2fs->e2fs_bsize, (off_t)0,
|
||||
UIO_SYSSPACE, IO_NODELOCKED | IO_NOMACCHECK,
|
||||
tcnp->cn_cred, NOCRED, NULL, NULL);
|
||||
if (error == 0) {
|
||||
/* Like ufs little-endian: */
|
||||
namlen = dirbuf.dotdot_type;
|
||||
namlen = dirbuf->dotdot_type;
|
||||
if (namlen != 2 ||
|
||||
dirbuf.dotdot_name[0] != '.' ||
|
||||
dirbuf.dotdot_name[1] != '.') {
|
||||
dirbuf->dotdot_name[0] != '.' ||
|
||||
dirbuf->dotdot_name[1] != '.') {
|
||||
ext2_dirbad(xp, (doff_t)12,
|
||||
"rename: mangled dir");
|
||||
} else {
|
||||
dirbuf.dotdot_ino = newparent;
|
||||
dirbuf->dotdot_ino = newparent;
|
||||
ext2_dir_blk_csum_set_mem(ip,
|
||||
(char *)dirbuf,
|
||||
ip->i_e2fs->e2fs_bsize);
|
||||
(void)vn_rdwr(UIO_WRITE, fvp,
|
||||
(caddr_t)&dirbuf,
|
||||
sizeof(struct dirtemplate),
|
||||
(caddr_t)dirbuf,
|
||||
ip->i_e2fs->e2fs_bsize,
|
||||
(off_t)0, UIO_SYSSPACE,
|
||||
IO_NODELOCKED | IO_SYNC |
|
||||
IO_NOMACCHECK, tcnp->cn_cred,
|
||||
@ -1095,6 +1103,7 @@ ext2_rename(struct vop_rename_args *ap)
|
||||
cache_purge(fdvp);
|
||||
}
|
||||
}
|
||||
free(dirbuf, M_TEMP);
|
||||
}
|
||||
error = ext2_dirremove(fdvp, fcnp);
|
||||
if (!error) {
|
||||
@ -1274,18 +1283,28 @@ ext2_do_posix1e_acl_inheritance_file(struct vnode *dvp, struct vnode *tvp,
|
||||
|
||||
#endif /* UFS_ACL */
|
||||
|
||||
static void
|
||||
ext2_init_dirent_tail(struct ext2fs_direct_tail *tp)
|
||||
{
|
||||
memset(tp, 0, sizeof(struct ext2fs_direct_tail));
|
||||
tp->e2dt_rec_len = sizeof(struct ext2fs_direct_tail);
|
||||
tp->e2dt_reserved_ft = EXT2_FT_DIR_CSUM;
|
||||
}
|
||||
|
||||
/*
|
||||
* Mkdir system call
|
||||
*/
|
||||
static int
|
||||
ext2_mkdir(struct vop_mkdir_args *ap)
|
||||
{
|
||||
struct m_ext2fs *fs;
|
||||
struct vnode *dvp = ap->a_dvp;
|
||||
struct vattr *vap = ap->a_vap;
|
||||
struct componentname *cnp = ap->a_cnp;
|
||||
struct inode *ip, *dp;
|
||||
struct vnode *tvp;
|
||||
struct dirtemplate dirtemplate, *dtp;
|
||||
char *buf = NULL;
|
||||
int error, dmode;
|
||||
|
||||
#ifdef INVARIANTS
|
||||
@ -1309,6 +1328,7 @@ ext2_mkdir(struct vop_mkdir_args *ap)
|
||||
if (error)
|
||||
goto out;
|
||||
ip = VTOI(tvp);
|
||||
fs = ip->i_e2fs;
|
||||
ip->i_gid = dp->i_gid;
|
||||
#ifdef SUIDDIR
|
||||
{
|
||||
@ -1367,8 +1387,21 @@ ext2_mkdir(struct vop_mkdir_args *ap)
|
||||
#undef DIRBLKSIZ
|
||||
#define DIRBLKSIZ VTOI(dvp)->i_e2fs->e2fs_bsize
|
||||
dirtemplate.dotdot_reclen = DIRBLKSIZ - 12;
|
||||
error = vn_rdwr(UIO_WRITE, tvp, (caddr_t)&dirtemplate,
|
||||
sizeof(dirtemplate), (off_t)0, UIO_SYSSPACE,
|
||||
buf = malloc(DIRBLKSIZ, M_TEMP, M_WAITOK | M_ZERO);
|
||||
if (!buf) {
|
||||
error = ENOMEM;
|
||||
ext2_dec_nlink(dp);
|
||||
dp->i_flag |= IN_CHANGE;
|
||||
goto bad;
|
||||
}
|
||||
if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) {
|
||||
dirtemplate.dotdot_reclen -= sizeof(struct ext2fs_direct_tail);
|
||||
ext2_init_dirent_tail(EXT2_DIRENT_TAIL(buf, DIRBLKSIZ));
|
||||
}
|
||||
memcpy(buf, &dirtemplate, sizeof(dirtemplate));
|
||||
ext2_dir_blk_csum_set_mem(ip, buf, DIRBLKSIZ);
|
||||
error = vn_rdwr(UIO_WRITE, tvp, (caddr_t)buf,
|
||||
DIRBLKSIZ, (off_t)0, UIO_SYSSPACE,
|
||||
IO_NODELOCKED | IO_SYNC | IO_NOMACCHECK, cnp->cn_cred, NOCRED,
|
||||
NULL, NULL);
|
||||
if (error) {
|
||||
@ -1412,6 +1445,7 @@ ext2_mkdir(struct vop_mkdir_args *ap)
|
||||
} else
|
||||
*ap->a_vpp = tvp;
|
||||
out:
|
||||
free(buf, M_TEMP);
|
||||
return (error);
|
||||
#undef DIRBLKSIZ
|
||||
#define DIRBLKSIZ DEV_BSIZE
|
||||
|
@ -182,6 +182,7 @@ struct m_ext2fs {
|
||||
int32_t *e2fs_maxcluster; /* max cluster in each cyl group */
|
||||
struct csum *e2fs_clustersum; /* cluster summary in each cyl group */
|
||||
int32_t e2fs_uhash; /* 3 if hash should be signed, 0 if not */
|
||||
uint32_t e2fs_csum_seed; /* sb checksum seed */
|
||||
};
|
||||
|
||||
/* cluster summary information */
|
||||
@ -204,6 +205,11 @@ struct csum {
|
||||
|
||||
#define E2FS_REV0_INODE_SIZE 128
|
||||
|
||||
/*
|
||||
* Metadata checksum algorithm codes
|
||||
*/
|
||||
#define EXT4_CRC32C_CHKSUM 1
|
||||
|
||||
/*
|
||||
* compatible/incompatible features
|
||||
*/
|
||||
@ -323,13 +329,15 @@ static const struct ext2_feature incompat[] = {
|
||||
#define EXT2F_ROCOMPAT_SUPP (EXT2F_ROCOMPAT_SPARSESUPER | \
|
||||
EXT2F_ROCOMPAT_LARGEFILE | \
|
||||
EXT2F_ROCOMPAT_GDT_CSUM | \
|
||||
EXT2F_ROCOMPAT_METADATA_CKSUM | \
|
||||
EXT2F_ROCOMPAT_DIR_NLINK | \
|
||||
EXT2F_ROCOMPAT_HUGE_FILE | \
|
||||
EXT2F_ROCOMPAT_EXTRA_ISIZE)
|
||||
#define EXT2F_INCOMPAT_SUPP (EXT2F_INCOMPAT_FTYPE | \
|
||||
EXT2F_INCOMPAT_64BIT)
|
||||
#define EXT4F_RO_INCOMPAT_SUPP (EXT2F_INCOMPAT_EXTENTS | \
|
||||
EXT2F_INCOMPAT_RECOVER | \
|
||||
EXT2F_INCOMPAT_EXTENTS | \
|
||||
EXT2F_INCOMPAT_64BIT | \
|
||||
EXT2F_INCOMPAT_CSUM_SEED)
|
||||
#define EXT4F_RO_INCOMPAT_SUPP (EXT2F_INCOMPAT_RECOVER | \
|
||||
EXT2F_INCOMPAT_FLEX_BG | \
|
||||
EXT2F_INCOMPAT_META_BG )
|
||||
|
||||
|
@ -60,6 +60,14 @@ struct ext2fs_htree_entry {
|
||||
uint32_t h_blk;
|
||||
};
|
||||
|
||||
/*
|
||||
* This goes at the end of each htree block.
|
||||
*/
|
||||
struct ext2fs_htree_tail {
|
||||
uint32_t ht_reserved;
|
||||
uint32_t ht_checksum; /* crc32c(uuid+inum+dirblock) */
|
||||
};
|
||||
|
||||
struct ext2fs_htree_root_info {
|
||||
uint32_t h_reserved1;
|
||||
uint8_t h_hash_version;
|
||||
|
Loading…
Reference in New Issue
Block a user