Changeset View
Changeset View
Standalone View
Standalone View
stand/libsa/zfs/zfs.c
Show First 20 Lines • Show All 477 Lines • ▼ Show 20 Lines | vdev_read(vdev_t *vdev, void *priv, off_t offset, void *buf, size_t bytes) | ||||
ret = 0; | ret = 0; | ||||
error: | error: | ||||
free(bouncebuf); | free(bouncebuf); | ||||
return (ret); | return (ret); | ||||
} | } | ||||
static int | static int | ||||
vdev_write(vdev_t *vdev __unused, void *priv, off_t offset, void *buf, | vdev_write(vdev_t *vdev, off_t offset, void *buf, size_t bytes) | ||||
size_t bytes) | |||||
{ | { | ||||
int fd, ret; | int fd, ret; | ||||
size_t head, tail, total_size, full_sec_size; | size_t head, tail, total_size, full_sec_size; | ||||
unsigned secsz, do_tail_write; | unsigned secsz, do_tail_write; | ||||
off_t start_sec; | off_t start_sec; | ||||
ssize_t res; | ssize_t res; | ||||
char *outbuf, *bouncebuf; | char *outbuf, *bouncebuf; | ||||
fd = (uintptr_t)priv; | fd = (uintptr_t)vdev->v_priv; | ||||
outbuf = (char *) buf; | outbuf = (char *)buf; | ||||
bouncebuf = NULL; | bouncebuf = NULL; | ||||
ret = ioctl(fd, DIOCGSECTORSIZE, &secsz); | ret = ioctl(fd, DIOCGSECTORSIZE, &secsz); | ||||
if (ret != 0) | if (ret != 0) | ||||
return (ret); | return (ret); | ||||
start_sec = offset / secsz; | start_sec = offset / secsz; | ||||
head = offset % secsz; | head = offset % secsz; | ||||
▲ Show 20 Lines • Show All 84 Lines • ▼ Show 20 Lines | vdev_write(vdev_t *vdev, off_t offset, void *buf, size_t bytes) | ||||
} | } | ||||
ret = 0; | ret = 0; | ||||
error: | error: | ||||
free(bouncebuf); | free(bouncebuf); | ||||
return (ret); | return (ret); | ||||
} | } | ||||
static void | |||||
vdev_clear_pad2(vdev_t *vdev) | |||||
{ | |||||
vdev_t *kid; | |||||
vdev_boot_envblock_t *be; | |||||
off_t off = offsetof(vdev_label_t, vl_be); | |||||
zio_checksum_info_t *ci; | |||||
zio_cksum_t cksum; | |||||
STAILQ_FOREACH(kid, &vdev->v_children, v_childlink) { | |||||
if (kid->v_state != VDEV_STATE_HEALTHY) | |||||
continue; | |||||
vdev_clear_pad2(kid); | |||||
} | |||||
if (!STAILQ_EMPTY(&vdev->v_children)) | |||||
return; | |||||
be = calloc(1, sizeof (*be)); | |||||
if (be == NULL) { | |||||
printf("failed to clear be area: out of memory\n"); | |||||
return; | |||||
} | |||||
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; | |||||
if (vdev_write(vdev, vdev->v_read_priv, off, be, VDEV_PAD_SIZE)) { | |||||
printf("failed to clear be area of primary vdev: %d\n", | |||||
errno); | |||||
} | |||||
free(be); | |||||
} | |||||
/* | |||||
* Read the next boot command from pad2. | |||||
* If any instance of pad2 is set to empty string, or the returned string | |||||
* values are not the same, we consider next boot not to be set. | |||||
*/ | |||||
static char * | |||||
vdev_read_pad2(vdev_t *vdev) | |||||
{ | |||||
vdev_t *kid; | |||||
char *tmp, *result = NULL; | |||||
vdev_boot_envblock_t *be; | |||||
off_t off = offsetof(vdev_label_t, vl_be); | |||||
STAILQ_FOREACH(kid, &vdev->v_children, v_childlink) { | |||||
if (kid->v_state != VDEV_STATE_HEALTHY) | |||||
continue; | |||||
tmp = vdev_read_pad2(kid); | |||||
if (tmp == NULL) | |||||
continue; | |||||
/* The next boot is not set, we are done. */ | |||||
if (*tmp == '\0') { | |||||
free(result); | |||||
return (tmp); | |||||
} | |||||
if (result == NULL) { | |||||
result = tmp; | |||||
continue; | |||||
} | |||||
/* Are the next boot strings different? */ | |||||
if (strcmp(result, tmp) != 0) { | |||||
free(tmp); | |||||
*result = '\0'; | |||||
break; | |||||
} | |||||
free(tmp); | |||||
} | |||||
if (result != NULL) | |||||
return (result); | |||||
be = malloc(sizeof (*be)); | |||||
if (be == NULL) | |||||
return (NULL); | |||||
if (vdev_read(vdev, vdev->v_read_priv, off, be, sizeof (*be))) { | |||||
return (NULL); | |||||
} | |||||
switch (be->vbe_version) { | |||||
case VB_RAW: | |||||
case VB_NVLIST: | |||||
result = strdup(be->vbe_bootenv); | |||||
default: | |||||
/* Backward compatibility with initial nextboot feaure. */ | |||||
result = strdup((char *)be); | |||||
} | |||||
return (result); | |||||
} | |||||
static int | static int | ||||
zfs_dev_init(void) | zfs_dev_init(void) | ||||
{ | { | ||||
spa_t *spa; | spa_t *spa; | ||||
spa_t *next; | spa_t *next; | ||||
spa_t *prev; | spa_t *prev; | ||||
zfs_init(); | zfs_init(); | ||||
Show All 36 Lines | |||||
static int | static int | ||||
zfs_probe(int fd, uint64_t *pool_guid) | zfs_probe(int fd, uint64_t *pool_guid) | ||||
{ | { | ||||
spa_t *spa; | spa_t *spa; | ||||
int ret; | int ret; | ||||
spa = NULL; | spa = NULL; | ||||
ret = vdev_probe(vdev_read, (void *)(uintptr_t)fd, &spa); | ret = vdev_probe(vdev_read, vdev_write, (void *)(uintptr_t)fd, &spa); | ||||
if (ret == 0 && pool_guid != NULL) | if (ret == 0 && pool_guid != NULL) | ||||
*pool_guid = spa->spa_guid; | *pool_guid = spa->spa_guid; | ||||
return (ret); | return (ret); | ||||
} | } | ||||
static int | static int | ||||
zfs_probe_partition(void *arg, const char *partname, | zfs_probe_partition(void *arg, const char *partname, | ||||
const struct ptable_entry *part) | const struct ptable_entry *part) | ||||
Show All 36 Lines | |||||
int | int | ||||
zfs_nextboot(void *vdev, char *buf, size_t size) | zfs_nextboot(void *vdev, char *buf, size_t size) | ||||
{ | { | ||||
struct zfs_devdesc *dev = (struct zfs_devdesc *)vdev; | struct zfs_devdesc *dev = (struct zfs_devdesc *)vdev; | ||||
spa_t *spa; | spa_t *spa; | ||||
vdev_t *vd; | vdev_t *vd; | ||||
char *result = NULL; | char *result = NULL; | ||||
nvlist_t *benv = NULL; | |||||
int result_size, rv; | |||||
if (dev->dd.d_dev->dv_type != DEVT_ZFS) | if (dev->dd.d_dev->dv_type != DEVT_ZFS) | ||||
return (1); | return (1); | ||||
if (dev->pool_guid == 0) | if (dev->pool_guid == 0) | ||||
spa = STAILQ_FIRST(&zfs_pools); | spa = STAILQ_FIRST(&zfs_pools); | ||||
else | else | ||||
spa = spa_find_by_guid(dev->pool_guid); | spa = spa_find_by_guid(dev->pool_guid); | ||||
if (spa == NULL) { | if (spa == NULL) { | ||||
printf("ZFS: can't find pool by guid\n"); | printf("ZFS: can't find pool by guid\n"); | ||||
return (1); | return (1); | ||||
} | } | ||||
STAILQ_FOREACH(vd, &spa->spa_root_vdev->v_children, v_childlink) { | STAILQ_FOREACH(vd, &spa->spa_root_vdev->v_children, v_childlink) { | ||||
char *tmp = vdev_read_pad2(vd); | benv = vdev_read_bootenv(vd); | ||||
/* Continue on error. */ | if (benv != NULL) | ||||
if (tmp == NULL) | break; | ||||
continue; | } | ||||
/* Nextboot is not set. */ | spa->spa_bootenv = benv; | ||||
if (*tmp == '\0') { | if (benv == NULL) | ||||
free(result); | |||||
free(tmp); | |||||
return (1); | return (1); | ||||
if ((rv = nvlist_find(benv, "command", DATA_TYPE_STRING, NULL, | |||||
&result, &result_size)) == 0) { | |||||
if (result_size == 0) { | |||||
/* ignore empty string */ | |||||
rv = ENOENT; | |||||
} else { | |||||
size = MIN(result_size + 1, size); | |||||
strlcpy(buf, result, size); | |||||
} | } | ||||
if (result == NULL) { | (void) nvlist_remove(benv, "command", DATA_TYPE_STRING); | ||||
result = tmp; | |||||
continue; | |||||
} | } | ||||
free(tmp); | |||||
} | |||||
if (result == NULL) | |||||
return (1); | |||||
STAILQ_FOREACH(vd, &spa->spa_root_vdev->v_children, v_childlink) { | STAILQ_FOREACH(vd, &spa->spa_root_vdev->v_children, v_childlink) { | ||||
vdev_clear_pad2(vd); | vdev_write_bootenv(vd, benv); | ||||
} | } | ||||
strlcpy(buf, result, size); | return (rv); | ||||
free(result); | |||||
return (0); | |||||
} | } | ||||
int | int | ||||
zfs_probe_dev(const char *devname, uint64_t *pool_guid) | zfs_probe_dev(const char *devname, uint64_t *pool_guid) | ||||
{ | { | ||||
struct disk_devdesc *dev; | struct disk_devdesc *dev; | ||||
struct ptable *table; | struct ptable *table; | ||||
struct zfs_probe_args pa; | struct zfs_probe_args pa; | ||||
▲ Show 20 Lines • Show All 508 Lines • Show Last 20 Lines |