Changeset View
Changeset View
Standalone View
Standalone View
head/sys/fs/ext2fs/ext2_vfsops.c
Show First 20 Lines • Show All 92 Lines • ▼ Show 20 Lines | static struct vfsops ext2fs_vfsops = { | ||||
.vfs_unmount = ext2_unmount, | .vfs_unmount = ext2_unmount, | ||||
.vfs_vget = ext2_vget, | .vfs_vget = ext2_vget, | ||||
}; | }; | ||||
VFS_SET(ext2fs_vfsops, ext2fs, 0); | VFS_SET(ext2fs_vfsops, ext2fs, 0); | ||||
static int ext2_check_sb_compat(struct ext2fs *es, struct cdev *dev, | static int ext2_check_sb_compat(struct ext2fs *es, struct cdev *dev, | ||||
int ronly); | int ronly); | ||||
static int compute_sb_data(struct vnode * devvp, | static int ext2_compute_sb_data(struct vnode * devvp, | ||||
struct ext2fs * es, struct m_ext2fs * fs); | struct ext2fs * es, struct m_ext2fs * fs); | ||||
static const char *ext2_opts[] = { "acls", "async", "noatime", "noclusterr", | static const char *ext2_opts[] = { "acls", "async", "noatime", "noclusterr", | ||||
"noclusterw", "noexec", "export", "force", "from", "multilabel", | "noclusterw", "noexec", "export", "force", "from", "multilabel", | ||||
"suiddir", "nosymfollow", "sync", "union", NULL }; | "suiddir", "nosymfollow", "sync", "union", NULL }; | ||||
/* | /* | ||||
* VFS Operations. | * VFS Operations. | ||||
▲ Show 20 Lines • Show All 206 Lines • ▼ Show 20 Lines | if (!ronly && mask) { | ||||
printf("\n"); | printf("\n"); | ||||
return (1); | return (1); | ||||
} | } | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
static e4fs_daddr_t | static e4fs_daddr_t | ||||
cg_location(struct m_ext2fs *fs, int number) | ext2_cg_location(struct m_ext2fs *fs, int number) | ||||
{ | { | ||||
int cg, descpb, logical_sb, has_super = 0; | int cg, descpb, logical_sb, has_super = 0; | ||||
/* | /* | ||||
* Adjust logical superblock block number. | * Adjust logical superblock block number. | ||||
* Godmar thinks: if the blocksize is greater than 1024, then | * Godmar thinks: if the blocksize is greater than 1024, then | ||||
* the superblock is logically part of block zero. | * the superblock is logically part of block zero. | ||||
*/ | */ | ||||
Show All 12 Lines | ext2_cg_location(struct m_ext2fs *fs, int number) | ||||
if (ext2_cg_has_sb(fs, cg)) | if (ext2_cg_has_sb(fs, cg)) | ||||
has_super = 1; | has_super = 1; | ||||
return (has_super + cg * (e4fs_daddr_t)EXT2_BLOCKS_PER_GROUP(fs) + | return (has_super + cg * (e4fs_daddr_t)EXT2_BLOCKS_PER_GROUP(fs) + | ||||
fs->e2fs->e2fs_first_dblock); | fs->e2fs->e2fs_first_dblock); | ||||
} | } | ||||
static int | |||||
ext2_cg_validate(struct m_ext2fs *fs) | |||||
{ | |||||
uint64_t b_bitmap; | |||||
uint64_t i_bitmap; | |||||
uint64_t i_tables; | |||||
uint64_t first_block, last_block, last_cg_block; | |||||
struct ext2_gd *gd; | |||||
unsigned int i, cg_count; | |||||
first_block = fs->e2fs->e2fs_first_dblock; | |||||
last_cg_block = ext2_cg_number_gdb(fs, 0); | |||||
cg_count = fs->e2fs_gcount; | |||||
for (i = 0; i < fs->e2fs_gcount; i++) { | |||||
gd = &fs->e2fs_gd[i]; | |||||
if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_FLEX_BG) || | |||||
i == fs->e2fs_gcount - 1) { | |||||
last_block = fs->e2fs_bcount - 1; | |||||
} else { | |||||
last_block = first_block + | |||||
(EXT2_BLOCKS_PER_GROUP(fs) - 1); | |||||
} | |||||
if ((cg_count == fs->e2fs_gcount) && | |||||
!(gd->ext4bgd_flags & EXT2_BG_INODE_ZEROED)) | |||||
cg_count = i; | |||||
b_bitmap = e2fs_gd_get_b_bitmap(gd); | |||||
if (b_bitmap == 0) { | |||||
printf("ext2fs: cg %u: block bitmap is zero\n", i); | |||||
return (EINVAL); | |||||
} | |||||
if (b_bitmap <= last_cg_block) { | |||||
printf("ext2fs: cg %u: block bitmap overlaps gds\n", i); | |||||
return (EINVAL); | |||||
} | |||||
if (b_bitmap < first_block || b_bitmap > last_block) { | |||||
printf("ext2fs: cg %u: block bitmap not in group, blk=%ju\n", | |||||
i, b_bitmap); | |||||
return (EINVAL); | |||||
} | |||||
i_bitmap = e2fs_gd_get_i_bitmap(gd); | |||||
if (i_bitmap == 0) { | |||||
printf("ext2fs: cg %u: inode bitmap is zero\n", i); | |||||
return (EINVAL); | |||||
} | |||||
if (i_bitmap <= last_cg_block) { | |||||
printf("ext2fs: cg %u: inode bitmap overlaps gds\n", i); | |||||
return (EINVAL); | |||||
} | |||||
if (i_bitmap < first_block || i_bitmap > last_block) { | |||||
printf("ext2fs: cg %u: inode bitmap not in group blk=%ju\n", | |||||
i, i_bitmap); | |||||
return (EINVAL); | |||||
} | |||||
i_tables = e2fs_gd_get_i_tables(gd); | |||||
if (i_tables == 0) { | |||||
printf("ext2fs: cg %u: inode table is zero\n", i); | |||||
return (EINVAL); | |||||
} | |||||
if (i_tables <= last_cg_block) { | |||||
printf("ext2fs: cg %u: inode talbes overlaps gds\n", i); | |||||
return (EINVAL); | |||||
} | |||||
if (i_tables < first_block || | |||||
i_tables + fs->e2fs_itpg - 1 > last_block) { | |||||
printf("ext2fs: cg %u: inode tables not in group blk=%ju\n", | |||||
i, i_tables); | |||||
return (EINVAL); | |||||
} | |||||
if (!EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_FLEX_BG)) | |||||
first_block += EXT2_BLOCKS_PER_GROUP(fs); | |||||
} | |||||
return (0); | |||||
} | |||||
/* | /* | ||||
* This computes the fields of the m_ext2fs structure from the | * This computes the fields of the m_ext2fs structure from the | ||||
* data in the ext2fs structure read in. | * data in the ext2fs structure read in. | ||||
*/ | */ | ||||
static int | static int | ||||
compute_sb_data(struct vnode *devvp, struct ext2fs *es, | ext2_compute_sb_data(struct vnode *devvp, struct ext2fs *es, | ||||
struct m_ext2fs *fs) | struct m_ext2fs *fs) | ||||
{ | { | ||||
int g_count = 0, error; | |||||
int i, j; | |||||
struct buf *bp; | struct buf *bp; | ||||
uint32_t e2fs_descpb, e2fs_gdbcount_alloc; | uint32_t e2fs_descpb, e2fs_gdbcount_alloc; | ||||
int i, j; | |||||
int g_count = 0; | |||||
int error; | |||||
fs->e2fs_bcount = es->e2fs_bcount; | /* Check checksum features */ | ||||
fs->e2fs_rbcount = es->e2fs_rbcount; | if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM) && | ||||
fs->e2fs_fbcount = es->e2fs_fbcount; | EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) { | ||||
if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT)) { | printf("ext2fs: incorrect checksum features combination\n"); | ||||
fs->e2fs_bcount |= (uint64_t)(es->e4fs_bcount_hi) << 32; | return (EINVAL); | ||||
fs->e2fs_rbcount |= (uint64_t)(es->e4fs_rbcount_hi) << 32; | |||||
fs->e2fs_fbcount |= (uint64_t)(es->e4fs_fbcount_hi) << 32; | |||||
} | } | ||||
/* Precompute checksum seed for all metadata */ | |||||
ext2_sb_csum_set_seed(fs); | |||||
/* Verify sb csum if possible */ | |||||
if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) { | |||||
error = ext2_sb_csum_verify(fs); | |||||
if (error) { | |||||
return (error); | |||||
} | |||||
} | |||||
/* Check for block size = 1K|2K|4K */ | |||||
if (es->e2fs_log_bsize > 2) { | |||||
printf("ext2fs: bad block size: %d\n", es->e2fs_log_bsize); | |||||
return (EINVAL); | |||||
} | |||||
fs->e2fs_bshift = EXT2_MIN_BLOCK_LOG_SIZE + es->e2fs_log_bsize; | fs->e2fs_bshift = EXT2_MIN_BLOCK_LOG_SIZE + es->e2fs_log_bsize; | ||||
fs->e2fs_bsize = 1U << fs->e2fs_bshift; | fs->e2fs_bsize = 1U << fs->e2fs_bshift; | ||||
fs->e2fs_fsbtodb = es->e2fs_log_bsize + 1; | fs->e2fs_fsbtodb = es->e2fs_log_bsize + 1; | ||||
fs->e2fs_qbmask = fs->e2fs_bsize - 1; | fs->e2fs_qbmask = fs->e2fs_bsize - 1; | ||||
/* Check for fragment size */ | |||||
if (es->e2fs_log_fsize > | |||||
(EXT2_MAX_FRAG_LOG_SIZE - EXT2_MIN_BLOCK_LOG_SIZE)) { | |||||
printf("ext2fs: invalid log cluster size: %u\n", | |||||
es->e2fs_log_fsize); | |||||
return (EINVAL); | |||||
} | |||||
fs->e2fs_fsize = EXT2_MIN_FRAG_SIZE << es->e2fs_log_fsize; | fs->e2fs_fsize = EXT2_MIN_FRAG_SIZE << es->e2fs_log_fsize; | ||||
if (fs->e2fs_fsize) | if (fs->e2fs_fsize != fs->e2fs_bsize) { | ||||
printf("ext2fs: fragment size (%u) != block size %u\n", | |||||
fs->e2fs_fsize, fs->e2fs_bsize); | |||||
return (EINVAL); | |||||
} | |||||
fs->e2fs_fpb = fs->e2fs_bsize / fs->e2fs_fsize; | fs->e2fs_fpb = fs->e2fs_bsize / fs->e2fs_fsize; | ||||
fs->e2fs_bpg = es->e2fs_bpg; | |||||
fs->e2fs_fpg = es->e2fs_fpg; | /* Check reserved gdt blocks for future filesystem expansion */ | ||||
fs->e2fs_ipg = es->e2fs_ipg; | if (es->e2fs_reserved_ngdb > (fs->e2fs_bsize / 4)) { | ||||
printf("ext2fs: number of reserved GDT blocks too large: %u\n", | |||||
es->e2fs_reserved_ngdb); | |||||
return (EINVAL); | |||||
} | |||||
if (es->e2fs_rev == E2FS_REV0) { | if (es->e2fs_rev == E2FS_REV0) { | ||||
fs->e2fs_isize = E2FS_REV0_INODE_SIZE; | fs->e2fs_isize = E2FS_REV0_INODE_SIZE; | ||||
} else { | } else { | ||||
fs->e2fs_isize = es->e2fs_inode_size; | fs->e2fs_isize = es->e2fs_inode_size; | ||||
/* | /* | ||||
* Check first ino. | |||||
*/ | |||||
if (es->e2fs_first_ino < EXT2_FIRSTINO) { | |||||
printf("ext2fs: invalid first ino: %u\n", | |||||
es->e2fs_first_ino); | |||||
return (EINVAL); | |||||
} | |||||
/* | |||||
* Simple sanity check for superblock inode size value. | * Simple sanity check for superblock inode size value. | ||||
*/ | */ | ||||
if (EXT2_INODE_SIZE(fs) < E2FS_REV0_INODE_SIZE || | if (EXT2_INODE_SIZE(fs) < E2FS_REV0_INODE_SIZE || | ||||
EXT2_INODE_SIZE(fs) > fs->e2fs_bsize || | EXT2_INODE_SIZE(fs) > fs->e2fs_bsize || | ||||
(fs->e2fs_isize & (fs->e2fs_isize - 1)) != 0) { | (fs->e2fs_isize & (fs->e2fs_isize - 1)) != 0) { | ||||
printf("ext2fs: invalid inode size %d\n", | printf("ext2fs: invalid inode size %u\n", | ||||
fs->e2fs_isize); | fs->e2fs_isize); | ||||
return (EIO); | |||||
} | |||||
} | |||||
/* Check for extra isize in big inodes. */ | |||||
if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_EXTRA_ISIZE) && | |||||
EXT2_INODE_SIZE(fs) < sizeof(struct ext2fs_dinode)) { | |||||
printf("ext2fs: no space for extra inode timestamps\n"); | |||||
return (EINVAL); | 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 */ | |||||
/* Check group descriptors */ | |||||
if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT) && | if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT) && | ||||
(es->e3fs_desc_size != sizeof(struct ext2_gd))) { | es->e3fs_desc_size != E2FS_64BIT_GD_SIZE) { | ||||
printf("ext2fs: group descriptor size unsupported %d\n", | printf("ext2fs: unsupported 64bit descriptor size %u\n", | ||||
es->e3fs_desc_size); | es->e3fs_desc_size); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
/* Check for block size = 1K|2K|4K */ | |||||
if (es->e2fs_log_bsize > 2) { | fs->e2fs_bpg = es->e2fs_bpg; | ||||
printf("ext2fs: bad block size: %d\n", es->e2fs_log_bsize); | fs->e2fs_fpg = es->e2fs_fpg; | ||||
if (fs->e2fs_bpg == 0 || fs->e2fs_fpg == 0) { | |||||
printf("ext2fs: zero blocks/fragments per group\n"); | |||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
/* Check for group size */ | |||||
if (fs->e2fs_bpg == 0) { | |||||
printf("ext2fs: zero blocks per group\n"); | |||||
return (EINVAL); | |||||
} | |||||
if (fs->e2fs_bpg != fs->e2fs_bsize * 8) { | if (fs->e2fs_bpg != fs->e2fs_bsize * 8) { | ||||
printf("ext2fs: non-standard group size unsupported %d\n", | printf("ext2fs: non-standard group size unsupported %d\n", | ||||
fs->e2fs_bpg); | fs->e2fs_bpg); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
fs->e2fs_ipb = fs->e2fs_bsize / EXT2_INODE_SIZE(fs); | fs->e2fs_ipb = fs->e2fs_bsize / EXT2_INODE_SIZE(fs); | ||||
if (fs->e2fs_ipg == 0) { | if (fs->e2fs_ipb == 0 || | ||||
printf("ext2fs: zero inodes per group\n"); | fs->e2fs_ipb > fs->e2fs_bsize / E2FS_REV0_INODE_SIZE) { | ||||
printf("ext2fs: bad inodes per block size\n"); | |||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
fs->e2fs_itpg = fs->e2fs_ipg / fs->e2fs_ipb; | |||||
/* Check for block consistency */ | fs->e2fs_ipg = es->e2fs_ipg; | ||||
if (es->e2fs_first_dblock >= fs->e2fs_bcount) { | if (fs->e2fs_ipg < fs->e2fs_ipb || fs->e2fs_ipg > fs->e2fs_bsize * 8) { | ||||
printf("ext2fs: invalid first data block\n"); | printf("ext2fs: invalid inodes per group: %u\n", fs->e2fs_ipb); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
fs->e2fs_itpg = fs->e2fs_ipg / fs->e2fs_ipb; | |||||
fs->e2fs_bcount = es->e2fs_bcount; | |||||
fs->e2fs_rbcount = es->e2fs_rbcount; | |||||
fs->e2fs_fbcount = es->e2fs_fbcount; | |||||
if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT)) { | |||||
fs->e2fs_bcount |= (uint64_t)(es->e4fs_bcount_hi) << 32; | |||||
fs->e2fs_rbcount |= (uint64_t)(es->e4fs_rbcount_hi) << 32; | |||||
fs->e2fs_fbcount |= (uint64_t)(es->e4fs_fbcount_hi) << 32; | |||||
} | |||||
if (fs->e2fs_rbcount > fs->e2fs_bcount || | if (fs->e2fs_rbcount > fs->e2fs_bcount || | ||||
fs->e2fs_fbcount > fs->e2fs_bcount) { | fs->e2fs_fbcount > fs->e2fs_bcount) { | ||||
printf("ext2fs: invalid block count\n"); | printf("ext2fs: invalid block count\n"); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
/* s_resuid / s_resgid ? */ | if (es->e2fs_first_dblock >= fs->e2fs_bcount) { | ||||
printf("ext2fs: first data block out of range\n"); | |||||
return (EINVAL); | |||||
} | |||||
fs->e2fs_gcount = howmany(fs->e2fs_bcount - es->e2fs_first_dblock, | fs->e2fs_gcount = howmany(fs->e2fs_bcount - es->e2fs_first_dblock, | ||||
EXT2_BLOCKS_PER_GROUP(fs)); | EXT2_BLOCKS_PER_GROUP(fs)); | ||||
if (fs->e2fs_gcount > ((uint64_t)1 << 32) - EXT2_DESCS_PER_BLOCK(fs)) { | |||||
printf("ext2fs: groups count too large: %u\n", fs->e2fs_gcount); | |||||
return (EINVAL); | |||||
} | |||||
/* Check for extra isize in big inodes. */ | |||||
if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_EXTRA_ISIZE) && | |||||
EXT2_INODE_SIZE(fs) < sizeof(struct ext2fs_dinode)) { | |||||
printf("ext2fs: no space for extra inode timestamps\n"); | |||||
return (EINVAL); | |||||
} | |||||
/* s_resuid / s_resgid ? */ | |||||
if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT)) { | if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT)) { | ||||
e2fs_descpb = fs->e2fs_bsize / sizeof(struct ext2_gd); | e2fs_descpb = fs->e2fs_bsize / E2FS_64BIT_GD_SIZE; | ||||
e2fs_gdbcount_alloc = howmany(fs->e2fs_gcount, e2fs_descpb); | e2fs_gdbcount_alloc = howmany(fs->e2fs_gcount, e2fs_descpb); | ||||
} else { | } else { | ||||
e2fs_descpb = fs->e2fs_bsize / E2FS_REV0_GD_SIZE; | e2fs_descpb = fs->e2fs_bsize / E2FS_REV0_GD_SIZE; | ||||
e2fs_gdbcount_alloc = howmany(fs->e2fs_gcount, | e2fs_gdbcount_alloc = howmany(fs->e2fs_gcount, | ||||
fs->e2fs_bsize / sizeof(struct ext2_gd)); | fs->e2fs_bsize / sizeof(struct ext2_gd)); | ||||
} | } | ||||
fs->e2fs_gdbcount = howmany(fs->e2fs_gcount, e2fs_descpb); | fs->e2fs_gdbcount = howmany(fs->e2fs_gcount, e2fs_descpb); | ||||
fs->e2fs_gd = malloc(e2fs_gdbcount_alloc * fs->e2fs_bsize, | fs->e2fs_gd = malloc(e2fs_gdbcount_alloc * fs->e2fs_bsize, | ||||
M_EXT2MNT, M_WAITOK | M_ZERO); | M_EXT2MNT, M_WAITOK | M_ZERO); | ||||
fs->e2fs_contigdirs = malloc(fs->e2fs_gcount * | fs->e2fs_contigdirs = malloc(fs->e2fs_gcount * | ||||
sizeof(*fs->e2fs_contigdirs), M_EXT2MNT, M_WAITOK | M_ZERO); | sizeof(*fs->e2fs_contigdirs), M_EXT2MNT, M_WAITOK | M_ZERO); | ||||
for (i = 0; i < fs->e2fs_gdbcount; i++) { | for (i = 0; i < fs->e2fs_gdbcount; i++) { | ||||
error = bread(devvp, | error = bread(devvp, | ||||
fsbtodb(fs, cg_location(fs, i)), | fsbtodb(fs, ext2_cg_location(fs, i)), | ||||
fs->e2fs_bsize, NOCRED, &bp); | fs->e2fs_bsize, NOCRED, &bp); | ||||
if (error) { | if (error) { | ||||
free(fs->e2fs_contigdirs, M_EXT2MNT); | free(fs->e2fs_contigdirs, M_EXT2MNT); | ||||
free(fs->e2fs_gd, M_EXT2MNT); | free(fs->e2fs_gd, M_EXT2MNT); | ||||
brelse(bp); | brelse(bp); | ||||
return (error); | return (error); | ||||
} | } | ||||
if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT)) { | if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT)) { | ||||
memcpy(&fs->e2fs_gd[ | memcpy(&fs->e2fs_gd[ | ||||
i * fs->e2fs_bsize / sizeof(struct ext2_gd)], | i * fs->e2fs_bsize / sizeof(struct ext2_gd)], | ||||
bp->b_data, fs->e2fs_bsize); | bp->b_data, fs->e2fs_bsize); | ||||
} else { | } else { | ||||
for (j = 0; j < e2fs_descpb && | for (j = 0; j < e2fs_descpb && | ||||
g_count < fs->e2fs_gcount; j++, g_count++) | g_count < fs->e2fs_gcount; j++, g_count++) | ||||
memcpy(&fs->e2fs_gd[g_count], | memcpy(&fs->e2fs_gd[g_count], | ||||
bp->b_data + j * E2FS_REV0_GD_SIZE, | bp->b_data + j * E2FS_REV0_GD_SIZE, | ||||
E2FS_REV0_GD_SIZE); | E2FS_REV0_GD_SIZE); | ||||
} | } | ||||
brelse(bp); | brelse(bp); | ||||
bp = NULL; | bp = NULL; | ||||
} | } | ||||
/* Precompute checksum seed for all metadata */ | |||||
ext2_sb_csum_set_seed(fs); | /* Validate cgs consistency */ | ||||
/* Verfy cg csum */ | error = ext2_cg_validate(fs); | ||||
if (error) | |||||
return (error); | |||||
/* Verfy cgs csum */ | |||||
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_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) { | ||||
error = ext2_gd_csum_verify(fs, devvp->v_rdev); | error = ext2_gd_csum_verify(fs, devvp->v_rdev); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
} | } | ||||
/* Initialization for the ext2 Orlov allocator variant. */ | /* Initialization for the ext2 Orlov allocator variant. */ | ||||
fs->e2fs_total_dir = 0; | fs->e2fs_total_dir = 0; | ||||
▲ Show 20 Lines • Show All 70 Lines • ▼ Show 20 Lines | ext2_reload(struct mount *mp, struct thread *td) | ||||
es = (struct ext2fs *)bp->b_data; | es = (struct ext2fs *)bp->b_data; | ||||
if (ext2_check_sb_compat(es, devvp->v_rdev, 0) != 0) { | if (ext2_check_sb_compat(es, devvp->v_rdev, 0) != 0) { | ||||
brelse(bp); | brelse(bp); | ||||
return (EIO); /* XXX needs translation */ | return (EIO); /* XXX needs translation */ | ||||
} | } | ||||
fs = VFSTOEXT2(mp)->um_e2fs; | fs = VFSTOEXT2(mp)->um_e2fs; | ||||
bcopy(bp->b_data, fs->e2fs, sizeof(struct ext2fs)); | bcopy(bp->b_data, fs->e2fs, sizeof(struct ext2fs)); | ||||
if ((error = compute_sb_data(devvp, es, fs)) != 0) { | if ((error = ext2_compute_sb_data(devvp, es, fs)) != 0) { | ||||
brelse(bp); | brelse(bp); | ||||
return (error); | return (error); | ||||
} | } | ||||
#ifdef UNKLAR | #ifdef UNKLAR | ||||
if (fs->fs_sbsize < SBSIZE) | if (fs->fs_sbsize < SBSIZE) | ||||
bp->b_flags |= B_INVAL; | bp->b_flags |= B_INVAL; | ||||
#endif | #endif | ||||
brelse(bp); | brelse(bp); | ||||
▲ Show 20 Lines • Show All 120 Lines • ▼ Show 20 Lines | "WARNING: R/W mount denied. Filesystem is not clean - run fsck\n"); | ||||
* while Linux keeps the super block in a locked buffer. | * while Linux keeps the super block in a locked buffer. | ||||
*/ | */ | ||||
ump->um_e2fs = malloc(sizeof(struct m_ext2fs), | ump->um_e2fs = malloc(sizeof(struct m_ext2fs), | ||||
M_EXT2MNT, M_WAITOK | M_ZERO); | M_EXT2MNT, M_WAITOK | M_ZERO); | ||||
ump->um_e2fs->e2fs = malloc(sizeof(struct ext2fs), | ump->um_e2fs->e2fs = malloc(sizeof(struct ext2fs), | ||||
M_EXT2MNT, M_WAITOK); | M_EXT2MNT, M_WAITOK); | ||||
mtx_init(EXT2_MTX(ump), "EXT2FS", "EXT2FS Lock", MTX_DEF); | mtx_init(EXT2_MTX(ump), "EXT2FS", "EXT2FS Lock", MTX_DEF); | ||||
bcopy(es, ump->um_e2fs->e2fs, (u_int)sizeof(struct ext2fs)); | bcopy(es, ump->um_e2fs->e2fs, (u_int)sizeof(struct ext2fs)); | ||||
if ((error = compute_sb_data(devvp, ump->um_e2fs->e2fs, ump->um_e2fs))) | if ((error = ext2_compute_sb_data(devvp, ump->um_e2fs->e2fs, ump->um_e2fs))) | ||||
goto out; | goto out; | ||||
/* | /* | ||||
* Calculate the maximum contiguous blocks and size of cluster summary | * Calculate the maximum contiguous blocks and size of cluster summary | ||||
* array. In FFS this is done by newfs; however, the superblock | * array. In FFS this is done by newfs; however, the superblock | ||||
* in ext2fs doesn't have these variables, so we can calculate | * in ext2fs doesn't have these variables, so we can calculate | ||||
* them here. | * them here. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 472 Lines • ▼ Show 20 Lines | ext2_cgupdate(struct ext2mount *mp, int waitfor) | ||||
/* Update gd csums */ | /* 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_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) | ||||
ext2_gd_csum_set(fs); | ext2_gd_csum_set(fs); | ||||
for (i = 0; i < fs->e2fs_gdbcount; i++) { | for (i = 0; i < fs->e2fs_gdbcount; i++) { | ||||
bp = getblk(mp->um_devvp, fsbtodb(fs, | bp = getblk(mp->um_devvp, fsbtodb(fs, | ||||
cg_location(fs, i)), | ext2_cg_location(fs, i)), | ||||
fs->e2fs_bsize, 0, 0, 0); | fs->e2fs_bsize, 0, 0, 0); | ||||
if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT)) { | if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT)) { | ||||
memcpy(bp->b_data, &fs->e2fs_gd[ | memcpy(bp->b_data, &fs->e2fs_gd[ | ||||
i * fs->e2fs_bsize / sizeof(struct ext2_gd)], | i * fs->e2fs_bsize / sizeof(struct ext2_gd)], | ||||
fs->e2fs_bsize); | fs->e2fs_bsize); | ||||
} else { | } else { | ||||
for (j = 0; j < fs->e2fs_bsize / E2FS_REV0_GD_SIZE && | for (j = 0; j < fs->e2fs_bsize / E2FS_REV0_GD_SIZE && | ||||
g_count < fs->e2fs_gcount; j++, g_count++) | g_count < fs->e2fs_gcount; j++, g_count++) | ||||
Show All 29 Lines |