Recover a ZFS pool hidden on a detached device
Originally written by Jeff Bonwick (http://www.mail-archive.com/zfs-discuss@opensolaris.org/msg15748.html), and updated by James Lee to work with modern ZFS libs (https://www.mail-archive.com/zfs-discuss@opensolaris.org/msg47316.html), I was able to compile this life-saving utility in Ubuntu 14.04 and have verified that it works. (I'm using ZFSonLinux.) | |
Download the ZFSonLinux tarball and replace the cmd/zhack/zhack.c file with "labelfix.c". Note that zhack is just a simple utility that we're replacing so that we don't have to setup the build environment. (It's hard, so we'll reuse the good work of the ZFSonLinux people.) | |
Run "./configure; make" and if all goes well then the zfs tools will be built, except for zhack, which we replaced. Run that with the device path to recover your data. | |
If you want to be super-careful and not tamper with your disk, you can clone it and run the utility on your clone. Or, create an overlay as described in this page: https://raid.wiki.kernel.org/index.php/Recovering_a_failed_software_RAID#Making_the_harddisks_read-only_using_an_overlay_file |
#include <devid.h> | |
#include <dirent.h> | |
#include <errno.h> | |
#include <libintl.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <sys/stat.h> | |
#include <unistd.h> | |
#include <fcntl.h> | |
#include <stddef.h> | |
#include <sys/vdev_impl.h> | |
/* | |
* Write a label block with a ZBT checksum. | |
*/ | |
static void | |
label_write(int fd, uint64_t offset, uint64_t size, void *buf) | |
{ | |
zio_eck_t *zbt, zbt_orig; | |
zio_cksum_t zc; | |
zbt = (zio_eck_t *)((char *)buf + size) - 1; | |
zbt_orig = *zbt; | |
ZIO_SET_CHECKSUM(&zbt->zec_cksum, offset, 0, 0, 0); | |
zio_checksum_SHA256(buf, size, &zc); | |
zbt->zec_cksum = zc; | |
VERIFY(pwrite64(fd, buf, size, offset) == size); | |
*zbt = zbt_orig; | |
} | |
int | |
main(int argc, char **argv) | |
{ | |
int fd; | |
vdev_label_t vl; | |
nvlist_t *config; | |
uberblock_t *ub = (uberblock_t *)vl.vl_uberblock; | |
uint64_t txg; | |
char *buf; | |
size_t buflen; | |
VERIFY(argc == 2); | |
VERIFY((fd = open(argv[1], O_RDWR)) != -1); | |
VERIFY(pread64(fd, &vl, sizeof (vdev_label_t), 0) == | |
sizeof (vdev_label_t)); | |
VERIFY(nvlist_unpack(vl.vl_vdev_phys.vp_nvlist, | |
sizeof (vl.vl_vdev_phys.vp_nvlist), &config, 0) == 0); | |
VERIFY(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_TXG, &txg) == 0); | |
VERIFY(txg == 0); | |
VERIFY(ub->ub_txg == 0); | |
VERIFY(ub->ub_rootbp.blk_birth != 0); | |
txg = ub->ub_rootbp.blk_birth; | |
ub->ub_txg = txg; | |
VERIFY(nvlist_remove_all(config, ZPOOL_CONFIG_POOL_TXG) == 0); | |
VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_POOL_TXG, txg) == 0); | |
buf = vl.vl_vdev_phys.vp_nvlist; | |
buflen = sizeof (vl.vl_vdev_phys.vp_nvlist); | |
VERIFY(nvlist_pack(config, &buf, &buflen, NV_ENCODE_XDR, 0) == 0); | |
label_write(fd, offsetof(vdev_label_t, vl_uberblock), | |
1ULL << UBERBLOCK_SHIFT, ub); | |
label_write(fd, offsetof(vdev_label_t, vl_vdev_phys), | |
VDEV_PHYS_SIZE, &vl.vl_vdev_phys); | |
fsync(fd); | |
return (0); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This comment has been minimized.
Hi, I just tried to build this and received the following error:
/debian/zfs/cmd/zhack/zhack.c:28: undefined reference to
zio_checksum_SHA256'`am i doing something wrong or does it need to be updated?