Changeset View
Changeset View
Standalone View
Standalone View
sys/fs/ext2fs/ext2_extents.c
Show All 31 Lines | |||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/types.h> | #include <sys/types.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/vnode.h> | #include <sys/vnode.h> | ||||
#include <sys/bio.h> | #include <sys/bio.h> | ||||
#include <sys/buf.h> | #include <sys/buf.h> | ||||
#include <sys/conf.h> | #include <sys/conf.h> | ||||
#include <sys/sdt.h> | |||||
#include <sys/stat.h> | #include <sys/stat.h> | ||||
#include <fs/ext2fs/ext2_mount.h> | #include <fs/ext2fs/ext2_mount.h> | ||||
#include <fs/ext2fs/fs.h> | #include <fs/ext2fs/fs.h> | ||||
#include <fs/ext2fs/inode.h> | #include <fs/ext2fs/inode.h> | ||||
#include <fs/ext2fs/ext2fs.h> | #include <fs/ext2fs/ext2fs.h> | ||||
#include <fs/ext2fs/ext2_extents.h> | #include <fs/ext2fs/ext2_extents.h> | ||||
#include <fs/ext2fs/ext2_extern.h> | #include <fs/ext2fs/ext2_extern.h> | ||||
SDT_PROVIDER_DECLARE(ext2fs); | |||||
/* | |||||
* ext2fs trace probe: | |||||
* arg0: verbosity. Higher numbers give more verbose messages | |||||
* arg1: Textual message | |||||
*/ | |||||
SDT_PROBE_DEFINE2(ext2fs, , trace, extents, "int", "char*"); | |||||
static MALLOC_DEFINE(M_EXT2EXTENTS, "ext2_extents", "EXT2 extents"); | static MALLOC_DEFINE(M_EXT2EXTENTS, "ext2_extents", "EXT2 extents"); | ||||
#ifdef EXT2FS_DEBUG | #ifdef EXT2FS_PRINT_EXTENTS | ||||
static void | static void | ||||
ext4_ext_print_extent(struct ext4_extent *ep) | ext4_ext_print_extent(struct ext4_extent *ep) | ||||
{ | { | ||||
printf(" ext %p => (blk %u len %u start %ju)\n", | printf(" ext %p => (blk %u len %u start %ju)\n", | ||||
ep, ep->e_blk, ep->e_len, | ep, ep->e_blk, ep->e_len, | ||||
(uint64_t)ep->e_start_hi << 32 | ep->e_start_lo); | (uint64_t)ep->e_start_hi << 32 | ep->e_start_lo); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 165 Lines • ▼ Show 20 Lines | |||||
ext4_ext_check_header(struct inode *ip, struct ext4_extent_header *eh) | ext4_ext_check_header(struct inode *ip, struct ext4_extent_header *eh) | ||||
{ | { | ||||
struct m_ext2fs *fs; | struct m_ext2fs *fs; | ||||
char *error_msg; | char *error_msg; | ||||
fs = ip->i_e2fs; | fs = ip->i_e2fs; | ||||
if (eh->eh_magic != EXT4_EXT_MAGIC) { | if (eh->eh_magic != EXT4_EXT_MAGIC) { | ||||
error_msg = "invalid magic"; | error_msg = "header: invalid magic"; | ||||
goto corrupted; | goto corrupted; | ||||
} | } | ||||
if (eh->eh_max == 0) { | if (eh->eh_max == 0) { | ||||
error_msg = "invalid eh_max"; | error_msg = "header: invalid eh_max"; | ||||
goto corrupted; | goto corrupted; | ||||
} | } | ||||
if (eh->eh_ecount > eh->eh_max) { | if (eh->eh_ecount > eh->eh_max) { | ||||
error_msg = "invalid eh_entries"; | error_msg = "header: invalid eh_entries"; | ||||
goto corrupted; | goto corrupted; | ||||
} | } | ||||
return (0); | return (0); | ||||
corrupted: | corrupted: | ||||
ext2_fserr(fs, ip->i_uid, error_msg); | SDT_PROBE2(ext2fs, , trace, extents, 1, error_msg); | ||||
return (EIO); | return (EIO); | ||||
} | } | ||||
static void | static void | ||||
ext4_ext_binsearch_index(struct ext4_extent_path *path, int blk) | ext4_ext_binsearch_index(struct ext4_extent_path *path, int blk) | ||||
{ | { | ||||
struct ext4_extent_header *eh; | struct ext4_extent_header *eh; | ||||
struct ext4_extent_index *r, *l, *m; | struct ext4_extent_index *r, *l, *m; | ||||
▲ Show 20 Lines • Show All 150 Lines • ▼ Show 20 Lines | error = bread(ip->i_devvp, fsbtodb(ip->i_e2fs, blk), | ||||
ip->i_e2fs->e2fs_bsize, NOCRED, &bp); | ip->i_e2fs->e2fs_bsize, NOCRED, &bp); | ||||
if (error) { | if (error) { | ||||
brelse(bp); | brelse(bp); | ||||
goto error; | goto error; | ||||
} | } | ||||
ppos++; | ppos++; | ||||
if (ppos > depth) { | if (ppos > depth) { | ||||
ext2_fserr(fs, ip->i_uid, | SDT_PROBE2(ext2fs, , trace, extents, 1, | ||||
"ppos > depth => extent corrupted"); | "ppos > depth => extent corrupted"); | ||||
error = EIO; | error = EIO; | ||||
brelse(bp); | brelse(bp); | ||||
goto error; | goto error; | ||||
} | } | ||||
ext4_ext_fill_path_bdata(&path[ppos], bp, blk); | ext4_ext_fill_path_bdata(&path[ppos], bp, blk); | ||||
bqrelse(bp); | bqrelse(bp); | ||||
▲ Show 20 Lines • Show All 214 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
struct m_ext2fs *fs; | struct m_ext2fs *fs; | ||||
struct ext4_extent_index *idx; | struct ext4_extent_index *idx; | ||||
int len; | int len; | ||||
fs = ip->i_e2fs; | fs = ip->i_e2fs; | ||||
if (lblk == path->ep_index->ei_blk) { | if (lblk == path->ep_index->ei_blk) { | ||||
ext2_fserr(fs, ip->i_uid, | SDT_PROBE2(ext2fs, , trace, extents, 1, | ||||
"lblk == index blk => extent corrupted"); | "lblk == index blk => extent corrupted"); | ||||
return (EIO); | return (EIO); | ||||
} | } | ||||
if (path->ep_header->eh_ecount >= path->ep_header->eh_max) { | if (path->ep_header->eh_ecount >= path->ep_header->eh_max) { | ||||
ext2_fserr(fs, ip->i_uid, | SDT_PROBE2(ext2fs, , trace, extents, 1, | ||||
"ecout > maxcount => extent corrupted"); | "ecout > maxcount => extent corrupted"); | ||||
return (EIO); | return (EIO); | ||||
} | } | ||||
if (lblk > path->ep_index->ei_blk) { | if (lblk > path->ep_index->ei_blk) { | ||||
/* Insert after. */ | /* Insert after. */ | ||||
idx = path->ep_index + 1; | idx = path->ep_index + 1; | ||||
} else { | } else { | ||||
/* Insert before. */ | /* Insert before. */ | ||||
idx = path->ep_index; | idx = path->ep_index; | ||||
} | } | ||||
len = EXT_LAST_INDEX(path->ep_header) - idx + 1; | len = EXT_LAST_INDEX(path->ep_header) - idx + 1; | ||||
if (len > 0) | if (len > 0) | ||||
memmove(idx + 1, idx, len * sizeof(struct ext4_extent_index)); | memmove(idx + 1, idx, len * sizeof(struct ext4_extent_index)); | ||||
if (idx > EXT_MAX_INDEX(path->ep_header)) { | if (idx > EXT_MAX_INDEX(path->ep_header)) { | ||||
ext2_fserr(fs, ip->i_uid, | SDT_PROBE2(ext2fs, , trace, extents, 1, | ||||
"index is out of range => extent corrupted"); | "index is out of range => extent corrupted"); | ||||
return (EIO); | return (EIO); | ||||
} | } | ||||
idx->ei_blk = lblk; | idx->ei_blk = lblk; | ||||
ext4_index_store_pblock(idx, blk); | ext4_index_store_pblock(idx, blk); | ||||
path->ep_header->eh_ecount++; | path->ep_header->eh_ecount++; | ||||
▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | ext4_ext_split(struct inode *ip, struct ext4_extent_path *path, | ||||
fs = ip->i_e2fs; | fs = ip->i_e2fs; | ||||
bp = NULL; | bp = NULL; | ||||
/* | /* | ||||
* We will split at current extent for now. | * We will split at current extent for now. | ||||
*/ | */ | ||||
if (path[depth].ep_ext > EXT_MAX_EXTENT(path[depth].ep_header)) { | if (path[depth].ep_ext > EXT_MAX_EXTENT(path[depth].ep_header)) { | ||||
ext2_fserr(fs, ip->i_uid, | SDT_PROBE2(ext2fs, , trace, extents, 1, | ||||
"extent is out of range => extent corrupted"); | "extent is out of range => extent corrupted"); | ||||
return (EIO); | return (EIO); | ||||
} | } | ||||
if (path[depth].ep_ext != EXT_MAX_EXTENT(path[depth].ep_header)) | if (path[depth].ep_ext != EXT_MAX_EXTENT(path[depth].ep_header)) | ||||
border = path[depth].ep_ext[1].e_blk; | border = path[depth].ep_ext[1].e_blk; | ||||
else | else | ||||
border = newext->e_blk; | border = newext->e_blk; | ||||
Show All 20 Lines | ext4_ext_split(struct inode *ip, struct ext4_extent_path *path, | ||||
neh = ext4_ext_block_header(bp->b_data); | neh = ext4_ext_block_header(bp->b_data); | ||||
neh->eh_ecount = 0; | neh->eh_ecount = 0; | ||||
neh->eh_max = ext4_ext_space_block(ip); | neh->eh_max = ext4_ext_space_block(ip); | ||||
neh->eh_magic = EXT4_EXT_MAGIC; | neh->eh_magic = EXT4_EXT_MAGIC; | ||||
neh->eh_depth = 0; | neh->eh_depth = 0; | ||||
ex = EXT_FIRST_EXTENT(neh); | ex = EXT_FIRST_EXTENT(neh); | ||||
if (path[depth].ep_header->eh_ecount != path[depth].ep_header->eh_max) { | if (path[depth].ep_header->eh_ecount != path[depth].ep_header->eh_max) { | ||||
ext2_fserr(fs, ip->i_uid, | SDT_PROBE2(ext2fs, , trace, extents, 1, | ||||
"extents count out of range => extent corrupted"); | "extents count out of range => extent corrupted"); | ||||
error = EIO; | error = EIO; | ||||
goto cleanup; | goto cleanup; | ||||
} | } | ||||
/* Start copy from next extent. */ | /* Start copy from next extent. */ | ||||
m = 0; | m = 0; | ||||
path[depth].ep_ext++; | path[depth].ep_ext++; | ||||
▲ Show 20 Lines • Show All 572 Lines • ▼ Show 20 Lines | if (!path[depth].ep_header) { | ||||
if (path[depth].ep_data == NULL) | if (path[depth].ep_data == NULL) | ||||
return (EINVAL); | return (EINVAL); | ||||
path[depth].ep_header = | path[depth].ep_header = | ||||
(struct ext4_extent_header* )path[depth].ep_data; | (struct ext4_extent_header* )path[depth].ep_data; | ||||
} | } | ||||
eh = path[depth].ep_header; | eh = path[depth].ep_header; | ||||
if (!eh) { | if (!eh) { | ||||
ext2_fserr(ip->i_e2fs, ip->i_uid, | SDT_PROBE2(ext2fs, , trace, extents, 1, | ||||
"bad header => extent corrupted"); | "bad header => extent corrupted"); | ||||
return (EIO); | return (EIO); | ||||
} | } | ||||
ex = EXT_LAST_EXTENT(eh); | ex = EXT_LAST_EXTENT(eh); | ||||
ex_blk = ex->e_blk; | ex_blk = ex->e_blk; | ||||
ex_len = ext4_ext_get_actual_len(ex); | ex_len = ext4_ext_get_actual_len(ex); | ||||
▲ Show 20 Lines • Show All 70 Lines • ▼ Show 20 Lines | error = bread(ip->i_devvp, fsbtodb(fs, pblk), | ||||
fs->e2fs_bsize, NOCRED, &bp); | fs->e2fs_bsize, NOCRED, &bp); | ||||
if (error) { | if (error) { | ||||
brelse(bp); | brelse(bp); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
eh = ext4_ext_block_header(bp->b_data); | eh = ext4_ext_block_header(bp->b_data); | ||||
if (eh->eh_depth != depth) { | if (eh->eh_depth != depth) { | ||||
ext2_fserr(fs, ip->i_uid, "unexpected eh_depth"); | SDT_PROBE2(ext2fs, , trace, extents, 1, | ||||
"unexpected eh_depth"); | |||||
goto err; | goto err; | ||||
} | } | ||||
error = ext4_ext_check_header(ip, eh); | error = ext4_ext_check_header(ip, eh); | ||||
if (error) | if (error) | ||||
goto err; | goto err; | ||||
return (bp); | return (bp); | ||||
▲ Show 20 Lines • Show All 114 Lines • Show Last 20 Lines |