Changeset View
Changeset View
Standalone View
Standalone View
stand/libsa/zfs/zfsimpl.c
Show First 20 Lines • Show All 72 Lines • ▼ Show 20 Lines | |||||
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; | static char *zfs_temp_buf, *zfs_temp_end, *zfs_temp_ptr; | ||||
#define TEMP_SIZE (1024 * 1024) | #define TEMP_SIZE (1024 * 1024) | ||||
#define ALL_LABELS_INVALID ((int)0xFFFFFFFF) | |||||
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); | ||||
▲ Show 20 Lines • Show All 419 Lines • ▼ Show 20 Lines | vdev_create(uint64_t guid, vdev_read_t *_read) | ||||
vdev->v_read = _read; | vdev->v_read = _read; | ||||
vdev->v_phys_read = 0; | vdev->v_phys_read = 0; | ||||
vdev->v_read_priv = 0; | vdev->v_read_priv = 0; | ||||
STAILQ_INSERT_TAIL(&zfs_vdevs, vdev, v_alllink); | STAILQ_INSERT_TAIL(&zfs_vdevs, vdev, v_alllink); | ||||
return (vdev); | return (vdev); | ||||
} | } | ||||
static void | |||||
vdev_delete_by_guid(uint64_t guid) | |||||
{ | |||||
vdev_t *dev, *kid; | |||||
if(dev = vdev_find(guid)) { | |||||
STAILQ_FOREACH(kid, &dev->v_children, v_childlink) | |||||
vdev_delete_by_guid(kid->v_guid); | |||||
STAILQ_REMOVE(&zfs_vdevs, dev, vdev, v_alllink); | |||||
free(dev); | |||||
} | |||||
} | |||||
static int | static int | ||||
vdev_init_from_nvlist(const unsigned char *nvlist, vdev_t *pvdev, | vdev_init_from_nvlist(const unsigned char *nvlist, vdev_t *pvdev, | ||||
vdev_t **vdevp, int is_newer) | vdev_t **vdevp, int is_newer) | ||||
{ | { | ||||
int rc; | int rc; | ||||
uint64_t guid, id, ashift, nparity; | uint64_t guid, id, ashift, nparity; | ||||
const char *type; | const char *type; | ||||
const char *path; | const char *path; | ||||
▲ Show 20 Lines • Show All 237 Lines • ▼ Show 20 Lines | spa_create(uint64_t guid, const char *name) | ||||
} | } | ||||
STAILQ_INIT(&spa->spa_vdevs); | STAILQ_INIT(&spa->spa_vdevs); | ||||
spa->spa_guid = guid; | spa->spa_guid = guid; | ||||
STAILQ_INSERT_TAIL(&zfs_pools, spa, spa_link); | STAILQ_INSERT_TAIL(&zfs_pools, spa, spa_link); | ||||
return (spa); | return (spa); | ||||
} | } | ||||
static void | |||||
spa_delete_by_guid(uint64_t guid) | |||||
{ | |||||
spa_t *spa; | |||||
if (spa = spa_find_by_guid(guid)) { | |||||
STAILQ_REMOVE(&zfs_pools, spa, spa, spa_link); | |||||
free(spa); | |||||
} | |||||
} | |||||
static const char * | static const char * | ||||
state_name(vdev_state_t state) | state_name(vdev_state_t state) | ||||
{ | { | ||||
static const char* names[] = { | static const char* names[] = { | ||||
"UNKNOWN", | "UNKNOWN", | ||||
"CLOSED", | "CLOSED", | ||||
"OFFLINE", | "OFFLINE", | ||||
"REMOVED", | "REMOVED", | ||||
▲ Show 20 Lines • Show All 147 Lines • ▼ Show 20 Lines | if (l < VDEV_LABELS / 2) | ||||
label_offset = 0; | label_offset = 0; | ||||
else | else | ||||
label_offset = psize - VDEV_LABELS * sizeof (vdev_label_t); | label_offset = psize - VDEV_LABELS * sizeof (vdev_label_t); | ||||
return (offset + l * sizeof (vdev_label_t) + label_offset); | return (offset + l * sizeof (vdev_label_t) + label_offset); | ||||
} | } | ||||
static int | static int | ||||
vdev_probe(vdev_phys_read_t *_read, void *read_priv, spa_t **spap) | vdev_probe_try(vdev_phys_read_t *_read, void *read_priv, spa_t **spap, int *tried_labels) | ||||
{ | { | ||||
vdev_t vtmp; | vdev_t vtmp; | ||||
vdev_phys_t *vdev_label = (vdev_phys_t *) zap_scratch; | vdev_phys_t *vdev_label = (vdev_phys_t *) zap_scratch; | ||||
vdev_phys_t *tmp_label; | vdev_phys_t *tmp_label; | ||||
spa_t *spa; | spa_t *spa; | ||||
vdev_t *vdev, *top_vdev, *pool_vdev; | vdev_t *vdev, *top_vdev, *pool_vdev; | ||||
off_t off; | off_t off; | ||||
blkptr_t bp; | blkptr_t bp; | ||||
const unsigned char *nvlist = NULL; | const unsigned char *nvlist = NULL; | ||||
uint64_t val; | uint64_t val; | ||||
uint64_t guid; | uint64_t guid; | ||||
uint64_t best_txg = 0; | uint64_t best_txg = 0; | ||||
uint64_t pool_txg, pool_guid; | uint64_t pool_txg, pool_guid; | ||||
uint64_t psize; | uint64_t psize; | ||||
const char *pool_name; | const char *pool_name; | ||||
const unsigned char *vdevs; | const unsigned char *vdevs; | ||||
const unsigned char *features; | const unsigned char *features; | ||||
int i, l, rc, is_newer; | int i, l, rc, is_newer; | ||||
char *upbuf; | char *upbuf; | ||||
const struct uberblock *up; | const struct uberblock *up; | ||||
int best_label = 0; | |||||
/* | /* | ||||
* 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_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) { | ||||
*tried_labels = ALL_LABELS_INVALID; | |||||
return (EIO); | return (EIO); | ||||
} | |||||
tmp_label = zfs_alloc(sizeof(vdev_phys_t)); | tmp_label = zfs_alloc(sizeof(vdev_phys_t)); | ||||
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); | ||||
Show All 10 Lines | for (l = 0; l < VDEV_LABELS; l++) { | ||||
if (tmp_label->vp_nvlist[0] != NV_ENCODE_XDR) | if (tmp_label->vp_nvlist[0] != NV_ENCODE_XDR) | ||||
continue; | continue; | ||||
nvlist = (const unsigned char *) tmp_label->vp_nvlist + 4; | nvlist = (const unsigned char *) tmp_label->vp_nvlist + 4; | ||||
if (nvlist_find(nvlist, ZPOOL_CONFIG_POOL_TXG, | if (nvlist_find(nvlist, ZPOOL_CONFIG_POOL_TXG, | ||||
DATA_TYPE_UINT64, NULL, &pool_txg) != 0) | DATA_TYPE_UINT64, NULL, &pool_txg) != 0) | ||||
continue; | continue; | ||||
if (best_txg <= pool_txg) { | if (best_txg <= pool_txg && (*tried_labels & (1 << l)) == 0) { | ||||
printf("ZFS: found label %d was written in newer txg\n", l); | |||||
best_txg = pool_txg; | best_txg = pool_txg; | ||||
best_label = l; | |||||
memcpy(vdev_label, tmp_label, sizeof (vdev_phys_t)); | memcpy(vdev_label, tmp_label, sizeof (vdev_phys_t)); | ||||
} | } | ||||
} | } | ||||
*tried_labels |= 1 << best_label; | |||||
zfs_free(tmp_label, sizeof (vdev_phys_t)); | zfs_free(tmp_label, sizeof (vdev_phys_t)); | ||||
if (best_txg == 0) | if (best_txg == 0) { | ||||
*tried_labels = ALL_LABELS_INVALID; | |||||
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; | ||||
if (nvlist_find(nvlist, ZPOOL_CONFIG_VERSION, DATA_TYPE_UINT64, | if (nvlist_find(nvlist, ZPOOL_CONFIG_VERSION, DATA_TYPE_UINT64, | ||||
NULL, &val) != 0) { | NULL, &val) != 0) { | ||||
▲ Show 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | vdev_probe_try(vdev_phys_read_t *_read, void *read_priv, spa_t **spap, int *tried_labels) | ||||
/* | /* | ||||
* Get the vdev tree and create our in-core copy of it. | * Get the vdev tree and create our in-core copy of it. | ||||
* If we already have a vdev with this guid, this must | * If we already have a vdev with this guid, this must | ||||
* be some kind of alias (overlapping slices, dangerously dedicated | * be some kind of alias (overlapping slices, dangerously dedicated | ||||
* disks etc). | * disks etc). | ||||
*/ | */ | ||||
if (nvlist_find(nvlist, ZPOOL_CONFIG_GUID, DATA_TYPE_UINT64, | if (nvlist_find(nvlist, ZPOOL_CONFIG_GUID, DATA_TYPE_UINT64, | ||||
NULL, &guid) != 0) { | NULL, &guid) != 0) { | ||||
return (EIO); | rc = EIO; | ||||
goto err_delete_spa; | |||||
} | } | ||||
vdev = vdev_find(guid); | vdev = vdev_find(guid); | ||||
if (vdev && vdev->v_phys_read) /* Has this vdev already been inited? */ | if (vdev && vdev->v_phys_read) { /* Has this vdev already been inited? */ | ||||
return (EIO); | rc = EIO; | ||||
goto err_delete_spa; | |||||
} | |||||
if (nvlist_find(nvlist, ZPOOL_CONFIG_VDEV_TREE, DATA_TYPE_NVLIST, | if (nvlist_find(nvlist, ZPOOL_CONFIG_VDEV_TREE, DATA_TYPE_NVLIST, | ||||
NULL, &vdevs)) { | NULL, &vdevs)) { | ||||
return (EIO); | rc = EIO; | ||||
goto err_delete_spa; | |||||
} | } | ||||
rc = vdev_init_from_nvlist(vdevs, NULL, &top_vdev, is_newer); | rc = vdev_init_from_nvlist(vdevs, NULL, &top_vdev, is_newer); | ||||
if (rc != 0) | if (rc != 0) | ||||
return (rc); | goto err_delete_vdev; | ||||
/* | /* | ||||
* Add the toplevel vdev to the pool if its not already there. | * Add the toplevel vdev to the pool if its not already there. | ||||
*/ | */ | ||||
STAILQ_FOREACH(pool_vdev, &spa->spa_vdevs, v_childlink) | STAILQ_FOREACH(pool_vdev, &spa->spa_vdevs, v_childlink) | ||||
if (top_vdev == pool_vdev) | if (top_vdev == pool_vdev) | ||||
break; | break; | ||||
if (!pool_vdev && top_vdev) { | if (!pool_vdev && top_vdev) { | ||||
top_vdev->spa = spa; | top_vdev->spa = spa; | ||||
STAILQ_INSERT_TAIL(&spa->spa_vdevs, top_vdev, v_childlink); | STAILQ_INSERT_TAIL(&spa->spa_vdevs, top_vdev, v_childlink); | ||||
} | } | ||||
/* | /* | ||||
* 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) { | if (vdev) { | ||||
vdev->v_phys_read = _read; | vdev->v_phys_read = _read; | ||||
vdev->v_read_priv = read_priv; | vdev->v_read_priv = read_priv; | ||||
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"); | ||||
return (EIO); | rc = EIO; | ||||
goto err_delete_vdev; | |||||
} | } | ||||
/* | /* | ||||
* Re-evaluate top-level vdev state. | * Re-evaluate top-level vdev state. | ||||
*/ | */ | ||||
vdev_set_state(top_vdev); | vdev_set_state(top_vdev); | ||||
/* | /* | ||||
Show All 27 Lines | for (i = 0; i < VDEV_UBERBLOCK_COUNT(vdev); i++) { | ||||
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)); | zfs_free(upbuf, VDEV_UBERBLOCK_SIZE(vdev)); | ||||
/* check uberblock and return as soon as a valid dva is found */ | |||||
for (i = 0; i < SPA_DVAS_PER_BP; i++) { | |||||
const dva_t *const dva = &spa->spa_uberblock.ub_rootbp.blk_dva[i]; | |||||
if (dva->dva_word[0] || dva->dva_word[1]) { | |||||
vdev->spa = spa; | vdev->spa = spa; | ||||
if (spap != NULL) | if (spap != NULL) | ||||
*spap = spa; | *spap = spa; | ||||
return (0); | return (0); | ||||
} | |||||
} | |||||
/* no uberblock with valid dva found */ | |||||
rc = EIO; | |||||
err_delete_vdev: | |||||
vdev_delete_by_guid(guid); | |||||
err_delete_spa: | |||||
spa_delete_by_guid(pool_guid); | |||||
return (rc); | |||||
} | |||||
static int | |||||
vdev_probe(vdev_phys_read_t *_read, void *read_priv, spa_t **spap) | |||||
{ | |||||
int tried_labels = 0; // this bitmask encodes tried labels | |||||
int err; | |||||
do { | |||||
err = vdev_probe_try(_read, read_priv, spap, &tried_labels); | |||||
} while (err && (tried_labels != ALL_LABELS_INVALID)); | |||||
return (err); | |||||
} | } | ||||
static int | static int | ||||
ilog2(int n) | ilog2(int n) | ||||
{ | { | ||||
int v; | int v; | ||||
for (v = 0; v < 32; v++) | for (v = 0; v < 32; v++) | ||||
▲ Show 20 Lines • Show All 1,366 Lines • Show Last 20 Lines |