Changeset View
Changeset View
Standalone View
Standalone View
stand/libsa/zfs/zfsimpl.c
Show All 25 Lines | ||||||||||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | |||||||||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | |||||||||||
/* | /* | |||||||||||
* Stand-alone ZFS file reader. | * Stand-alone ZFS file reader. | |||||||||||
*/ | */ | |||||||||||
#include <stdbool.h> | ||||||||||||
#include <sys/endian.h> | #include <sys/endian.h> | |||||||||||
#include <sys/stat.h> | #include <sys/stat.h> | |||||||||||
#include <sys/stdint.h> | #include <sys/stdint.h> | |||||||||||
#include <sys/list.h> | #include <sys/list.h> | |||||||||||
#include <machine/_inttypes.h> | #include <machine/_inttypes.h> | |||||||||||
#include "zfsimpl.h" | #include "zfsimpl.h" | |||||||||||
#include "zfssubr.c" | #include "zfssubr.c" | |||||||||||
▲ Show 20 Lines • Show All 181 Lines • ▼ Show 20 Lines | if (!vdev->v_phys_read) | |||||||||||
return (EIO); | return (EIO); | |||||||||||
if (bp) { | if (bp) { | |||||||||||
psize = BP_GET_PSIZE(bp); | psize = BP_GET_PSIZE(bp); | |||||||||||
} else { | } else { | |||||||||||
psize = size; | psize = size; | |||||||||||
} | } | |||||||||||
rc = vdev->v_phys_read(vdev, vdev->v_read_priv, offset, buf, psize); | rc = vdev->v_phys_read(vdev, vdev->v_priv, offset, buf, psize); | |||||||||||
if (rc == 0) { | if (rc == 0) { | |||||||||||
if (bp != NULL) | if (bp != NULL) | |||||||||||
rc = zio_checksum_verify(vdev->v_spa, bp, buf); | rc = zio_checksum_verify(vdev->v_spa, bp, buf); | |||||||||||
} | } | |||||||||||
return (rc); | return (rc); | |||||||||||
} | } | |||||||||||
static int | ||||||||||||
vdev_write_phys(vdev_t *vdev, void *buf, off_t offset, size_t size) | ||||||||||||
{ | ||||||||||||
if (vdev->v_phys_write == NULL) | ||||||||||||
return (ENXIO); | ||||||||||||
return (vdev->v_phys_write(vdev, offset, buf, size)); | ||||||||||||
} | ||||||||||||
typedef struct remap_segment { | typedef struct remap_segment { | |||||||||||
vdev_t *rs_vd; | vdev_t *rs_vd; | |||||||||||
uint64_t rs_offset; | uint64_t rs_offset; | |||||||||||
uint64_t rs_asize; | uint64_t rs_asize; | |||||||||||
uint64_t rs_split_offset; | uint64_t rs_split_offset; | |||||||||||
list_node_t rs_node; | list_node_t rs_node; | |||||||||||
} remap_segment_t; | } remap_segment_t; | |||||||||||
▲ Show 20 Lines • Show All 1,333 Lines • ▼ Show 20 Lines | vdev_label_read(vdev_t *vd, int l, void *buf, uint64_t offset, | |||||||||||
BP_SET_CHECKSUM(&bp, ZIO_CHECKSUM_LABEL); | BP_SET_CHECKSUM(&bp, ZIO_CHECKSUM_LABEL); | |||||||||||
BP_SET_COMPRESS(&bp, ZIO_COMPRESS_OFF); | BP_SET_COMPRESS(&bp, ZIO_COMPRESS_OFF); | |||||||||||
DVA_SET_OFFSET(BP_IDENTITY(&bp), off); | DVA_SET_OFFSET(BP_IDENTITY(&bp), off); | |||||||||||
ZIO_SET_CHECKSUM(&bp.blk_cksum, off, 0, 0, 0); | ZIO_SET_CHECKSUM(&bp.blk_cksum, off, 0, 0, 0); | |||||||||||
return (vdev_read_phys(vd, &bp, buf, off, size)); | return (vdev_read_phys(vd, &bp, buf, off, size)); | |||||||||||
} | } | |||||||||||
static int | ||||||||||||
vdev_label_write(vdev_t *vd, int l, vdev_boot_envblock_t *be, uint64_t offset) | ||||||||||||
{ | ||||||||||||
zio_checksum_info_t *ci; | ||||||||||||
zio_cksum_t cksum; | ||||||||||||
off_t off; | ||||||||||||
void *buf; | ||||||||||||
size_t size = VDEV_PAD_SIZE; | ||||||||||||
int rc; | ||||||||||||
off = vdev_label_offset(vd->v_psize, l, offset); | ||||||||||||
/* Make sure we can read this location. */ | ||||||||||||
buf = malloc(size); | ||||||||||||
if (buf == NULL) | ||||||||||||
return (ENOMEM); | ||||||||||||
rc = vdev_label_read(vd, l, buf, offset, size); | ||||||||||||
free(buf); | ||||||||||||
if (rc != 0) { | ||||||||||||
printf("will not update %s label %d, label read failed: %d\n", | ||||||||||||
vd->v_name ? vd->v_name : "unknown", l, rc); | ||||||||||||
return (rc); | ||||||||||||
} | ||||||||||||
ci = &zio_checksum_table[ZIO_CHECKSUM_LABEL]; | ||||||||||||
be->vbe_zbt.zec_magic = ZEC_MAGIC; | ||||||||||||
zio_checksum_label_verifier(&be->vbe_zbt.zec_cksum, off); | ||||||||||||
ci->ci_func[0](be, sizeof (*be), NULL, &cksum); | ||||||||||||
be->vbe_zbt.zec_cksum = cksum; | ||||||||||||
return (vdev_write_phys(vd, be, off, VDEV_PAD_SIZE)); | ||||||||||||
} | ||||||||||||
static int | ||||||||||||
vdev_write_bootenv_impl(vdev_t *vdev, vdev_boot_envblock_t *be) | ||||||||||||
{ | ||||||||||||
vdev_t *kid; | ||||||||||||
int rv; | ||||||||||||
STAILQ_FOREACH(kid, &vdev->v_children, v_childlink) { | ||||||||||||
if (kid->v_state != VDEV_STATE_HEALTHY) | ||||||||||||
continue; | ||||||||||||
rv = vdev_write_bootenv_impl(kid, be); | ||||||||||||
} | ||||||||||||
for (int l = 0; l < VDEV_LABELS; l++) { | ||||||||||||
rv = vdev_label_write(vdev, l, be, | ||||||||||||
offsetof(vdev_label_t, vl_be)); | ||||||||||||
if (rv != 0) { | ||||||||||||
printf("failed to write bootenv to %s label %d\n", | ||||||||||||
vdev->v_name, l); | ||||||||||||
} | ||||||||||||
} | ||||||||||||
return (0); | ||||||||||||
} | ||||||||||||
int | ||||||||||||
vdev_write_bootenv(vdev_t *vdev, nvlist_t *nvl) | ||||||||||||
{ | ||||||||||||
vdev_boot_envblock_t *be; | ||||||||||||
nvlist_t nv; | ||||||||||||
glebius: If I read code correct this message will print once again the failure message from… | ||||||||||||
int rv; | ||||||||||||
if (nvl->nv_size > sizeof(be->vbe_nvlist)) | ||||||||||||
return (E2BIG); | ||||||||||||
be = malloc(sizeof(*be)); | ||||||||||||
if (be == NULL) | ||||||||||||
return (ENOMEM); | ||||||||||||
nv.nv_header = nvl->nv_header; | ||||||||||||
nv.nv_asize = nvl->nv_asize; | ||||||||||||
nv.nv_size = nvl->nv_size; | ||||||||||||
*(nvs_header_t *)be->vbe_nvlist = nv.nv_header; | ||||||||||||
nv.nv_data = be->vbe_nvlist + sizeof(nvs_header_t); | ||||||||||||
bcopy(nvl->nv_data, nv.nv_data, nv.nv_size); | ||||||||||||
rv = nvlist_export(&nv); | ||||||||||||
if (rv == 0) { | ||||||||||||
rv = vdev_write_bootenv_impl(vdev, be); | ||||||||||||
} | ||||||||||||
free(be); | ||||||||||||
return (rv); | ||||||||||||
} | ||||||||||||
/* | ||||||||||||
* Read the bootenv area from pool label, return the nvlist from it. | ||||||||||||
* We return from first successful read. | ||||||||||||
*/ | ||||||||||||
nvlist_t * | ||||||||||||
vdev_read_bootenv(vdev_t *vdev) | ||||||||||||
{ | ||||||||||||
vdev_t *kid; | ||||||||||||
nvlist_t *benv; | ||||||||||||
vdev_boot_envblock_t *be; | ||||||||||||
int rv; | ||||||||||||
STAILQ_FOREACH(kid, &vdev->v_children, v_childlink) { | ||||||||||||
if (kid->v_state != VDEV_STATE_HEALTHY) | ||||||||||||
continue; | ||||||||||||
benv = vdev_read_bootenv(kid); | ||||||||||||
if (benv != NULL) | ||||||||||||
return (benv); | ||||||||||||
} | ||||||||||||
be = malloc(sizeof (*be)); | ||||||||||||
if (be == NULL) | ||||||||||||
return (NULL); | ||||||||||||
rv = 0; | ||||||||||||
for (int l = 0; l < VDEV_LABELS; l++) { | ||||||||||||
rv = vdev_label_read(vdev, l, be, | ||||||||||||
offsetof(vdev_label_t, vl_be), | ||||||||||||
sizeof (*be)); | ||||||||||||
if (rv == 0) | ||||||||||||
break; | ||||||||||||
} | ||||||||||||
if (rv != 0) { | ||||||||||||
free(be); | ||||||||||||
return (NULL); | ||||||||||||
} | ||||||||||||
benv = nvlist_import(be->vbe_nvlist + 4, be->vbe_nvlist[0], | ||||||||||||
be->vbe_nvlist[1]); | ||||||||||||
if (benv == NULL) { | ||||||||||||
char *command = (char *)be; | ||||||||||||
bool ok = false; | ||||||||||||
/* Check for legacy zfsbootcfg command string */ | ||||||||||||
for (int i = 0; command[i] != '\0'; i++) { | ||||||||||||
if (iscntrl(command[i])) { | ||||||||||||
ok = false; | ||||||||||||
break; | ||||||||||||
} else { | ||||||||||||
ok = true; | ||||||||||||
} | ||||||||||||
} | ||||||||||||
benv = nvlist_create(NV_UNIQUE_NAME); | ||||||||||||
if (ok) | ||||||||||||
nvlist_add_string(benv, "command", command); | ||||||||||||
} | ||||||||||||
return (benv); | ||||||||||||
} | ||||||||||||
static nvlist_t * | static nvlist_t * | |||||||||||
vdev_label_read_config(vdev_t *vd, uint64_t txg) | vdev_label_read_config(vdev_t *vd, uint64_t txg) | |||||||||||
{ | { | |||||||||||
vdev_phys_t *label; | vdev_phys_t *label; | |||||||||||
uint64_t best_txg = 0; | uint64_t best_txg = 0; | |||||||||||
uint64_t label_txg = 0; | uint64_t label_txg = 0; | |||||||||||
uint64_t asize; | uint64_t asize; | |||||||||||
nvlist_t *nvl = NULL, *tmp; | nvlist_t *nvl = NULL, *tmp; | |||||||||||
int error; | int error; | |||||||||||
Done Inline Actions
We leak be here. glebius: We leak be here. | ||||||||||||
label = malloc(sizeof (vdev_phys_t)); | label = malloc(sizeof (vdev_phys_t)); | |||||||||||
if (label == NULL) | if (label == NULL) | |||||||||||
return (NULL); | return (NULL); | |||||||||||
for (int l = 0; l < VDEV_LABELS; l++) { | for (int l = 0; l < VDEV_LABELS; l++) { | |||||||||||
const unsigned char *nvlist; | ||||||||||||
if (vdev_label_read(vd, l, label, | if (vdev_label_read(vd, l, label, | |||||||||||
offsetof(vdev_label_t, vl_vdev_phys), | offsetof(vdev_label_t, vl_vdev_phys), | |||||||||||
sizeof (vdev_phys_t))) | sizeof (vdev_phys_t))) | |||||||||||
continue; | continue; | |||||||||||
nvlist = (const unsigned char *) label->vp_nvlist; | tmp = nvlist_import(label->vp_nvlist + 4, | |||||||||||
tmp = nvlist_import(nvlist + 4, nvlist[0], nvlist[1]); | label->vp_nvlist[0], label->vp_nvlist[1]); | |||||||||||
if (tmp == NULL) | if (tmp == NULL) | |||||||||||
continue; | continue; | |||||||||||
error = nvlist_find(tmp, ZPOOL_CONFIG_POOL_TXG, | error = nvlist_find(tmp, ZPOOL_CONFIG_POOL_TXG, | |||||||||||
DATA_TYPE_UINT64, NULL, &label_txg, NULL); | DATA_TYPE_UINT64, NULL, &label_txg, NULL); | |||||||||||
if (error != 0 || label_txg == 0) { | if (error != 0 || label_txg == 0) { | |||||||||||
nvlist_destroy(nvl); | nvlist_destroy(nvl); | |||||||||||
nvl = tmp; | nvl = tmp; | |||||||||||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | for (int n = 0; n < VDEV_UBERBLOCK_COUNT(vd); n++) { | |||||||||||
if (vdev_uberblock_compare(buf, ub) > 0) | if (vdev_uberblock_compare(buf, ub) > 0) | |||||||||||
*ub = *buf; | *ub = *buf; | |||||||||||
} | } | |||||||||||
} | } | |||||||||||
free(buf); | free(buf); | |||||||||||
} | } | |||||||||||
static int | static int | |||||||||||
vdev_probe(vdev_phys_read_t *_read, void *read_priv, spa_t **spap) | vdev_probe(vdev_phys_read_t *_read, vdev_phys_write_t *_write, void *priv, | |||||||||||
spa_t **spap) | ||||||||||||
{ | { | |||||||||||
vdev_t vtmp; | vdev_t vtmp; | |||||||||||
spa_t *spa; | spa_t *spa; | |||||||||||
vdev_t *vdev; | vdev_t *vdev; | |||||||||||
nvlist_t *nvl; | nvlist_t *nvl; | |||||||||||
uint64_t val; | uint64_t val; | |||||||||||
uint64_t guid, vdev_children; | uint64_t guid, vdev_children; | |||||||||||
uint64_t pool_txg, pool_guid; | uint64_t pool_txg, pool_guid; | |||||||||||
const char *pool_name; | const char *pool_name; | |||||||||||
int rc, namelen; | int rc, namelen; | |||||||||||
/* | /* | |||||||||||
* Load the vdev label and figure out which | * Load the vdev label and figure out which | |||||||||||
* uberblock is most current. | * uberblock is most current. | |||||||||||
*/ | */ | |||||||||||
memset(&vtmp, 0, sizeof(vtmp)); | memset(&vtmp, 0, sizeof(vtmp)); | |||||||||||
vtmp.v_phys_read = _read; | vtmp.v_phys_read = _read; | |||||||||||
vtmp.v_read_priv = read_priv; | vtmp.v_phys_write = _write; | |||||||||||
vtmp.v_psize = P2ALIGN(ldi_get_size(read_priv), | vtmp.v_priv = priv; | |||||||||||
vtmp.v_psize = P2ALIGN(ldi_get_size(priv), | ||||||||||||
(uint64_t)sizeof (vdev_label_t)); | (uint64_t)sizeof (vdev_label_t)); | |||||||||||
/* Test for minimum device size. */ | /* Test for minimum device size. */ | |||||||||||
if (vtmp.v_psize < SPA_MINDEVSIZE) | if (vtmp.v_psize < SPA_MINDEVSIZE) | |||||||||||
return (EIO); | return (EIO); | |||||||||||
nvl = vdev_label_read_config(&vtmp, UINT64_MAX); | nvl = vdev_label_read_config(&vtmp, UINT64_MAX); | |||||||||||
if (nvl == NULL) | if (nvl == NULL) | |||||||||||
▲ Show 20 Lines • Show All 97 Lines • ▼ Show 20 Lines | vdev_probe(vdev_phys_read_t *_read, vdev_phys_write_t *_write, void *priv, | |||||||||||
/* | /* | |||||||||||
* We should already have created an incomplete vdev for this | * We should already have created an incomplete vdev for this | |||||||||||
* vdev. Find it and initialise it with our read proc. | * vdev. Find it and initialise it with our read proc. | |||||||||||
*/ | */ | |||||||||||
vdev = vdev_find(guid); | vdev = vdev_find(guid); | |||||||||||
if (vdev != NULL) { | if (vdev != NULL) { | |||||||||||
vdev->v_phys_read = _read; | vdev->v_phys_read = _read; | |||||||||||
vdev->v_read_priv = read_priv; | vdev->v_phys_write = _write; | |||||||||||
vdev->v_priv = priv; | ||||||||||||
vdev->v_psize = vtmp.v_psize; | vdev->v_psize = vtmp.v_psize; | |||||||||||
/* | /* | |||||||||||
* If no other state is set, mark vdev healthy. | * If no other state is set, mark vdev healthy. | |||||||||||
*/ | */ | |||||||||||
if (vdev->v_state == VDEV_STATE_UNKNOWN) | if (vdev->v_state == VDEV_STATE_UNKNOWN) | |||||||||||
vdev->v_state = VDEV_STATE_HEALTHY; | vdev->v_state = VDEV_STATE_HEALTHY; | |||||||||||
} else { | } else { | |||||||||||
printf("ZFS: inconsistent nvlist contents\n"); | printf("ZFS: inconsistent nvlist contents\n"); | |||||||||||
▲ Show 20 Lines • Show All 1,253 Lines • ▼ Show 20 Lines | ||||||||||||
} | } | |||||||||||
static int | static int | |||||||||||
load_nvlist(spa_t *spa, uint64_t obj, nvlist_t **value) | load_nvlist(spa_t *spa, uint64_t obj, nvlist_t **value) | |||||||||||
{ | { | |||||||||||
dnode_phys_t dir; | dnode_phys_t dir; | |||||||||||
size_t size; | size_t size; | |||||||||||
int rc; | int rc; | |||||||||||
unsigned char *nv; | char *nv; | |||||||||||
*value = NULL; | *value = NULL; | |||||||||||
if ((rc = objset_get_dnode(spa, &spa->spa_mos, obj, &dir)) != 0) | if ((rc = objset_get_dnode(spa, &spa->spa_mos, obj, &dir)) != 0) | |||||||||||
return (rc); | return (rc); | |||||||||||
if (dir.dn_type != DMU_OT_PACKED_NVLIST && | if (dir.dn_type != DMU_OT_PACKED_NVLIST && | |||||||||||
dir.dn_bonustype != DMU_OT_PACKED_NVLIST_SIZE) { | dir.dn_bonustype != DMU_OT_PACKED_NVLIST_SIZE) { | |||||||||||
return (EIO); | return (EIO); | |||||||||||
} | } | |||||||||||
▲ Show 20 Lines • Show All 351 Lines • Show Last 20 Lines |
If I read code correct this message will print once again the failure message from vdev_label_write(), except it doesn't check for NULL v_name.