Skip to content

Instantly share code, notes, and snippets.

@jjwhitney
Created October 22, 2014 10:59
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jjwhitney/baaa63144da89726e482 to your computer and use it in GitHub Desktop.
Save jjwhitney/baaa63144da89726e482 to your computer and use it in GitHub Desktop.
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
Copy link

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?

@brunonizio
Copy link

im looking to use this..but im completly lost... really need help, my mail brunonizio@gmail.com

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment