Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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);
}
@2600box

This comment has been minimized.

Copy link

@2600box 2600box commented Dec 14, 2017

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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.