Changeset View
Changeset View
Standalone View
Standalone View
stand/libsa/zfs/zfsimpl.c
Show First 20 Lines • Show All 70 Lines • ▼ Show 20 Lines | |||||
* List of all pools, chained through spa_link. | * List of all pools, chained through spa_link. | ||||
*/ | */ | ||||
static spa_list_t zfs_pools; | static spa_list_t zfs_pools; | ||||
static const dnode_phys_t *dnode_cache_obj; | static const dnode_phys_t *dnode_cache_obj; | ||||
static uint64_t dnode_cache_bn; | static uint64_t dnode_cache_bn; | ||||
static char *dnode_cache_buf; | static char *dnode_cache_buf; | ||||
static char *zap_scratch; | static char *zap_scratch; | ||||
static char *zfs_temp_buf, *zfs_temp_end, *zfs_temp_ptr; | |||||
#define TEMP_SIZE (1024 * 1024) | |||||
static int zio_read(const spa_t *spa, const blkptr_t *bp, void *buf); | static int zio_read(const spa_t *spa, const blkptr_t *bp, void *buf); | ||||
static int zfs_get_root(const spa_t *spa, uint64_t *objid); | static int zfs_get_root(const spa_t *spa, uint64_t *objid); | ||||
static int zfs_rlookup(const spa_t *spa, uint64_t objnum, char *result); | static int zfs_rlookup(const spa_t *spa, uint64_t objnum, char *result); | ||||
static int zap_lookup(const spa_t *spa, const dnode_phys_t *dnode, | static int zap_lookup(const spa_t *spa, const dnode_phys_t *dnode, | ||||
const char *name, uint64_t integer_size, uint64_t num_integers, | const char *name, uint64_t integer_size, uint64_t num_integers, | ||||
void *value); | void *value); | ||||
static void | static void | ||||
zfs_init(void) | zfs_init(void) | ||||
{ | { | ||||
STAILQ_INIT(&zfs_vdevs); | STAILQ_INIT(&zfs_vdevs); | ||||
STAILQ_INIT(&zfs_pools); | STAILQ_INIT(&zfs_pools); | ||||
zfs_temp_buf = malloc(TEMP_SIZE); | |||||
zfs_temp_end = zfs_temp_buf + TEMP_SIZE; | |||||
zfs_temp_ptr = zfs_temp_buf; | |||||
dnode_cache_buf = malloc(SPA_MAXBLOCKSIZE); | dnode_cache_buf = malloc(SPA_MAXBLOCKSIZE); | ||||
zap_scratch = malloc(SPA_MAXBLOCKSIZE); | zap_scratch = malloc(SPA_MAXBLOCKSIZE); | ||||
zfs_init_crc(); | zfs_init_crc(); | ||||
} | } | ||||
static void * | |||||
zfs_alloc(size_t size) | |||||
{ | |||||
char *ptr; | |||||
if (zfs_temp_ptr + size > zfs_temp_end) { | |||||
panic("ZFS: out of temporary buffer space"); | |||||
} | |||||
ptr = zfs_temp_ptr; | |||||
zfs_temp_ptr += size; | |||||
return (ptr); | |||||
} | |||||
static void | |||||
zfs_free(void *ptr, size_t size) | |||||
{ | |||||
zfs_temp_ptr -= size; | |||||
if (zfs_temp_ptr != ptr) { | |||||
panic("ZFS: zfs_alloc()/zfs_free() mismatch"); | |||||
} | |||||
} | |||||
static int | static int | ||||
xdr_int(const unsigned char **xdr, int *ip) | xdr_int(const unsigned char **xdr, int *ip) | ||||
{ | { | ||||
*ip = be32dec(*xdr); | *ip = be32dec(*xdr); | ||||
(*xdr) += 4; | (*xdr) += 4; | ||||
return (0); | return (0); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 815 Lines • ▼ Show 20 Lines | vdev_probe(vdev_phys_read_t *_read, void *read_priv, spa_t **spap) | ||||
vtmp.v_read_priv = read_priv; | vtmp.v_read_priv = read_priv; | ||||
psize = P2ALIGN(ldi_get_size(read_priv), | psize = P2ALIGN(ldi_get_size(read_priv), | ||||
(uint64_t)sizeof (vdev_label_t)); | (uint64_t)sizeof (vdev_label_t)); | ||||
/* Test for minimum pool size. */ | /* Test for minimum pool size. */ | ||||
if (psize < SPA_MINDEVSIZE) | if (psize < SPA_MINDEVSIZE) | ||||
return (EIO); | return (EIO); | ||||
tmp_label = zfs_alloc(sizeof(vdev_phys_t)); | tmp_label = malloc(sizeof(vdev_phys_t)); | ||||
if (tmp_label == NULL) | |||||
return (ENOMEM); | |||||
for (l = 0; l < VDEV_LABELS; l++) { | for (l = 0; l < VDEV_LABELS; l++) { | ||||
off = vdev_label_offset(psize, l, | off = vdev_label_offset(psize, l, | ||||
offsetof(vdev_label_t, vl_vdev_phys)); | offsetof(vdev_label_t, vl_vdev_phys)); | ||||
BP_ZERO(&bp); | BP_ZERO(&bp); | ||||
BP_SET_LSIZE(&bp, sizeof(vdev_phys_t)); | BP_SET_LSIZE(&bp, sizeof(vdev_phys_t)); | ||||
BP_SET_PSIZE(&bp, sizeof(vdev_phys_t)); | BP_SET_PSIZE(&bp, sizeof(vdev_phys_t)); | ||||
Show All 14 Lines | if (nvlist_find(nvlist, ZPOOL_CONFIG_POOL_TXG, | ||||
continue; | continue; | ||||
if (best_txg <= pool_txg) { | if (best_txg <= pool_txg) { | ||||
best_txg = pool_txg; | best_txg = pool_txg; | ||||
memcpy(vdev_label, tmp_label, sizeof (vdev_phys_t)); | memcpy(vdev_label, tmp_label, sizeof (vdev_phys_t)); | ||||
} | } | ||||
} | } | ||||
zfs_free(tmp_label, sizeof (vdev_phys_t)); | free(tmp_label); | ||||
if (best_txg == 0) | if (best_txg == 0) | ||||
return (EIO); | return (EIO); | ||||
if (vdev_label->vp_nvlist[0] != NV_ENCODE_XDR) | if (vdev_label->vp_nvlist[0] != NV_ENCODE_XDR) | ||||
return (EIO); | return (EIO); | ||||
nvlist = (const unsigned char *) vdev_label->vp_nvlist + 4; | nvlist = (const unsigned char *) vdev_label->vp_nvlist + 4; | ||||
▲ Show 20 Lines • Show All 114 Lines • ▼ Show 20 Lines | vdev_probe(vdev_phys_read_t *_read, void *read_priv, spa_t **spap) | ||||
*/ | */ | ||||
vdev_set_state(top_vdev); | vdev_set_state(top_vdev); | ||||
/* | /* | ||||
* Ok, we are happy with the pool so far. Lets find | * Ok, we are happy with the pool so far. Lets find | ||||
* the best uberblock and then we can actually access | * the best uberblock and then we can actually access | ||||
* the contents of the pool. | * the contents of the pool. | ||||
*/ | */ | ||||
upbuf = zfs_alloc(VDEV_UBERBLOCK_SIZE(vdev)); | upbuf = malloc(VDEV_UBERBLOCK_SIZE(vdev)); | ||||
if (upbuf == NULL) | |||||
return (ENOMEM); | |||||
up = (const struct uberblock *)upbuf; | up = (const struct uberblock *)upbuf; | ||||
for (l = 0; l < VDEV_LABELS; l++) { | for (l = 0; l < VDEV_LABELS; l++) { | ||||
for (i = 0; i < VDEV_UBERBLOCK_COUNT(vdev); i++) { | for (i = 0; i < VDEV_UBERBLOCK_COUNT(vdev); i++) { | ||||
off = vdev_label_offset(psize, l, | off = vdev_label_offset(psize, l, | ||||
VDEV_UBERBLOCK_OFFSET(vdev, i)); | VDEV_UBERBLOCK_OFFSET(vdev, i)); | ||||
BP_ZERO(&bp); | BP_ZERO(&bp); | ||||
DVA_SET_OFFSET(&bp.blk_dva[0], off); | DVA_SET_OFFSET(&bp.blk_dva[0], off); | ||||
BP_SET_LSIZE(&bp, VDEV_UBERBLOCK_SIZE(vdev)); | BP_SET_LSIZE(&bp, VDEV_UBERBLOCK_SIZE(vdev)); | ||||
Show All 12 Lines | for (i = 0; i < VDEV_UBERBLOCK_COUNT(vdev); i++) { | ||||
if (up->ub_txg > spa->spa_uberblock.ub_txg || | if (up->ub_txg > spa->spa_uberblock.ub_txg || | ||||
(up->ub_txg == spa->spa_uberblock.ub_txg && | (up->ub_txg == spa->spa_uberblock.ub_txg && | ||||
up->ub_timestamp > | up->ub_timestamp > | ||||
spa->spa_uberblock.ub_timestamp)) { | spa->spa_uberblock.ub_timestamp)) { | ||||
spa->spa_uberblock = *up; | spa->spa_uberblock = *up; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
zfs_free(upbuf, VDEV_UBERBLOCK_SIZE(vdev)); | free(upbuf); | ||||
vdev->spa = spa; | vdev->spa = spa; | ||||
if (spap != NULL) | if (spap != NULL) | ||||
*spap = spa; | *spap = spa; | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
▲ Show 20 Lines • Show All 56 Lines • ▼ Show 20 Lines | zio_read(const spa_t *spa, const blkptr_t *bp, void *buf) | ||||
* Process data embedded in block pointer | * Process data embedded in block pointer | ||||
*/ | */ | ||||
if (BP_IS_EMBEDDED(bp)) { | if (BP_IS_EMBEDDED(bp)) { | ||||
ASSERT(BPE_GET_ETYPE(bp) == BP_EMBEDDED_TYPE_DATA); | ASSERT(BPE_GET_ETYPE(bp) == BP_EMBEDDED_TYPE_DATA); | ||||
size = BPE_GET_PSIZE(bp); | size = BPE_GET_PSIZE(bp); | ||||
ASSERT(size <= BPE_PAYLOAD_SIZE); | ASSERT(size <= BPE_PAYLOAD_SIZE); | ||||
if (cpfunc != ZIO_COMPRESS_OFF) | if (cpfunc != ZIO_COMPRESS_OFF) { | ||||
pbuf = zfs_alloc(size); | pbuf = malloc(size); | ||||
else | if (pbuf == NULL) { | ||||
error = ENOMEM; | |||||
goto embedout; | |||||
} | |||||
} else { | |||||
pbuf = buf; | pbuf = buf; | ||||
} | |||||
decode_embedded_bp_compressed(bp, pbuf); | decode_embedded_bp_compressed(bp, pbuf); | ||||
error = 0; | error = 0; | ||||
if (cpfunc != ZIO_COMPRESS_OFF) { | if (cpfunc != ZIO_COMPRESS_OFF) { | ||||
error = zio_decompress_data(cpfunc, pbuf, | error = zio_decompress_data(cpfunc, pbuf, | ||||
size, buf, BP_GET_LSIZE(bp)); | size, buf, BP_GET_LSIZE(bp)); | ||||
zfs_free(pbuf, size); | free(pbuf); | ||||
} | } | ||||
embedout: | |||||
if (error != 0) | if (error != 0) | ||||
printf("ZFS: i/o error - unable to decompress block pointer data, error %d\n", | printf("ZFS: i/o error - unable to decompress block pointer data, error %d\n", | ||||
error); | error); | ||||
return (error); | return (error); | ||||
} | } | ||||
error = EIO; | error = EIO; | ||||
Show All 16 Lines | if (!vdev || !vdev->v_read) | ||||
continue; | continue; | ||||
size = BP_GET_PSIZE(bp); | size = BP_GET_PSIZE(bp); | ||||
if (vdev->v_read == vdev_raidz_read) { | if (vdev->v_read == vdev_raidz_read) { | ||||
align = 1ULL << vdev->v_top->v_ashift; | align = 1ULL << vdev->v_top->v_ashift; | ||||
if (P2PHASE(size, align) != 0) | if (P2PHASE(size, align) != 0) | ||||
size = P2ROUNDUP(size, align); | size = P2ROUNDUP(size, align); | ||||
} | } | ||||
if (size != BP_GET_PSIZE(bp) || cpfunc != ZIO_COMPRESS_OFF) | if (size != BP_GET_PSIZE(bp) || cpfunc != ZIO_COMPRESS_OFF) { | ||||
pbuf = zfs_alloc(size); | pbuf = malloc(size); | ||||
else | if (pbuf == NULL) { | ||||
printf("ZFS: i/o error - out of memory\n"); | |||||
return (ENOMEM); | |||||
} | |||||
} else { | |||||
pbuf = buf; | pbuf = buf; | ||||
} | |||||
if (DVA_GET_GANG(dva)) | if (DVA_GET_GANG(dva)) | ||||
error = zio_read_gang(spa, bp, pbuf); | error = zio_read_gang(spa, bp, pbuf); | ||||
else | else | ||||
error = vdev->v_read(vdev, bp, pbuf, offset, size); | error = vdev->v_read(vdev, bp, pbuf, offset, size); | ||||
if (error == 0) { | if (error == 0) { | ||||
if (cpfunc != ZIO_COMPRESS_OFF) | if (cpfunc != ZIO_COMPRESS_OFF) | ||||
error = zio_decompress_data(cpfunc, pbuf, | error = zio_decompress_data(cpfunc, pbuf, | ||||
BP_GET_PSIZE(bp), buf, BP_GET_LSIZE(bp)); | BP_GET_PSIZE(bp), buf, BP_GET_LSIZE(bp)); | ||||
else if (size != BP_GET_PSIZE(bp)) | else if (size != BP_GET_PSIZE(bp)) | ||||
bcopy(pbuf, buf, BP_GET_PSIZE(bp)); | bcopy(pbuf, buf, BP_GET_PSIZE(bp)); | ||||
} | } | ||||
if (buf != pbuf) | if (buf != pbuf) | ||||
zfs_free(pbuf, size); | free(pbuf); | ||||
if (error == 0) | if (error == 0) | ||||
break; | break; | ||||
} | } | ||||
if (error != 0) | if (error != 0) | ||||
printf("ZFS: i/o error - all block copies unavailable\n"); | printf("ZFS: i/o error - all block copies unavailable\n"); | ||||
return (error); | return (error); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 979 Lines • ▼ Show 20 Lines | if (dn->dn_bonustype != DMU_OT_SA) { | ||||
if (dn->dn_bonuslen != 0) | if (dn->dn_bonuslen != 0) | ||||
sahdrp = (sa_hdr_phys_t *)DN_BONUS(dn); | sahdrp = (sa_hdr_phys_t *)DN_BONUS(dn); | ||||
else { | else { | ||||
if ((dn->dn_flags & DNODE_FLAG_SPILL_BLKPTR) != 0) { | if ((dn->dn_flags & DNODE_FLAG_SPILL_BLKPTR) != 0) { | ||||
blkptr_t *bp = DN_SPILL_BLKPTR(dn); | blkptr_t *bp = DN_SPILL_BLKPTR(dn); | ||||
int error; | int error; | ||||
size = BP_GET_LSIZE(bp); | size = BP_GET_LSIZE(bp); | ||||
buf = zfs_alloc(size); | buf = malloc(size); | ||||
error = zio_read(spa, bp, buf); | error = zio_read(spa, bp, buf); | ||||
if (error != 0) { | if (error != 0) { | ||||
zfs_free(buf, size); | free(buf); | ||||
return (error); | return (error); | ||||
} | } | ||||
sahdrp = buf; | sahdrp = buf; | ||||
} else { | } else { | ||||
return (EIO); | return (EIO); | ||||
} | } | ||||
} | } | ||||
hdrsize = SA_HDR_SIZE(sahdrp); | hdrsize = SA_HDR_SIZE(sahdrp); | ||||
sb->st_mode = *(uint64_t *)((char *)sahdrp + hdrsize + | sb->st_mode = *(uint64_t *)((char *)sahdrp + hdrsize + | ||||
SA_MODE_OFFSET); | SA_MODE_OFFSET); | ||||
sb->st_uid = *(uint64_t *)((char *)sahdrp + hdrsize + | sb->st_uid = *(uint64_t *)((char *)sahdrp + hdrsize + | ||||
SA_UID_OFFSET); | SA_UID_OFFSET); | ||||
sb->st_gid = *(uint64_t *)((char *)sahdrp + hdrsize + | sb->st_gid = *(uint64_t *)((char *)sahdrp + hdrsize + | ||||
SA_GID_OFFSET); | SA_GID_OFFSET); | ||||
sb->st_size = *(uint64_t *)((char *)sahdrp + hdrsize + | sb->st_size = *(uint64_t *)((char *)sahdrp + hdrsize + | ||||
SA_SIZE_OFFSET); | SA_SIZE_OFFSET); | ||||
if (buf != NULL) | if (buf != NULL) | ||||
zfs_free(buf, size); | free(buf); | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
zfs_dnode_readlink(const spa_t *spa, dnode_phys_t *dn, char *path, size_t psize) | zfs_dnode_readlink(const spa_t *spa, dnode_phys_t *dn, char *path, size_t psize) | ||||
{ | { | ||||
Show All 11 Lines | if (dn->dn_bonustype == DMU_OT_SA) { | ||||
else { | else { | ||||
blkptr_t *bp; | blkptr_t *bp; | ||||
if ((dn->dn_flags & DNODE_FLAG_SPILL_BLKPTR) == 0) | if ((dn->dn_flags & DNODE_FLAG_SPILL_BLKPTR) == 0) | ||||
return (EIO); | return (EIO); | ||||
bp = DN_SPILL_BLKPTR(dn); | bp = DN_SPILL_BLKPTR(dn); | ||||
size = BP_GET_LSIZE(bp); | size = BP_GET_LSIZE(bp); | ||||
buf = zfs_alloc(size); | buf = malloc(size); | ||||
if (buf == NULL) | |||||
return (ENOMEM); | |||||
rc = zio_read(spa, bp, buf); | rc = zio_read(spa, bp, buf); | ||||
if (rc != 0) { | if (rc != 0) { | ||||
zfs_free(buf, size); | free(buf); | ||||
return (rc); | return (rc); | ||||
} | } | ||||
sahdrp = buf; | sahdrp = buf; | ||||
} | } | ||||
hdrsize = SA_HDR_SIZE(sahdrp); | hdrsize = SA_HDR_SIZE(sahdrp); | ||||
p = (char *)((uintptr_t)sahdrp + hdrsize + SA_SYMLINK_OFFSET); | p = (char *)((uintptr_t)sahdrp + hdrsize + SA_SYMLINK_OFFSET); | ||||
memcpy(path, p, psize); | memcpy(path, p, psize); | ||||
if (buf != NULL) | if (buf != NULL) | ||||
zfs_free(buf, size); | free(buf); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Second test is purely to silence bogus compiler | * Second test is purely to silence bogus compiler | ||||
* warning about accessing past the end of dn_bonus. | * warning about accessing past the end of dn_bonus. | ||||
*/ | */ | ||||
if (psize + sizeof(znode_phys_t) <= dn->dn_bonuslen && | if (psize + sizeof(znode_phys_t) <= dn->dn_bonuslen && | ||||
sizeof(znode_phys_t) <= sizeof(dn->dn_bonus)) { | sizeof(znode_phys_t) <= sizeof(dn->dn_bonus)) { | ||||
▲ Show 20 Lines • Show All 179 Lines • Show Last 20 Lines |