Как ZFS хранит данные

Zfs является достаточно популярной файловой системой для долговременного хранения данных. Кроме того она обеспечивает целостность записанных данных, сохраняя вместе с данными и их контрольные суммы. Механизм контрольных сумм позволяет выявить, и при наличии избыточности восстановить, поврежденные данные.

В данной статье на практическом примере производится разбор, как и куда zfs сохраняет данные.

Непосредственно для доступа к данным мы не будем использовать утилиту zdb, а попробуем с помощью radare2 посмотреть непосредственно на байты которые записаны на диске.

О zfs


Zfs(Zettabyte File System) это COW(copy on write) файловая система, созданная в Sun для операционной системы Solaris.

Одним из основных преимуществ этой файловой системы считается использование контрольных сумм не только для метаданных но и для данных пользователя.

Дисковая структура zfs


Для более подробного разбора компонентов zfs рекомендуется обратится к официальной документации ZFS On-Disk Specification от Sun.

Виртуальные устройства


Пул zfs состоит из виртуальных устройств (далее vdev). Более детальная информация нам сейчас не нужна, отметим только что vdev существует два вида логическое и физическое виртуальное устройство.

Метка


На каждом физическом виртуальном устройстве хранится четыре метки (на рисунке L0, L1, L2 и L3).

Метка

Boot-блок


Непосредственно после меток L0 и L1 выделено 3,5 Мб пространства, зарезервированного для будущего использования.

Точка отсчета uberblock


В отличии от остальных объектов zfs положение меток строго фиксировано и обновление их происходит в два шага, сначала обновляются метки L0 и L2 затем L1 и L3. Для данной статьи из данных записанных в метке нас будет интересовать только uberblock, рассмотрим его подробнее.

Uberblock


Uberblock представлен следующей структурой:

struct uberblock {
	uint64_t	ub_magic;	/* UBERBLOCK_MAGIC		*/
	uint64_t	ub_version;	/* SPA_VERSION			*/
	uint64_t	ub_txg;		/* txg of last sync		*/
	uint64_t	ub_guid_sum;	/* sum of all vdev guids	*/
	uint64_t	ub_timestamp;	/* UTC time of last sync	*/
	blkptr_t	ub_rootbp;	/* MOS objset_phys_t		*/
	/* highest SPA_VERSION supported by software that wrote this txg */
	uint64_t	ub_software_version;
};

Опишем некоторые поля:

ub_txg
Номер транзакции
ub_timestamp
Содержит время записи uberblock (в UTC формате)
ub_rootbp
Ссылка на Meta Object Set (В zfs ссылки на блоки представлены структурой blkptr_t, будет описана ниже).

Ссылки на блоки (blkptr_t)


Ссылки на блоки представляют собой следующую структуру:

typedef struct blkptr {
	dva_t		blk_dva[SPA_DVAS_PER_BP]; /* Data Virtual Addresses */
	uint64_t	blk_prop;	/* size, compression, type, etc	    */
	uint64_t	blk_pad[2];	/* Extra space for the future	    */
	uint64_t	blk_phys_birth;	/* txg when block was allocated	    */
	uint64_t	blk_birth;	/* transaction group at birth	    */
	uint64_t	blk_fill;	/* fill count			    */
	zio_cksum_t	blk_cksum;	/* 256-bit checksum		    */
} blkptr_t;
/*
 * All SPA data is represented by 128-bit data virtual addresses (DVAs).
 * The members of the dva_t should be considered opaque outside the SPA.
 */
typedef struct dva {
	uint64_t	dva_word[2];
} dva_t;
/*
 * Each block has a 256-bit checksum -- strong enough for cryptographic hashes.
 */
typedef struct zio_cksum {
	uint64_t	zc_word[4];
} zio_cksum_t;

Если представить в виде массива байт то получится следующее изображение

image

Наиболее важные поля
dva_t
Виртуальный адрес данных. В поле offset хранится смещение в секторах (512 байт).
На изображении выше это строки 0~5.
blk_prop
В соответствующих полях записан тип, размер, уровень косвенности блока и т.п.
type преобразеется в перечесление dmu_object_type. А поля cksum и comp в zio_checksum и zio_compress соответственно.

typedef enum dmu_object_type {
	DMU_OT_NONE,
	/* general: */
	DMU_OT_OBJECT_DIRECTORY,	/* ZAP */
	DMU_OT_OBJECT_ARRAY,		/* UINT64 */
	DMU_OT_PACKED_NVLIST,		/* UINT8 (XDR by nvlist_pack/unpack) */
	DMU_OT_PACKED_NVLIST_SIZE,	/* UINT64 */
	DMU_OT_BPOBJ,			/* UINT64 */
	DMU_OT_BPOBJ_HDR,		/* UINT64 */
	/* spa: */
	DMU_OT_SPACE_MAP_HEADER,	/* UINT64 */
	DMU_OT_SPACE_MAP,		/* UINT64 */
	/* zil: */
	DMU_OT_INTENT_LOG,		/* UINT64 */
	/* dmu: */
	DMU_OT_DNODE,			/* DNODE */
	DMU_OT_OBJSET,			/* OBJSET */
	/* dsl: */
	DMU_OT_DSL_DIR,			/* UINT64 */
	DMU_OT_DSL_DIR_CHILD_MAP,	/* ZAP */
	DMU_OT_DSL_DS_SNAP_MAP,		/* ZAP */
	DMU_OT_DSL_PROPS,		/* ZAP */
	DMU_OT_DSL_DATASET,		/* UINT64 */
	/* zpl: */
	DMU_OT_ZNODE,			/* ZNODE */
	DMU_OT_OLDACL,			/* Old ACL */
	DMU_OT_PLAIN_FILE_CONTENTS,	/* UINT8 */
	DMU_OT_DIRECTORY_CONTENTS,	/* ZAP */
	DMU_OT_MASTER_NODE,		/* ZAP */
	DMU_OT_UNLINKED_SET,		/* ZAP */
	/* zvol: */
	DMU_OT_ZVOL,			/* UINT8 */
	DMU_OT_ZVOL_PROP,		/* ZAP */
	/* other; for testing only! */
	DMU_OT_PLAIN_OTHER,		/* UINT8 */
	DMU_OT_UINT64_OTHER,		/* UINT64 */
	DMU_OT_ZAP_OTHER,		/* ZAP */
	/* new object types: */
	DMU_OT_ERROR_LOG,		/* ZAP */
	DMU_OT_SPA_HISTORY,		/* UINT8 */
	DMU_OT_SPA_HISTORY_OFFSETS,	/* spa_his_phys_t */
	DMU_OT_POOL_PROPS,		/* ZAP */
	DMU_OT_DSL_PERMS,		/* ZAP */
	DMU_OT_ACL,			/* ACL */
	DMU_OT_SYSACL,			/* SYSACL */
	DMU_OT_FUID,			/* FUID table (Packed NVLIST UINT8) */
	DMU_OT_FUID_SIZE,		/* FUID table size UINT64 */
	DMU_OT_NEXT_CLONES,		/* ZAP */
	DMU_OT_SCAN_QUEUE,		/* ZAP */
	DMU_OT_USERGROUP_USED,		/* ZAP */
	DMU_OT_USERGROUP_QUOTA,		/* ZAP */
	DMU_OT_USERREFS,		/* ZAP */
	DMU_OT_DDT_ZAP,			/* ZAP */
	DMU_OT_DDT_STATS,		/* ZAP */
	DMU_OT_SA,			/* System attr */
	DMU_OT_SA_MASTER_NODE,		/* ZAP */
	DMU_OT_SA_ATTR_REGISTRATION,	/* ZAP */
	DMU_OT_SA_ATTR_LAYOUTS,		/* ZAP */
	DMU_OT_SCAN_XLATE,		/* ZAP */
	DMU_OT_DEDUP,			/* fake dedup BP from ddt_bp_create() */
	DMU_OT_DEADLIST,		/* ZAP */
	DMU_OT_DEADLIST_HDR,		/* UINT64 */
	DMU_OT_DSL_CLONES,		/* ZAP */
	DMU_OT_BPOBJ_SUBOBJ,		/* UINT64 */
	/*
	 * Do not allocate new object types here. Doing so makes the on-disk
	 * format incompatible with any other format that uses the same object
	 * type number.
	 *
	 * When creating an object which does not have one of the above types
	 * use the DMU_OTN_* type with the correct byteswap and metadata
	 * values.
	 *
	 * The DMU_OTN_* types do not have entries in the dmu_ot table,
	 * use the DMU_OT_IS_METDATA() and DMU_OT_BYTESWAP() macros instead
	 * of indexing into dmu_ot directly (this works for both DMU_OT_* types
	 * and DMU_OTN_* types).
	 */
	DMU_OT_NUMTYPES,

	/*
	 * Names for valid types declared with DMU_OT().
	 */
	DMU_OTN_UINT8_DATA = DMU_OT(DMU_BSWAP_UINT8, B_FALSE),
	DMU_OTN_UINT8_METADATA = DMU_OT(DMU_BSWAP_UINT8, B_TRUE),
	DMU_OTN_UINT16_DATA = DMU_OT(DMU_BSWAP_UINT16, B_FALSE),
	DMU_OTN_UINT16_METADATA = DMU_OT(DMU_BSWAP_UINT16, B_TRUE),
	DMU_OTN_UINT32_DATA = DMU_OT(DMU_BSWAP_UINT32, B_FALSE),
	DMU_OTN_UINT32_METADATA = DMU_OT(DMU_BSWAP_UINT32, B_TRUE),
	DMU_OTN_UINT64_DATA = DMU_OT(DMU_BSWAP_UINT64, B_FALSE),
	DMU_OTN_UINT64_METADATA = DMU_OT(DMU_BSWAP_UINT64, B_TRUE),
	DMU_OTN_ZAP_DATA = DMU_OT(DMU_BSWAP_ZAP, B_FALSE),
	DMU_OTN_ZAP_METADATA = DMU_OT(DMU_BSWAP_ZAP, B_TRUE),
} dmu_object_type_t;

Перечисления zio_checksum и zio_compress представлены ниже.

enum zio_checksum {
	ZIO_CHECKSUM_INHERIT = 0,
	ZIO_CHECKSUM_ON,
	ZIO_CHECKSUM_OFF,
	ZIO_CHECKSUM_LABEL,
	ZIO_CHECKSUM_GANG_HEADER,
	ZIO_CHECKSUM_ZILOG,
	ZIO_CHECKSUM_FLETCHER_2,
	ZIO_CHECKSUM_FLETCHER_4,
	ZIO_CHECKSUM_SHA256,
	ZIO_CHECKSUM_ZILOG2,
	ZIO_CHECKSUM_FUNCTIONS
};

enum zio_compress {
	ZIO_COMPRESS_INHERIT = 0,
	ZIO_COMPRESS_ON,
	ZIO_COMPRESS_OFF,
	ZIO_COMPRESS_LZJB,
	ZIO_COMPRESS_EMPTY,
	ZIO_COMPRESS_GZIP_1,
	ZIO_COMPRESS_GZIP_2,
	ZIO_COMPRESS_GZIP_3,
	ZIO_COMPRESS_GZIP_4,
	ZIO_COMPRESS_GZIP_5,
	ZIO_COMPRESS_GZIP_6,
	ZIO_COMPRESS_GZIP_7,
	ZIO_COMPRESS_GZIP_8,
	ZIO_COMPRESS_GZIP_9,
	ZIO_COMPRESS_ZLE,
	ZIO_COMPRESS_LZ4,
	ZIO_COMPRESS_FUNCTIONS
};

Объект (dnode)


Исключая uberblock все остальные сущности (метаданные и пользовательские данные) представлены в виде объектов. В перечислении dmu_object_type перечислены возможные типы объектов.

Объект описывается структурой dnode_phys, представленой ниже:

typedef struct dnode_phys {
	uint8_t dn_type;		/* dmu_object_type_t */
	uint8_t dn_indblkshift;		/* ln2(indirect block size) */
	uint8_t dn_nlevels;		/* 1=dn_blkptr->data blocks */
	uint8_t dn_nblkptr;		/* length of dn_blkptr */
	uint8_t dn_bonustype;		/* type of data in bonus buffer */
	uint8_t	dn_checksum;		/* ZIO_CHECKSUM type */
	uint8_t	dn_compress;		/* ZIO_COMPRESS type */
	uint8_t dn_flags;		/* DNODE_FLAG_* */
	uint16_t dn_datablkszsec;	/* data block size in 512b sectors */
	uint16_t dn_bonuslen;		/* length of dn_bonus */
	uint8_t dn_pad2[4];
	/* accounting is protected by dn_dirty_mtx */
	uint64_t dn_maxblkid;		/* largest allocated block ID */
	uint64_t dn_used;		/* bytes (or sectors) of disk space */
	uint64_t dn_pad3[4];
	union {
		blkptr_t dn_blkptr[1+DN_MAX_BONUSLEN/sizeof (blkptr_t)];
		struct {
			blkptr_t __dn_ignore1;
			uint8_t dn_bonus[DN_MAX_BONUSLEN];
		};
		struct {
			blkptr_t __dn_ignore2;
			uint8_t __dn_ignore3[DN_MAX_BONUSLEN-sizeof (blkptr_t)];
			blkptr_t dn_spill;
		};
	};
} dnode_phys_t;
typedef struct zil_header {
	uint64_t zh_claim_txg;	/* txg in which log blocks were claimed */
	uint64_t zh_replay_seq;	/* highest replayed sequence number */
	blkptr_t zh_log;	/* log chain */
	uint64_t zh_claim_blk_seq; /* highest claimed block sequence number */
	uint64_t zh_flags;	/* header flags */
	uint64_t zh_claim_lr_seq; /* highest claimed lr sequence number */
	uint64_t zh_pad[3];
} zil_header_t;


Набор объектов


Объекты zfs могут группироваться в так называемые наборы объектов (objset), и представлены следующими типами:

typedef enum dmu_objset_type {
	DMU_OST_NONE,
	DMU_OST_META,			/* MOS */
	DMU_OST_ZFS,			/* Dataset
	DMU_OST_ZVOL,			/* Блочное устройство zfs (vol)
	DMU_OST_OTHER,			/* For testing only! */
	DMU_OST_ANY,			/* Be careful! */
	DMU_OST_NUMTYPES
} dmu_objset_type_t;

Сам набор объектов представлен такой 2-х килобайтной структурой:
typedef struct objset_phys {
	dnode_phys_t os_meta_dnode;
	zil_header_t os_zil_header;
	uint64_t os_type;
	uint64_t os_flags;
	char os_pad[OBJSET_PHYS_SIZE - sizeof (dnode_phys_t)*3 -
	    sizeof (zil_header_t) - sizeof (uint64_t)*2];
	dnode_phys_t os_userused_dnode;
	dnode_phys_t os_groupused_dnode;
} objset_phys_t;

Смотрим на байты


В этой статье мы будем использовать тестовый пул основанный на 101-мегабайтном файле.
Почуму именно 101 Мб? Дело в том что zfs разбивает свободное пространнство (за минусом 4х 256Кб меток и 3.5 мегабайтного boot-блока) на фиксированные блоки (смотри Как работает ZFS — часть 1: vdev). Для 100Мб диска размер блока равняется 16Мб и для 100Мб диска таких блоков поместится только 5 и доступный объем будет равен 80Мб. А вот для 101Мб таких блоков уже вмещается 6 и доступный объем увеличивается до 96Мб. Хотя для данной статьи это не так уж и важно. Но например для 4Тб диска если его полностью отдать zfs то получим «потерянное» пространство размером более 13Гб.

3725 «двоичных» Гб делятся на блоки размером 16Гб каждый и остаток в 13Гб не используется.

Создаем тестовый пул


# dd if=/dev/zero of=/tmp/test_disk bs=1M count=101
101+0 записей получено
101+0 записей отправлено
105906176 байт (106 MB, 101 MiB) скопирован, 0,0847695 s, 1,2 GB/s

#zpool create test -o ashift=9 /tmp/test_disk

Зададим recordsize равным 512 байтам и добавим пару файлов.

# zfs set recordsize=512 test

# dd if=/dev/urandom of=/test/0B bs=1 count=0
0+0 записей получено
0+0 записей отправлено
0 байт скопировано, 0,000171206 s, 0,0 kB/s
# dd if=/dev/urandom of=/test/512B bs=512 count=1
1+0 записей получено
1+0 записей отправлено
512 байт скопировано, 0,000215428 s, 2,4 MB/s
# dd if=/dev/urandom of=/test/513B bs=513 count=1
1+0 записей получено
1+0 записей отправлено
513 байт скопировано, 0,00022484 s, 2,3 MB/s


Посмотрим сколько места файлы занимают на диске

# du -a --block-size=1
1024 ./512B
512 ./0B
2560 ./513B

Из интересного бросается в глаза то что файл нулевого размера занимает 512 байт (сравните с ext3 где он имеет размер ноль байтов). Файл размером 513 байт занимает не 1536 байт а целых 2560 байт, хотя казалось бы должен был бы занять место равное удвоенному размеру recordsize плюс служебная информация. Давайте разбирать почему так происходит.

Находим активный uberblock


Для доступа к сырым данным будем использовать утилиту radare2.
Сортируем по номеру транзакции.

# r2 /tmp/test_disk
[0x00000000]> pf q @@s:0x20010 0x40000 0x400|sort -k2
0x00020010 = (qword)0x0000000000000000

0x00028010 = (qword)0x0000000000000020
0x00028810 = (qword)0x0000000000000022
0x00028c10 = (qword)0x0000000000000023
0x0002e010 = (qword)0x0000000000000038

Активный uberblock находится по адресу 0x0002e000 (от найденого смещения 0x0002e010 отнимаем 16 байт).

Считываем uberblock полностью
[0x0003fc10]> 0x0002e000
[0x0002e000]> pf qqqqt:[128].q ub_magic ub_version ub_txg ub_guid_sum ub_timestamp ub_software_version
ub_magic : 0x0002e000 = (qword)0x0000000000bab10c
ub_version : 0x0002e008 = (qword)0x0000000000001388
ub_txg : 0x0002e010 = (qword)0x0000000000000038
ub_guid_sum : 0x0002e018 = (qword)0x667c11fc34e97151
ub_timestamp : 0x0002e020 = Wed Jan 31 07:29:56 2018
ub_software_version : 0x0002e0a8 = (qword)0x0000000000001388


Получаем ub_rootbp
[0x0002e000]> s+0x28
[0x0002e028]> pf [2]q[2]q[2]qq[2]qqqq[4]q blk_dva_0 blk_dva_1 blk_dva_2 blk_prop blk_pad[2] blk_phys_birth blk_birth blk_fill blk_cksum
blk_dva_0 : 0x0002e028 = (qword)[ 0x0000000000000001, 0x00000000000000ab ]
blk_dva_1 : 0x0002e038 = (qword)[ 0x0000000000000001, 0x00000000000000bc ]
blk_dva_2 : 0x0002e048 = (qword)[ 0x0000000000000001, 0x00000000000000bd ]
blk_prop : 0x0002e058 = (qword)0x800b070f00000003
blk_pad[2] : 0x0002e060 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_phys_birth : 0x0002e070 = (qword)0x0000000000000000
blk_birth : 0x0002e078 = (qword)0x0000000000000038
blk_fill : 0x0002e080 = (qword)0x0000000000000023
blk_cksum : 0x0002e088 = (qword)[ 0x0000000d43174e30, 0x00000513bae6359f, 0x0000ff222817dfe3, 0x00223eedae162ece ]

Для разбора параметров blkptr(blk_prop) использую MS Excell

image

Судя по значению comp (=15) блок сжат lz4 и занимает на диске 512 байт (PSIZE — показывает количество секторов) и после распаковки должен стать 2048 байт(LSIZE).

Сохраним блок в файл
Вычислим смещение от начала диска. Для этого значение поля blk_dva[0].dva_word[1](=0x00000000000000ab) из структуры blkptr умножим на 512(размер сектора) и добавим 0x400000(4Мб — метки L0, L1 и boot-блок). Результат поделим на 512 (работаем блоками по 512 байт).

[0x0002e028]> ?v 0x00000000000000ab<9+0x400000
0x415600
[0x0002e028]> ? 0x415600/512
8363 0x20ab 020253 8.2K 0000:00ab 8363 "\xab " 0b0010000010101011 8363.0 8363.000000f 8363.000000 0t102110202

# dd if=/tmp/test_disk bs=512 skip=8363 count=1 of=/tmp/mos.objset.bin.lz4


Для распаковки используем небольшую программку (исходник в конце статьи).

# zdec mos.objset.bin.lz4 mos.objset.bin 2048
Input: mos.objset.bin.lz4
Output: mos.objset.bin
Out size: 2048
-----------------------------
Input size: 512
Real input size: 187
Decompress result: 0


Посмотрим что хранится в MOS объекте

# r2 mos.objset.bin
[0x00000000]> pf [512].[192].qq[304].[512].[512]. os_type os_flags
os_type : 0x000002c0 = (qword)0x0000000000000001
os_flags : 0x000002c8 = (qword)0x0000000000000000
[0x00000000]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000000 = 0x0a
dn_indblkshift : 0x00000001 = 0x0e
dn_nlevels : 0x00000002 = 0x01
dn_nblkptr : 0x00000003 = 0x03
dn_bonustype : 0x00000004 = 0x00
dn_checksum : 0x00000005 = 0x00
dn_compress : 0x00000006 = 0x00
dn_flags : 0x00000007 = 0x01
dn_datablkszsec : 0x00000008 = 0x0020
dn_bonuslen : 0x0000000a = 0x0000
dn_pad2[4] : 0x0000000c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000010 = (qword)0x0000000000000001
dn_used : 0x00000018 = (qword)0x0000000000001e00
dn_pad3[4] : 0x00000020 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]

Считываем массив blkptr (начало массива со смещением +0x40). Размер структуры blkptr 128 байт (смещение +0x80)

[0x00000000]> s+0x40
[0x00000040]> pf [2]q[2]q[2]qq[2]qqqq[4]q blk_dva_0 blk_dva_1 blk_dva_2 blk_prop blk_pad[2] blk_phys_birth blk_birth blk_fill blk_cksum
blk_dva_0 : 0x00000040 = (qword)[ 0x0000000000000004, 0x00000000000000fd ]
blk_dva_1 : 0x00000050 = (qword)[ 0x0000000000000004, 0x0000000000000014 ]
blk_dva_2 : 0x00000060 = (qword)[ 0x0000000000000004, 0x0000000000000018 ]
blk_prop : 0x00000070 = (qword)0x800a070f0003001f
blk_pad[2] : 0x00000078 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_phys_birth : 0x00000088 = (qword)0x0000000000000000
blk_birth : 0x00000090 = (qword)0x0000000000000038
blk_fill : 0x00000098 = (qword)0x000000000000001f
blk_cksum : 0x000000a0 = (qword)[ 0x0000005b728c5143, 0x00006add456a9057, 0x0046f84e9ebc9fc1, 0x227baf4ccb8d8253 ]
[0x00000040]> s+0x80
[0x000000c0]> pf [2]q[2]q[2]qq[2]qqqq[4]q blk_dva_0 blk_dva_1 blk_dva_2 blk_prop blk_pad[2] blk_phys_birth blk_birth blk_fill blk_cksum
blk_dva_0 : 0x000000c0 = (qword)[ 0x0000000000000001, 0x00000000000000c7 ]
blk_dva_1 : 0x000000d0 = (qword)[ 0x0000000000000001, 0x00000000000000c8 ]
blk_dva_2 : 0x000000e0 = (qword)[ 0x0000000000000001, 0x00000000000000f9 ]
blk_prop : 0x000000f0 = (qword)0x800a070f0000001f
blk_pad[2] : 0x000000f8 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_phys_birth : 0x00000108 = (qword)0x0000000000000000
blk_birth : 0x00000110 = (qword)0x0000000000000038
blk_fill : 0x00000118 = (qword)0x0000000000000004
blk_cksum : 0x00000120 = (qword)[ 0x000000212e3f6320, 0x000007421d158d58, 0x00012cb9dd4a54c3, 0x0026ea30b4caddc5 ]
[0x000000c0]> s+0x80
[0x00000140]> pf [2]q[2]q[2]qq[2]qqqq[4]q blk_dva_0 blk_dva_1 blk_dva_2 blk_prop blk_pad[2] blk_phys_birth blk_birth blk_fill blk_cksum
blk_dva_0 : 0x00000140 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_dva_1 : 0x00000150 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_dva_2 : 0x00000160 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_prop : 0x00000170 = (qword)0x0000000000000000
blk_pad[2] : 0x00000178 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_phys_birth : 0x00000188 = (qword)0x0000000000000000
blk_birth : 0x00000190 = (qword)0x0000000000000000
blk_fill : 0x00000198 = (qword)0x0000000000000000
blk_cksum : 0x000001a0 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]

image

Блоки сжаты алгоритмом lz4 и имеют размер 2048 байт и 512 байт соответственно (и реальный размер 16384 байт).

Сохраним в файл и распакуем
# dd if=/tmp/test_disk bs=512 skip=8445 count=4 of=/tmp/dsl.dnode.0.bin.lz4
# dd if=/tmp/test_disk bs=512 skip=8391 count=1 of=/tmp/dsl.dnode.1.bin.lz4
# zdec dsl.dnode.0.bin.lz4 dsl.dnode.0.bin 16384
Input: dsl.dnode.0.bin.lz4
Output: dsl.dnode.0.bin
Out size: 16384
-----------------------------
Input size: 2048
Real input size: 1589
Decompress result: 0
# zdec dsl.dnode.1.bin.lz4 dsl.dnode.1.bin 16384
Input: dsl.dnode.1.bin.lz4
Output: dsl.dnode.1.bin
Out size: 16384
-----------------------------
Input size: 512
Real input size: 464
Decompress result: 0

Составим список из объектов

31 объект
# r2 dsl.dnode.0.bin
[0x00000000]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000000 = 0x00
dn_indblkshift : 0x00000001 = 0x00
dn_nlevels : 0x00000002 = 0x00
dn_nblkptr : 0x00000003 = 0x00
dn_bonustype : 0x00000004 = 0x00
dn_checksum : 0x00000005 = 0x00
dn_compress : 0x00000006 = 0x00
dn_flags : 0x00000007 = 0x00
dn_datablkszsec : 0x00000008 = 0x0000
dn_bonuslen : 0x0000000a = 0x0000
dn_pad2[4] : 0x0000000c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000010 = (qword)0x0000000000000000
dn_used : 0x00000018 = (qword)0x0000000000000000
dn_pad3[4] : 0x00000020 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00000000]> s+0x200
[0x00000200]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000200 = 0x01
dn_indblkshift : 0x00000201 = 0x0e
dn_nlevels : 0x00000202 = 0x01
dn_nblkptr : 0x00000203 = 0x03
dn_bonustype : 0x00000204 = 0x00
dn_checksum : 0x00000205 = 0x00
dn_compress : 0x00000206 = 0x00
dn_flags : 0x00000207 = 0x01
dn_datablkszsec : 0x00000208 = 0x0002
dn_bonuslen : 0x0000020a = 0x0000
dn_pad2[4] : 0x0000020c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000210 = (qword)0x0000000000000000
dn_used : 0x00000218 = (qword)0x0000000000000600
dn_pad3[4] : 0x00000220 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00000200]> s+0x200
[0x00000400]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000400 = 0x0c
dn_indblkshift : 0x00000401 = 0x0e
dn_nlevels : 0x00000402 = 0x01
dn_nblkptr : 0x00000403 = 0x01
dn_bonustype : 0x00000404 = 0x0c
dn_checksum : 0x00000405 = 0x00
dn_compress : 0x00000406 = 0x00
dn_flags : 0x00000407 = 0x00
dn_datablkszsec : 0x00000408 = 0x0001
dn_bonuslen : 0x0000040a = 0x0100
dn_pad2[4] : 0x0000040c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000410 = (qword)0x0000000000000000
dn_used : 0x00000418 = (qword)0x0000000000000000
dn_pad3[4] : 0x00000420 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00000400]> s+0x200
[0x00000600]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000600 = 0x0f
dn_indblkshift : 0x00000601 = 0x0e
dn_nlevels : 0x00000602 = 0x01
dn_nblkptr : 0x00000603 = 0x03
dn_bonustype : 0x00000604 = 0x00
dn_checksum : 0x00000605 = 0x00
dn_compress : 0x00000606 = 0x00
dn_flags : 0x00000607 = 0x01
dn_datablkszsec : 0x00000608 = 0x0001
dn_bonuslen : 0x0000060a = 0x0000
dn_pad2[4] : 0x0000060c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000610 = (qword)0x0000000000000000
dn_used : 0x00000618 = (qword)0x0000000000000000
dn_pad3[4] : 0x00000620 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00000600]> s+0x200
[0x00000800]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000800 = 0x0d
dn_indblkshift : 0x00000801 = 0x0e
dn_nlevels : 0x00000802 = 0x01
dn_nblkptr : 0x00000803 = 0x03
dn_bonustype : 0x00000804 = 0x00
dn_checksum : 0x00000805 = 0x00
dn_compress : 0x00000806 = 0x00
dn_flags : 0x00000807 = 0x01
dn_datablkszsec : 0x00000808 = 0x0001
dn_bonuslen : 0x0000080a = 0x0000
dn_pad2[4] : 0x0000080c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000810 = (qword)0x0000000000000000
dn_used : 0x00000818 = (qword)0x0000000000000000
dn_pad3[4] : 0x00000820 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00000800]> s+0x200
[0x00000a00]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000a00 = 0x0c
dn_indblkshift : 0x00000a01 = 0x0e
dn_nlevels : 0x00000a02 = 0x01
dn_nblkptr : 0x00000a03 = 0x01
dn_bonustype : 0x00000a04 = 0x0c
dn_checksum : 0x00000a05 = 0x00
dn_compress : 0x00000a06 = 0x00
dn_flags : 0x00000a07 = 0x00
dn_datablkszsec : 0x00000a08 = 0x0001
dn_bonuslen : 0x00000a0a = 0x0100
dn_pad2[4] : 0x00000a0c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000a10 = (qword)0x0000000000000000
dn_used : 0x00000a18 = (qword)0x0000000000000000
dn_pad3[4] : 0x00000a20 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00000a00]> s+0x200
[0x00000c00]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000c00 = 0x0f
dn_indblkshift : 0x00000c01 = 0x0e
dn_nlevels : 0x00000c02 = 0x01
dn_nblkptr : 0x00000c03 = 0x03
dn_bonustype : 0x00000c04 = 0x00
dn_checksum : 0x00000c05 = 0x00
dn_compress : 0x00000c06 = 0x00
dn_flags : 0x00000c07 = 0x01
dn_datablkszsec : 0x00000c08 = 0x0001
dn_bonuslen : 0x00000c0a = 0x0000
dn_pad2[4] : 0x00000c0c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000c10 = (qword)0x0000000000000000
dn_used : 0x00000c18 = (qword)0x0000000000000000
dn_pad3[4] : 0x00000c20 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00000c00]> s+0x200
[0x00000e00]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000e00 = 0x0d
dn_indblkshift : 0x00000e01 = 0x0e
dn_nlevels : 0x00000e02 = 0x01
dn_nblkptr : 0x00000e03 = 0x03
dn_bonustype : 0x00000e04 = 0x00
dn_checksum : 0x00000e05 = 0x00
dn_compress : 0x00000e06 = 0x00
dn_flags : 0x00000e07 = 0x01
dn_datablkszsec : 0x00000e08 = 0x0001
dn_bonuslen : 0x00000e0a = 0x0000
dn_pad2[4] : 0x00000e0c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000e10 = (qword)0x0000000000000000
dn_used : 0x00000e18 = (qword)0x0000000000000000
dn_pad3[4] : 0x00000e20 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00000e00]> s+0x200
[0x00001000]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00001000 = 0x0c
dn_indblkshift : 0x00001001 = 0x0e
dn_nlevels : 0x00001002 = 0x01
dn_nblkptr : 0x00001003 = 0x01
dn_bonustype : 0x00001004 = 0x0c
dn_checksum : 0x00001005 = 0x00
dn_compress : 0x00001006 = 0x00
dn_flags : 0x00001007 = 0x00
dn_datablkszsec : 0x00001008 = 0x0001
dn_bonuslen : 0x0000100a = 0x0100
dn_pad2[4] : 0x0000100c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00001010 = (qword)0x0000000000000000
dn_used : 0x00001018 = (qword)0x0000000000000000
dn_pad3[4] : 0x00001020 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00001000]> s+0x200
[0x00001200]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00001200 = 0x0f
dn_indblkshift : 0x00001201 = 0x0e
dn_nlevels : 0x00001202 = 0x01
dn_nblkptr : 0x00001203 = 0x03
dn_bonustype : 0x00001204 = 0x00
dn_checksum : 0x00001205 = 0x00
dn_compress : 0x00001206 = 0x00
dn_flags : 0x00001207 = 0x01
dn_datablkszsec : 0x00001208 = 0x0001
dn_bonuslen : 0x0000120a = 0x0000
dn_pad2[4] : 0x0000120c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00001210 = (qword)0x0000000000000000
dn_used : 0x00001218 = (qword)0x0000000000000000
dn_pad3[4] : 0x00001220 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00001200]> s+0x200
[0x00001400]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00001400 = 0x0d
dn_indblkshift : 0x00001401 = 0x0e
dn_nlevels : 0x00001402 = 0x01
dn_nblkptr : 0x00001403 = 0x03
dn_bonustype : 0x00001404 = 0x00
dn_checksum : 0x00001405 = 0x00
dn_compress : 0x00001406 = 0x00
dn_flags : 0x00001407 = 0x01
dn_datablkszsec : 0x00001408 = 0x0001
dn_bonuslen : 0x0000140a = 0x0000
dn_pad2[4] : 0x0000140c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00001410 = (qword)0x0000000000000000
dn_used : 0x00001418 = (qword)0x0000000000000000
dn_pad3[4] : 0x00001420 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00001400]> s+0x200
[0x00001600]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00001600 = 0x05
dn_indblkshift : 0x00001601 = 0x0e
dn_nlevels : 0x00001602 = 0x01
dn_nblkptr : 0x00001603 = 0x03
dn_bonustype : 0x00001604 = 0x06
dn_checksum : 0x00001605 = 0x00
dn_compress : 0x00001606 = 0x00
dn_flags : 0x00001607 = 0x00
dn_datablkszsec : 0x00001608 = 0x0100
dn_bonuslen : 0x0000160a = 0x0030
dn_pad2[4] : 0x0000160c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00001610 = (qword)0x0000000000000000
dn_used : 0x00001618 = (qword)0x0000000000000000
dn_pad3[4] : 0x00001620 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00001600]> s+0x200
[0x00001800]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00001800 = 0x0c
dn_indblkshift : 0x00001801 = 0x0e
dn_nlevels : 0x00001802 = 0x01
dn_nblkptr : 0x00001803 = 0x01
dn_bonustype : 0x00001804 = 0x0c
dn_checksum : 0x00001805 = 0x00
dn_compress : 0x00001806 = 0x00
dn_flags : 0x00001807 = 0x00
dn_datablkszsec : 0x00001808 = 0x0001
dn_bonuslen : 0x0000180a = 0x0100
dn_pad2[4] : 0x0000180c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00001810 = (qword)0x0000000000000000
dn_used : 0x00001818 = (qword)0x0000000000000000
dn_pad3[4] : 0x00001820 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00001800]> s+0x200
[0x00001a00]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00001a00 = 0x0f
dn_indblkshift : 0x00001a01 = 0x0e
dn_nlevels : 0x00001a02 = 0x01
dn_nblkptr : 0x00001a03 = 0x03
dn_bonustype : 0x00001a04 = 0x00
dn_checksum : 0x00001a05 = 0x00
dn_compress : 0x00001a06 = 0x00
dn_flags : 0x00001a07 = 0x01
dn_datablkszsec : 0x00001a08 = 0x0001
dn_bonuslen : 0x00001a0a = 0x0000
dn_pad2[4] : 0x00001a0c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00001a10 = (qword)0x0000000000000000
dn_used : 0x00001a18 = (qword)0x0000000000000000
dn_pad3[4] : 0x00001a20 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00001a00]> s+0x200
[0x00001c00]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00001c00 = 0x0d
dn_indblkshift : 0x00001c01 = 0x0e
dn_nlevels : 0x00001c02 = 0x01
dn_nblkptr : 0x00001c03 = 0x03
dn_bonustype : 0x00001c04 = 0x00
dn_checksum : 0x00001c05 = 0x00
dn_compress : 0x00001c06 = 0x00
dn_flags : 0x00001c07 = 0x01
dn_datablkszsec : 0x00001c08 = 0x0001
dn_bonuslen : 0x00001c0a = 0x0000
dn_pad2[4] : 0x00001c0c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00001c10 = (qword)0x0000000000000000
dn_used : 0x00001c18 = (qword)0x0000000000000000
dn_pad3[4] : 0x00001c20 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00001c00]> s+0x200
[0x00001e00]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00001e00 = 0x10
dn_indblkshift : 0x00001e01 = 0x0e
dn_nlevels : 0x00001e02 = 0x01
dn_nblkptr : 0x00001e03 = 0x01
dn_bonustype : 0x00001e04 = 0x10
dn_checksum : 0x00001e05 = 0x00
dn_compress : 0x00001e06 = 0x00
dn_flags : 0x00001e07 = 0x00
dn_datablkszsec : 0x00001e08 = 0x0001
dn_bonuslen : 0x00001e0a = 0x0140
dn_pad2[4] : 0x00001e0c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00001e10 = (qword)0x0000000000000000
dn_used : 0x00001e18 = (qword)0x0000000000000000
dn_pad3[4] : 0x00001e20 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00001e00]> s+0x200
[0x00002000]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00002000 = 0x0e
dn_indblkshift : 0x00002001 = 0x0e
dn_nlevels : 0x00002002 = 0x01
dn_nblkptr : 0x00002003 = 0x03
dn_bonustype : 0x00002004 = 0x00
dn_checksum : 0x00002005 = 0x00
dn_compress : 0x00002006 = 0x00
dn_flags : 0x00002007 = 0x01
dn_datablkszsec : 0x00002008 = 0x0001
dn_bonuslen : 0x0000200a = 0x0000
dn_pad2[4] : 0x0000200c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00002010 = (qword)0x0000000000000000
dn_used : 0x00002018 = (qword)0x0000000000000000
dn_pad3[4] : 0x00002020 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00002000]> s+0x200
[0x00002200]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00002200 = 0x32
dn_indblkshift : 0x00002201 = 0x0e
dn_nlevels : 0x00002202 = 0x01
dn_nblkptr : 0x00002203 = 0x01
dn_bonustype : 0x00002204 = 0x33
dn_checksum : 0x00002205 = 0x00
dn_compress : 0x00002206 = 0x00
dn_flags : 0x00002207 = 0x01
dn_datablkszsec : 0x00002208 = 0x0001
dn_bonuslen : 0x0000220a = 0x0140
dn_pad2[4] : 0x0000220c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00002210 = (qword)0x0000000000000000
dn_used : 0x00002218 = (qword)0x0000000000000000
dn_pad3[4] : 0x00002220 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00002200]> s+0x200
[0x00002400]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00002400 = 0x10
dn_indblkshift : 0x00002401 = 0x0e
dn_nlevels : 0x00002402 = 0x01
dn_nblkptr : 0x00002403 = 0x01
dn_bonustype : 0x00002404 = 0x10
dn_checksum : 0x00002405 = 0x00
dn_compress : 0x00002406 = 0x00
dn_flags : 0x00002407 = 0x00
dn_datablkszsec : 0x00002408 = 0x0001
dn_bonuslen : 0x0000240a = 0x0140
dn_pad2[4] : 0x0000240c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00002410 = (qword)0x0000000000000000
dn_used : 0x00002418 = (qword)0x0000000000000000
dn_pad3[4] : 0x00002420 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00002400]> s+0x200
[0x00002600]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00002600 = 0x32
dn_indblkshift : 0x00002601 = 0x0e
dn_nlevels : 0x00002602 = 0x01
dn_nblkptr : 0x00002603 = 0x01
dn_bonustype : 0x00002604 = 0x33
dn_checksum : 0x00002605 = 0x00
dn_compress : 0x00002606 = 0x00
dn_flags : 0x00002607 = 0x01
dn_datablkszsec : 0x00002608 = 0x0001
dn_bonuslen : 0x0000260a = 0x0140
dn_pad2[4] : 0x0000260c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00002610 = (qword)0x0000000000000000
dn_used : 0x00002618 = (qword)0x0000000000000000
dn_pad3[4] : 0x00002620 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00002600]> s+0x200
[0x00002800]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00002800 = 0x05
dn_indblkshift : 0x00002801 = 0x0e
dn_nlevels : 0x00002802 = 0x01
dn_nblkptr : 0x00002803 = 0x03
dn_bonustype : 0x00002804 = 0x06
dn_checksum : 0x00002805 = 0x00
dn_compress : 0x00002806 = 0x00
dn_flags : 0x00002807 = 0x00
dn_datablkszsec : 0x00002808 = 0x0100
dn_bonuslen : 0x0000280a = 0x0030
dn_pad2[4] : 0x0000280c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00002810 = (qword)0x0000000000000000
dn_used : 0x00002818 = (qword)0x0000000000000000
dn_pad3[4] : 0x00002820 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00002800]> s+0x200
[0x00002a00]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00002a00 = 0x10
dn_indblkshift : 0x00002a01 = 0x0e
dn_nlevels : 0x00002a02 = 0x01
dn_nblkptr : 0x00002a03 = 0x01
dn_bonustype : 0x00002a04 = 0x10
dn_checksum : 0x00002a05 = 0x00
dn_compress : 0x00002a06 = 0x00
dn_flags : 0x00002a07 = 0x00
dn_datablkszsec : 0x00002a08 = 0x0001
dn_bonuslen : 0x00002a0a = 0x0140
dn_pad2[4] : 0x00002a0c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00002a10 = (qword)0x0000000000000000
dn_used : 0x00002a18 = (qword)0x0000000000000000
dn_pad3[4] : 0x00002a20 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00002a00]> s+0x200
[0x00002c00]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00002c00 = 0x0e
dn_indblkshift : 0x00002c01 = 0x0e
dn_nlevels : 0x00002c02 = 0x01
dn_nblkptr : 0x00002c03 = 0x03
dn_bonustype : 0x00002c04 = 0x00
dn_checksum : 0x00002c05 = 0x00
dn_compress : 0x00002c06 = 0x00
dn_flags : 0x00002c07 = 0x01
dn_datablkszsec : 0x00002c08 = 0x0001
dn_bonuslen : 0x00002c0a = 0x0000
dn_pad2[4] : 0x00002c0c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00002c10 = (qword)0x0000000000000000
dn_used : 0x00002c18 = (qword)0x0000000000000000
dn_pad3[4] : 0x00002c20 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00002c00]> s+0x200
[0x00002e00]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00002e00 = 0x32
dn_indblkshift : 0x00002e01 = 0x0e
dn_nlevels : 0x00002e02 = 0x01
dn_nblkptr : 0x00002e03 = 0x01
dn_bonustype : 0x00002e04 = 0x33
dn_checksum : 0x00002e05 = 0x00
dn_compress : 0x00002e06 = 0x00
dn_flags : 0x00002e07 = 0x01
dn_datablkszsec : 0x00002e08 = 0x0001
dn_bonuslen : 0x00002e0a = 0x0140
dn_pad2[4] : 0x00002e0c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00002e10 = (qword)0x0000000000000000
dn_used : 0x00002e18 = (qword)0x0000000000000000
dn_pad3[4] : 0x00002e20 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00002e00]> s+0x200
[0x00003000]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00003000 = 0x05
dn_indblkshift : 0x00003001 = 0x0e
dn_nlevels : 0x00003002 = 0x01
dn_nblkptr : 0x00003003 = 0x03
dn_bonustype : 0x00003004 = 0x06
dn_checksum : 0x00003005 = 0x00
dn_compress : 0x00003006 = 0x00
dn_flags : 0x00003007 = 0x00
dn_datablkszsec : 0x00003008 = 0x0100
dn_bonuslen : 0x0000300a = 0x0030
dn_pad2[4] : 0x0000300c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00003010 = (qword)0x0000000000000000
dn_used : 0x00003018 = (qword)0x0000000000000000
dn_pad3[4] : 0x00003020 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00003000]> s+0x200
[0x00003200]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00003200 = 0x25
dn_indblkshift : 0x00003201 = 0x0e
dn_nlevels : 0x00003202 = 0x01
dn_nblkptr : 0x00003203 = 0x03
dn_bonustype : 0x00003204 = 0x00
dn_checksum : 0x00003205 = 0x00
dn_compress : 0x00003206 = 0x00
dn_flags : 0x00003207 = 0x01
dn_datablkszsec : 0x00003208 = 0x0001
dn_bonuslen : 0x0000320a = 0x0000
dn_pad2[4] : 0x0000320c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00003210 = (qword)0x0000000000000000
dn_used : 0x00003218 = (qword)0x0000000000000000
dn_pad3[4] : 0x00003220 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00003200]> s+0x200
[0x00003400]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00003400 = 0x34
dn_indblkshift : 0x00003401 = 0x0e
dn_nlevels : 0x00003402 = 0x01
dn_nblkptr : 0x00003403 = 0x03
dn_bonustype : 0x00003404 = 0x00
dn_checksum : 0x00003405 = 0x00
dn_compress : 0x00003406 = 0x00
dn_flags : 0x00003407 = 0x01
dn_datablkszsec : 0x00003408 = 0x0001
dn_bonuslen : 0x0000340a = 0x0000
dn_pad2[4] : 0x0000340c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00003410 = (qword)0x0000000000000000
dn_used : 0x00003418 = (qword)0x0000000000000000
dn_pad3[4] : 0x00003420 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00003400]> s+0x200
[0x00003600]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00003600 = 0x03
dn_indblkshift : 0x00003601 = 0x0e
dn_nlevels : 0x00003602 = 0x01
dn_nblkptr : 0x00003603 = 0x03
dn_bonustype : 0x00003604 = 0x04
dn_checksum : 0x00003605 = 0x00
dn_compress : 0x00003606 = 0x00
dn_flags : 0x00003607 = 0x01
dn_datablkszsec : 0x00003608 = 0x0020
dn_bonuslen : 0x0000360a = 0x0008
dn_pad2[4] : 0x0000360c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00003610 = (qword)0x0000000000000000
dn_used : 0x00003618 = (qword)0x0000000000000c00
dn_pad3[4] : 0x00003620 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00003600]> s+0x200
[0x00003800]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00003800 = 0xc4
dn_indblkshift : 0x00003801 = 0x0e
dn_nlevels : 0x00003802 = 0x01
dn_nblkptr : 0x00003803 = 0x03
dn_bonustype : 0x00003804 = 0x00
dn_checksum : 0x00003805 = 0x00
dn_compress : 0x00003806 = 0x00
dn_flags : 0x00003807 = 0x01
dn_datablkszsec : 0x00003808 = 0x0001
dn_bonuslen : 0x0000380a = 0x0000
dn_pad2[4] : 0x0000380c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00003810 = (qword)0x0000000000000000
dn_used : 0x00003818 = (qword)0x0000000000000600
dn_pad3[4] : 0x00003820 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00003800]> s+0x200
[0x00003a00]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00003a00 = 0xc4
dn_indblkshift : 0x00003a01 = 0x0e
dn_nlevels : 0x00003a02 = 0x01
dn_nblkptr : 0x00003a03 = 0x03
dn_bonustype : 0x00003a04 = 0x00
dn_checksum : 0x00003a05 = 0x00
dn_compress : 0x00003a06 = 0x00
dn_flags : 0x00003a07 = 0x01
dn_datablkszsec : 0x00003a08 = 0x0001
dn_bonuslen : 0x00003a0a = 0x0000
dn_pad2[4] : 0x00003a0c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00003a10 = (qword)0x0000000000000000
dn_used : 0x00003a18 = (qword)0x0000000000000600
dn_pad3[4] : 0x00003a20 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00003a00]> s+0x200
[0x00003c00]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00003c00 = 0xc4
dn_indblkshift : 0x00003c01 = 0x0e
dn_nlevels : 0x00003c02 = 0x01
dn_nblkptr : 0x00003c03 = 0x03
dn_bonustype : 0x00003c04 = 0x00
dn_checksum : 0x00003c05 = 0x00
dn_compress : 0x00003c06 = 0x00
dn_flags : 0x00003c07 = 0x01
dn_datablkszsec : 0x00003c08 = 0x0020
dn_bonuslen : 0x00003c0a = 0x0000
dn_pad2[4] : 0x00003c0c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00003c10 = (qword)0x0000000000000001
dn_used : 0x00003c18 = (qword)0x0000000000003600
dn_pad3[4] : 0x00003c20 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00003c00]> s+0x200
[0x00003e00]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00003e00 = 0x05
dn_indblkshift : 0x00003e01 = 0x0e
dn_nlevels : 0x00003e02 = 0x01
dn_nblkptr : 0x00003e03 = 0x03
dn_bonustype : 0x00003e04 = 0x06
dn_checksum : 0x00003e05 = 0x00
dn_compress : 0x00003e06 = 0x02
dn_flags : 0x00003e07 = 0x01
dn_datablkszsec : 0x00003e08 = 0x0020
dn_bonuslen : 0x00003e0a = 0x0030
dn_pad2[4] : 0x00003e0c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00003e10 = (qword)0x0000000000000000
dn_used : 0x00003e18 = (qword)0x0000000000000600
dn_pad3[4] : 0x00003e20 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]


4 объекта
# r2 dsl.dnode.1.bin
[0x00000000]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000000 = 0x1d
dn_indblkshift : 0x00000001 = 0x0e
dn_nlevels : 0x00000002 = 0x01
dn_nblkptr : 0x00000003 = 0x03
dn_bonustype : 0x00000004 = 0x1e
dn_checksum : 0x00000005 = 0x00
dn_compress : 0x00000006 = 0x00
dn_flags : 0x00000007 = 0x01
dn_datablkszsec : 0x00000008 = 0x0100
dn_bonuslen : 0x0000000a = 0x0028
dn_pad2[4] : 0x0000000c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000010 = (qword)0x0000000000000000
dn_used : 0x00000018 = (qword)0x0000000000001200
dn_pad3[4] : 0x00000020 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00000000]> s+0x200
[0x00000200]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000200 = 0xc4
dn_indblkshift : 0x00000201 = 0x0e
dn_nlevels : 0x00000202 = 0x01
dn_nblkptr : 0x00000203 = 0x03
dn_bonustype : 0x00000204 = 0x00
dn_checksum : 0x00000205 = 0x00
dn_compress : 0x00000206 = 0x00
dn_flags : 0x00000207 = 0x01
dn_datablkszsec : 0x00000208 = 0x0001
dn_bonuslen : 0x0000020a = 0x0000
dn_pad2[4] : 0x0000020c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000210 = (qword)0x0000000000000000
dn_used : 0x00000218 = (qword)0x0000000000000600
dn_pad3[4] : 0x00000220 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00000200]> s+0x200
[0x00000400]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000400 = 0x02
dn_indblkshift : 0x00000401 = 0x0e
dn_nlevels : 0x00000402 = 0x01
dn_nblkptr : 0x00000403 = 0x03
dn_bonustype : 0x00000404 = 0x00
dn_checksum : 0x00000405 = 0x00
dn_compress : 0x00000406 = 0x00
dn_flags : 0x00000407 = 0x01
dn_datablkszsec : 0x00000408 = 0x0001
dn_bonuslen : 0x0000040a = 0x0000
dn_pad2[4] : 0x0000040c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000410 = (qword)0x0000000000000000
dn_used : 0x00000418 = (qword)0x0000000000000000
dn_pad3[4] : 0x00000420 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00000400]> s+0x200
[0x00000600]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000600 = 0x08
dn_indblkshift : 0x00000601 = 0x0e
dn_nlevels : 0x00000602 = 0x01
dn_nblkptr : 0x00000603 = 0x01
dn_bonustype : 0x00000604 = 0x07
dn_checksum : 0x00000605 = 0x00
dn_compress : 0x00000606 = 0x00
dn_flags : 0x00000607 = 0x01
dn_datablkszsec : 0x00000608 = 0x0008
dn_bonuslen : 0x0000060a = 0x0140
dn_pad2[4] : 0x0000060c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000610 = (qword)0x0000000000000000
dn_used : 0x00000618 = (qword)0x0000000000000c00
dn_pad3[4] : 0x00000620 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]


В данный момент нас интересуют объекты 15, 18, 21.
index dn_type dn_bonustype dn_bonuslen
15 0x10 DMU_OT_DSL_DATASET 0x10 DMU_OT_DSL_DATASET 0x0140
18 0x10 DMU_OT_DSL_DATASET 0x10 DMU_OT_DSL_DATASET 0x0140
21 0x10 DMU_OT_DSL_DATASET 0x10 DMU_OT_DSL_DATASET 0x0140


Для объектов типа DMU_OT_DSL_DATASET в бонус-буфере структуры dnode хранится структура dsl_dataset_phys.
typedef struct dsl_dataset_phys {
	uint64_t ds_dir_obj;		/* DMU_OT_DSL_DIR */
	uint64_t ds_prev_snap_obj;	/* DMU_OT_DSL_DATASET */
	uint64_t ds_prev_snap_txg;
	uint64_t ds_next_snap_obj;	/* DMU_OT_DSL_DATASET */
	uint64_t ds_snapnames_zapobj;	/* DMU_OT_DSL_DS_SNAP_MAP 0 for snaps */
	uint64_t ds_num_children;	/* clone/snap children; ==0 for head */
	uint64_t ds_creation_time;	/* seconds since 1970 */
	uint64_t ds_creation_txg;
	uint64_t ds_deadlist_obj;	/* DMU_OT_DEADLIST */
	/*
	 * ds_referenced_bytes, ds_compressed_bytes, and ds_uncompressed_bytes
	 * include all blocks referenced by this dataset, including those
	 * shared with any other datasets.
	 */
	uint64_t ds_referenced_bytes;
	uint64_t ds_compressed_bytes;
	uint64_t ds_uncompressed_bytes;
	uint64_t ds_unique_bytes;	/* only relevant to snapshots */
	/*
	 * The ds_fsid_guid is a 56-bit ID that can change to avoid
	 * collisions.  The ds_guid is a 64-bit ID that will never
	 * change, so there is a small probability that it will collide.
	 */
	uint64_t ds_fsid_guid;
	uint64_t ds_guid;
	uint64_t ds_flags;		/* DS_FLAG_* */
	blkptr_t ds_bp;
	uint64_t ds_next_clones_obj;	/* DMU_OT_DSL_CLONES */
	uint64_t ds_props_obj;		/* DMU_OT_DSL_PROPS for snaps */
	uint64_t ds_userrefs_obj;	/* DMU_OT_USERREFS */
	uint64_t ds_pad[5]; /* pad out to 320 bytes for good measure */
} dsl_dataset_phys_t;


Считываем объект 15

# r2 dsl.dnode.0.bin
-- Change the size of the file with the 'r' (resize) command
[0x00000000]> 0x00001e00
[0x00001e00]> s+0x40
[0x00001e40]> s+0x80
[0x00001ec0]> pf qqqqqqt:qqqqqqqqqb[127].qqq[5]q ds_dir_obj ds_prev_snap_obj ds_prev_snap_txg ds_next_snap_obj ds_snapnames_zapobj ds_num_children ds_creation_time ds_creation_txg ds_deadlist_obj ds_referenced_bytes ds_compressed_bytes ds_uncompressed_bytes ds_unique_bytes ds_fsid_guid ds_guid ds_flags ds_bp ds_next_clones_obj ds_props_obj ds_userrefs_obj ds_pad[5]
ds_dir_obj : 0x00001ec0 = (qword)0x000000000000000c
ds_prev_snap_obj : 0x00001ec8 = (qword)0x0000000000000012
ds_prev_snap_txg : 0x00001ed0 = (qword)0x0000000000000001
ds_next_snap_obj : 0x00001ed8 = (qword)0x0000000000000000
ds_snapnames_zapobj : 0x00001ee0 = (qword)0x0000000000000010
ds_num_children : 0x00001ee8 = (qword)0x0000000000000000
ds_creation_time : 0x00001ef0 = Wed Jan 31 07:25:31 2018
ds_creation_txg : 0x00001ef8 = (qword)0x0000000000000001
ds_deadlist_obj : 0x00001f00 = (qword)0x0000000000000013
ds_referenced_bytes : 0x00001f08 = (qword)0x0000000000000000
ds_compressed_bytes : 0x00001f10 = (qword)0x0000000000000000
ds_uncompressed_bytes : 0x00001f18 = (qword)0x0000000000000000
ds_unique_bytes : 0x00001f20 = (qword)0x0000000000000000
ds_fsid_guid : 0x00001f28 = (qword)0x0072595fd26fec77
ds_guid : 0x00001f30 = (qword)0x3723b59bcad0d186
ds_flags : 0x00001f38 = (qword)0x0000000000000004
ds_bp : 0x00001f40 = 0x00
ds_next_clones_obj : 0x00001fc0 = (qword)0x0000000000000000
ds_props_obj : 0x00001fc8 = (qword)0x0000000000000000
ds_userrefs_obj : 0x00001fd0 = (qword)0x0000000000000000
ds_pad[5] : 0x00001fd8 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
0x00001f40
[0x00001f40]> pf [2]q[2]q[2]qq[2]qqqq[4]q blk_dva_0 blk_dva_1 blk_dva_2 blk_prop blk_pad[2] blk_phys_birth blk_birth blk_fill blk_cksum
blk_dva_0 : 0x00001f40 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_dva_1 : 0x00001f50 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_dva_2 : 0x00001f60 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_prop : 0x00001f70 = (qword)0x0000000000000000
blk_pad[2] : 0x00001f78 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_phys_birth : 0x00001f88 = (qword)0x0000000000000000
blk_birth : 0x00001f90 = (qword)0x0000000000000000
blk_fill : 0x00001f98 = (qword)0x0000000000000000
blk_cksum : 0x00001fa0 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]

Считываем объект 18

0x00002400
[0x00002400]> s+0x40
[0x00002440]> s+0x80
[0x000024c0]> pf qqqqqqt:qqqqqqqqqb[127].qqq[5]q ds_dir_obj ds_prev_snap_obj ds_prev_snap_txg ds_next_snap_obj ds_snapnames_zapobj ds_num_children ds_creation_time ds_creation_txg ds_deadlist_obj ds_referenced_bytes ds_compressed_bytes ds_uncompressed_bytes ds_unique_bytes ds_fsid_guid ds_guid ds_flags ds_bp ds_next_clones_obj ds_props_obj ds_userrefs_obj ds_pad[5]
ds_dir_obj : 0x000024c0 = (qword)0x000000000000000c
ds_prev_snap_obj : 0x000024c8 = (qword)0x0000000000000000
ds_prev_snap_txg : 0x000024d0 = (qword)0x0000000000000000
ds_next_snap_obj : 0x000024d8 = (qword)0x000000000000000f
ds_snapnames_zapobj : 0x000024e0 = (qword)0x0000000000000000
ds_num_children : 0x000024e8 = (qword)0x0000000000000002
ds_creation_time : 0x000024f0 = Wed Jan 31 07:25:31 2018
ds_creation_txg : 0x000024f8 = (qword)0x0000000000000001
ds_deadlist_obj : 0x00002500 = (qword)0x0000000000000011
ds_referenced_bytes : 0x00002508 = (qword)0x0000000000000000
ds_compressed_bytes : 0x00002510 = (qword)0x0000000000000000
ds_uncompressed_bytes : 0x00002518 = (qword)0x0000000000000000
ds_unique_bytes : 0x00002520 = (qword)0x0000000000000000
ds_fsid_guid : 0x00002528 = (qword)0x007551fa166ccbaf
ds_guid : 0x00002530 = (qword)0x107a852b04f9f01f
ds_flags : 0x00002538 = (qword)0x0000000000000004
ds_bp : 0x00002540 = 0x00
ds_next_clones_obj : 0x000025c0 = (qword)0x0000000000000019
ds_props_obj : 0x000025c8 = (qword)0x0000000000000000
ds_userrefs_obj : 0x000025d0 = (qword)0x0000000000000000
ds_pad[5] : 0x000025d8 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
0x00002540
[0x00002540]> pf [2]q[2]q[2]qq[2]qqqq[4]q blk_dva_0 blk_dva_1 blk_dva_2 blk_prop blk_pad[2] blk_phys_birth blk_birth blk_fill blk_cksum
blk_dva_0 : 0x00002540 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_dva_1 : 0x00002550 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_dva_2 : 0x00002560 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_prop : 0x00002570 = (qword)0x0000000000000000
blk_pad[2] : 0x00002578 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_phys_birth : 0x00002588 = (qword)0x0000000000000000
blk_birth : 0x00002590 = (qword)0x0000000000000000
blk_fill : 0x00002598 = (qword)0x0000000000000000
blk_cksum : 0x000025a0 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]

Считываем объект 21

0x00002a00
[0x00002a00]> s+0x40
[0x00002a40]> s+0x80
[0x00002ac0]> pf qqqqqqt:qqqqqqqqqb[127].qqq[5]q ds_dir_obj ds_prev_snap_obj ds_prev_snap_txg ds_next_snap_obj ds_snapnames_zapobj ds_num_children ds_creation_time ds_creation_txg ds_deadlist_obj ds_referenced_bytes ds_compressed_bytes ds_uncompressed_bytes ds_unique_bytes ds_fsid_guid ds_guid ds_flags ds_bp ds_next_clones_obj ds_props_obj ds_userrefs_obj ds_pad[5]
ds_dir_obj : 0x00002ac0 = (qword)0x0000000000000002
ds_prev_snap_obj : 0x00002ac8 = (qword)0x0000000000000012
ds_prev_snap_txg : 0x00002ad0 = (qword)0x0000000000000001
ds_next_snap_obj : 0x00002ad8 = (qword)0x0000000000000000
ds_snapnames_zapobj : 0x00002ae0 = (qword)0x0000000000000016
ds_num_children : 0x00002ae8 = (qword)0x0000000000000000
ds_creation_time : 0x00002af0 = Wed Jan 31 07:25:31 2018
ds_creation_txg : 0x00002af8 = (qword)0x0000000000000001
ds_deadlist_obj : 0x00002b00 = (qword)0x0000000000000017
ds_referenced_bytes : 0x00002b08 = (qword)0x0000000000005600
ds_compressed_bytes : 0x00002b10 = (qword)0x0000000000002e00
ds_uncompressed_bytes : 0x00002b18 = (qword)0x0000000000002e00
ds_unique_bytes : 0x00002b20 = (qword)0x0000000000005600
ds_fsid_guid : 0x00002b28 = (qword)0x00aca2eec566a5b9
ds_guid : 0x00002b30 = (qword)0x6994c8e8b2452f06
ds_flags : 0x00002b38 = (qword)0x0000000000000004
ds_bp : 0x00002b40 = 0x01
ds_next_clones_obj : 0x00002bc0 = (qword)0x0000000000000000
ds_props_obj : 0x00002bc8 = (qword)0x0000000000000000
ds_userrefs_obj : 0x00002bd0 = (qword)0x0000000000000000
ds_pad[5] : 0x00002bd8 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
0x00002b40
[0x00002b40]> pf [2]q[2]q[2]qq[2]qqqq[4]q blk_dva_0 blk_dva_1 blk_dva_2 blk_prop blk_pad[2] blk_phys_birth blk_birth blk_fill blk_cksum
blk_dva_0 : 0x00002b40 = (qword)[ 0x0000000000000001, 0x0000000000000057 ]
blk_dva_1 : 0x00002b50 = (qword)[ 0x0000000000000001, 0x0000000000000058 ]
blk_dva_2 : 0x00002b60 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_prop : 0x00002b70 = (qword)0x800b070f00000003
blk_pad[2] : 0x00002b78 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_phys_birth : 0x00002b88 = (qword)0x0000000000000000
blk_birth : 0x00002b90 = (qword)0x0000000000000038
blk_fill : 0x00002b98 = (qword)0x0000000000000009
blk_cksum : 0x00002ba0 = (qword)[ 0x0000000efd4a0466, 0x000005ded369f382, 0x00012e169b3aebd5, 0x00298598c4f3c9d9 ]

image
Только этот объект хранит данные, далее будем работать с ним.

Сохраним в файл и распакуем

# dd if=/tmp/test_disk bs=512 skip=8279 count=1 of=/tmp/os.dataset.bin.lz4
# zdec os.dataset.bin.lz4 os.dataset.bin 2048
Input: os.dataset.bin.lz4
Output: os.dataset.bin
Out size: 2048
-----------------------------
Input size: 512
Real input size: 201
Decompress result: 0

Смотрим содержимое objset

# r2 os.dataset.bin
[0x00000000]> pf [512].[192].qq[304].[512].[512]. os_type os_flags
os_type : 0x000002c0 = (qword)0x0000000000000002
os_flags : 0x000002c8 = (qword)0x0000000000000001
[0x00000000]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000000 = 0x0a
dn_indblkshift : 0x00000001 = 0x0e
dn_nlevels : 0x00000002 = 0x07
dn_nblkptr : 0x00000003 = 0x03
dn_bonustype : 0x00000004 = 0x00
dn_checksum : 0x00000005 = 0x00
dn_compress : 0x00000006 = 0x00
dn_flags : 0x00000007 = 0x01
dn_datablkszsec : 0x00000008 = 0x0020
dn_bonuslen : 0x0000000a = 0x0000
dn_pad2[4] : 0x0000000c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000010 = (qword)0x0000000000000000
dn_used : 0x00000018 = (qword)0x0000000000002000
dn_pad3[4] : 0x00000020 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00000000]> s+0x40
[0x00000040]> pf [2]q[2]q[2]qq[2]qqqq[4]q blk_dva_0 blk_dva_1 blk_dva_2 blk_prop blk_pad[2] blk_phys_birth blk_birth blk_fill blk_cksum
blk_dva_0 : 0x00000040 = (qword)[ 0x0000000000000001, 0x000000000000010c ]
blk_dva_1 : 0x00000050 = (qword)[ 0x0000000000000001, 0x000000000000010d ]
blk_dva_2 : 0x00000060 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_prop : 0x00000070 = (qword)0x860a070f0000001f
blk_pad[2] : 0x00000078 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_phys_birth : 0x00000088 = (qword)0x0000000000000000
blk_birth : 0x00000090 = (qword)0x0000000000000038
blk_fill : 0x00000098 = (qword)0x0000000000000009
blk_cksum : 0x000000a0 = (qword)[ 0x0000001353eb3bd1, 0x000007c5fce654db, 0x000196a4bd5ee712, 0x00384d0db7501d91 ]

image

Это ссылка на косвенный блок 6 уровня, последовательно будем копать до нулевого уровня.

L6
# dd if=/tmp/test_disk bs=512 skip=8460 count=1 of=/tmp/os.dataset.dnode.l6.bin.lz4
# zdec os.dataset.dnode.l6.bin.lz4 os.dataset.dnode.l6.bin 16384
Input: os.dataset.dnode.l6.bin.lz4
Output: os.dataset.dnode.l6.bin
Out size: 16384
-----------------------------
Input size: 512
Real input size: 150
Decompress result: 0
# r2 os.dataset.dnode.l6.bin
[0x00000000]> pf [2]q[2]q[2]qq[2]qqqq[4]q blk_dva_0 blk_dva_1 blk_dva_2 blk_prop blk_pad[2] blk_phys_birth blk_birth blk_fill blk_cksum
blk_dva_0 : 0x00000000 = (qword)[ 0x0000000000000001, 0x00000000000000b6 ]
blk_dva_1 : 0x00000010 = (qword)[ 0x0000000000000001, 0x000000000000010b ]
blk_dva_2 : 0x00000020 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_prop : 0x00000030 = (qword)0x850a070f0000001f
blk_pad[2] : 0x00000038 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_phys_birth : 0x00000048 = (qword)0x0000000000000000
blk_birth : 0x00000050 = (qword)0x0000000000000038
blk_fill : 0x00000058 = (qword)0x0000000000000009
blk_cksum : 0x00000060 = (qword)[ 0x00000012eaa1fd11, 0x000007989478980e, 0x00018c88e386c191, 0x0036c2a7102bf2c2 ]


L5
[0x00000000]> "? 0x400000/512 + 0x00000000000000b6"
8374 0x20b6 020266 8.2K 0000:00b6 8374 "\xb6 " 0b0010000010110110 8374.0 8374.000000f 8374.000000 0t102111011
# dd if=/tmp/test_disk bs=512 skip=8374 count=1 of=/tmp/os.dataset.dnode.l5.bin.lz4
# zdec os.dataset.dnode.l5.bin.lz4 os.dataset.dnode.l5.bin 16384
Input: os.dataset.dnode.l5.bin.lz4
Output: os.dataset.dnode.l5.bin
Out size: 16384
-----------------------------
Input size: 512
Real input size: 149
Decompress result: 0
# r2 os.dataset.dnode.l5.bin
[0x00000000]> pf [2]q[2]q[2]qq[2]qqqq[4]q blk_dva_0 blk_dva_1 blk_dva_2 blk_prop blk_pad[2] blk_phys_birth blk_birth blk_fill blk_cksum
blk_dva_0 : 0x00000000 = (qword)[ 0x0000000000000001, 0x00000000000000b4 ]
blk_dva_1 : 0x00000010 = (qword)[ 0x0000000000000001, 0x00000000000000b5 ]
blk_dva_2 : 0x00000020 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_prop : 0x00000030 = (qword)0x840a070f0000001f
blk_pad[2] : 0x00000038 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_phys_birth : 0x00000048 = (qword)0x0000000000000000
blk_birth : 0x00000050 = (qword)0x0000000000000038
blk_fill : 0x00000058 = (qword)0x0000000000000009
blk_cksum : 0x00000060 = (qword)[ 0x000000135bd403fd, 0x000007c79b2ed6a0, 0x0001969b589bf00e, 0x00383d2f2da4c77e ]


L4
[0x00000000]> "? 0x400000/512 + 0x00000000000000b4"
8372 0x20b4 020264 8.2K 0000:00b4 8372 "\xb4 " 0b0010000010110100 8372.0 8372.000000f 8372.000000 0t102111002
# dd if=/tmp/test_disk bs=512 skip=8372 count=1 of=/tmp/os.dataset.dnode.l4.bin.lz4
# zdec os.dataset.dnode.l4.bin.lz4 os.dataset.dnode.l4.bin 16384
Input: os.dataset.dnode.l4.bin.lz4
Output: os.dataset.dnode.l4.bin
Out size: 16384
-----------------------------
Input size: 512
Real input size: 150
Decompress result: 0
# r2 os.dataset.dnode.l4.bin
-- Execute a command every time a breakpoint is hit with 'e cmd.bp = !my-program'
[0x00000000]> pf [2]q[2]q[2]qq[2]qqqq[4]q blk_dva_0 blk_dva_1 blk_dva_2 blk_prop blk_pad[2] blk_phys_birth blk_birth blk_fill blk_cksum
blk_dva_0 : 0x00000000 = (qword)[ 0x0000000000000001, 0x0000000000000081 ]
blk_dva_1 : 0x00000010 = (qword)[ 0x0000000000000001, 0x0000000000000082 ]
blk_dva_2 : 0x00000020 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_prop : 0x00000030 = (qword)0x830a070f0000001f
blk_pad[2] : 0x00000038 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_phys_birth : 0x00000048 = (qword)0x0000000000000000
blk_birth : 0x00000050 = (qword)0x0000000000000038
blk_fill : 0x00000058 = (qword)0x0000000000000009
blk_cksum : 0x00000060 = (qword)[ 0x00000012cee6bcc2, 0x0000078b79b1c147, 0x000189aa5ace3a0a, 0x00365db1d10dc06e ]


L3
[0x00000000]> "? 0x400000/512 + 0x0000000000000081"
8321 0x2081 020201 8.1K 0000:0081 8321 "\x81 " 0b0010000010000001 8321.0 8321.000000f 8321.000000 0t102102012
# dd if=/tmp/test_disk bs=512 skip=8321 count=1 of=/tmp/os.dataset.dnode.l3.bin.lz4
# zdec os.dataset.dnode.l3.bin.lz4 os.dataset.dnode.l3.bin 16384
Input: os.dataset.dnode.l3.bin.lz4
Output: os.dataset.dnode.l3.bin
Out size: 16384
-----------------------------
Input size: 512
Real input size: 150
Decompress result: 0
# r2 os.dataset.dnode.l3.bin
-- Use the '[' and ']' keys in visual mode to adjust the screen width
[0x00000000]> pf [2]q[2]q[2]qq[2]qqqq[4]q blk_dva_0 blk_dva_1 blk_dva_2 blk_prop blk_pad[2] blk_phys_birth blk_birth blk_fill blk_cksum
blk_dva_0 : 0x00000000 = (qword)[ 0x0000000000000001, 0x00000000000000ea ]
blk_dva_1 : 0x00000010 = (qword)[ 0x0000000000000001, 0x0000000000000080 ]
blk_dva_2 : 0x00000020 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_prop : 0x00000030 = (qword)0x820a070f0000001f
blk_pad[2] : 0x00000038 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_phys_birth : 0x00000048 = (qword)0x0000000000000000
blk_birth : 0x00000050 = (qword)0x0000000000000038
blk_fill : 0x00000058 = (qword)0x0000000000000009
blk_cksum : 0x00000060 = (qword)[ 0x00000013d660f06c, 0x000007fd7a9a913f, 0x0001a28c7591888d, 0x003a04c5208f66a6 ]


L2
[0x00000000]> "? 0x400000/512 + 0x00000000000000ea"
8426 0x20ea 020352 8.2K 0000:00ea 8426 "\xea " 0b0010000011101010 8426.0 8426.000000f 8426.000000 0t102120002
# dd if=/tmp/test_disk bs=512 skip=8426 count=1 of=/tmp/os.dataset.dnode.l2.bin.lz4
# zdec os.dataset.dnode.l2.bin.lz4 os.dataset.dnode.l2.bin 16384
Input: os.dataset.dnode.l2.bin.lz4
Output: os.dataset.dnode.l2.bin
Out size: 16384
-----------------------------
Input size: 512
Real input size: 150
Decompress result: 0
# r2 os.dataset.dnode.l2.bin
[0x00000000]> pf [2]q[2]q[2]qq[2]qqqq[4]q blk_dva_0 blk_dva_1 blk_dva_2 blk_prop blk_pad[2] blk_phys_birth blk_birth blk_fill blk_cksum
blk_dva_0 : 0x00000000 = (qword)[ 0x0000000000000001, 0x000000000000007e ]
blk_dva_1 : 0x00000010 = (qword)[ 0x0000000000000001, 0x00000000000000d8 ]
blk_dva_2 : 0x00000020 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_prop : 0x00000030 = (qword)0x810a070f0000001f
blk_pad[2] : 0x00000038 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_phys_birth : 0x00000048 = (qword)0x0000000000000000
blk_birth : 0x00000050 = (qword)0x0000000000000038
blk_fill : 0x00000058 = (qword)0x0000000000000009
blk_cksum : 0x00000060 = (qword)[ 0x000000119de2c7aa, 0x00000700d12632b0, 0x000169e2d81be607, 0x00317850a78e8a46 ]


L1
[0x00000000]> "? 0x400000/512 + 0x000000000000007e"
8318 0x207e 020176 8.1K 0000:007e 8318 "~ " 0b0010000001111110 8318.0 8318.000000f 8318.000000 0t102102002
# dd if=/tmp/test_disk bs=512 skip=8318 count=1 of=/tmp/os.dataset.dnode.l1.bin.lz4
# zdec os.dataset.dnode.l1.bin.lz4 os.dataset.dnode.l1.bin 16384
Input: os.dataset.dnode.l1.bin.lz4
Output: os.dataset.dnode.l1.bin
Out size: 16384
-----------------------------
Input size: 512
Real input size: 150
Decompress result: 0
# r2 os.dataset.dnode.l1.bin
[0x00000000]> pf [2]q[2]q[2]qq[2]qqqq[4]q blk_dva_0 blk_dva_1 blk_dva_2 blk_prop blk_pad[2] blk_phys_birth blk_birth blk_fill blk_cksum
blk_dva_0 : 0x00000000 = (qword)[ 0x0000000000000002, 0x0000000000000105 ]
blk_dva_1 : 0x00000010 = (qword)[ 0x0000000000000002, 0x000000000000007c ]
blk_dva_2 : 0x00000020 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_prop : 0x00000030 = (qword)0x800a070f0001001f
blk_pad[2] : 0x00000038 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_phys_birth : 0x00000048 = (qword)0x0000000000000000
blk_birth : 0x00000050 = (qword)0x0000000000000038
blk_fill : 0x00000058 = (qword)0x0000000000000009
blk_cksum : 0x00000060 = (qword)[ 0x0000003e07b9461b, 0x00001c6526d2728c, 0x00097c6c15624af0, 0x0268557731d83b04 ]


L0
[0x00000000]> "? 0x400000/512 + 0x0000000000000105"
8453 0x2105 020405 8.3K 0000:0105 8453 "\x05!" 0b0010000100000101 8453.0 8453.000000f 8453.000000 0t102121002
# dd if=/tmp/test_disk bs=512 skip=8453 count=2 of=/tmp/os.dataset.dnode.l0.bin.lz4
# zdec os.dataset.dnode.l0.bin.lz4 os.dataset.dnode.l0.bin 16384
Input: os.dataset.dnode.l0.bin.lz4
Output: os.dataset.dnode.l0.bin
Out size: 16384
-----------------------------
Input size: 1024
Real input size: 1007
Decompress result: 0

Нулевой уровень это непосредственно objset.

Составим список объектов

9 объектов
# r2 os.dataset.dnode.l0.bin
[0x00000000]> s+0x200
[0x00000200]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000200 = 0x15
dn_indblkshift : 0x00000201 = 0x0e
dn_nlevels : 0x00000202 = 0x01
dn_nblkptr : 0x00000203 = 0x03
dn_bonustype : 0x00000204 = 0x00
dn_checksum : 0x00000205 = 0x00
dn_compress : 0x00000206 = 0x00
dn_flags : 0x00000207 = 0x03
dn_datablkszsec : 0x00000208 = 0x0001
dn_bonuslen : 0x0000020a = 0x0000
dn_pad2[4] : 0x0000020c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000210 = (qword)0x0000000000000000
dn_used : 0x00000218 = (qword)0x0000000000000400
dn_pad3[4] : 0x00000220 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00000200]> s+0x200
[0x00000400]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000400 = 0x2d
dn_indblkshift : 0x00000401 = 0x0e
dn_nlevels : 0x00000402 = 0x01
dn_nblkptr : 0x00000403 = 0x03
dn_bonustype : 0x00000404 = 0x00
dn_checksum : 0x00000405 = 0x00
dn_compress : 0x00000406 = 0x00
dn_flags : 0x00000407 = 0x03
dn_datablkszsec : 0x00000408 = 0x0001
dn_bonuslen : 0x0000040a = 0x0000
dn_pad2[4] : 0x0000040c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000410 = (qword)0x0000000000000000
dn_used : 0x00000418 = (qword)0x0000000000000000
dn_pad3[4] : 0x00000420 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00000400]> s+0x200
[0x00000600]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000600 = 0x16
dn_indblkshift : 0x00000601 = 0x0e
dn_nlevels : 0x00000602 = 0x01
dn_nblkptr : 0x00000603 = 0x03
dn_bonustype : 0x00000604 = 0x00
dn_checksum : 0x00000605 = 0x00
dn_compress : 0x00000606 = 0x00
dn_flags : 0x00000607 = 0x03
dn_datablkszsec : 0x00000608 = 0x0001
dn_bonuslen : 0x0000060a = 0x0000
dn_pad2[4] : 0x0000060c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000610 = (qword)0x0000000000000000
dn_used : 0x00000618 = (qword)0x0000000000000000
dn_pad3[4] : 0x00000620 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00000600]> s+0x200
[0x00000800]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000800 = 0x14
dn_indblkshift : 0x00000801 = 0x0e
dn_nlevels : 0x00000802 = 0x01
dn_nblkptr : 0x00000803 = 0x01
dn_bonustype : 0x00000804 = 0x2c
dn_checksum : 0x00000805 = 0x00
dn_compress : 0x00000806 = 0x00
dn_flags : 0x00000807 = 0x03
dn_datablkszsec : 0x00000808 = 0x0001
dn_bonuslen : 0x0000080a = 0x00a8
dn_pad2[4] : 0x0000080c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000810 = (qword)0x0000000000000000
dn_used : 0x00000818 = (qword)0x0000000000000000
dn_pad3[4] : 0x00000820 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00000800]> s+0x200
[0x00000a00]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000a00 = 0x2e
dn_indblkshift : 0x00000a01 = 0x0e
dn_nlevels : 0x00000a02 = 0x01
dn_nblkptr : 0x00000a03 = 0x03
dn_bonustype : 0x00000a04 = 0x00
dn_checksum : 0x00000a05 = 0x00
dn_compress : 0x00000a06 = 0x00
dn_flags : 0x00000a07 = 0x03
dn_datablkszsec : 0x00000a08 = 0x0003
dn_bonuslen : 0x00000a0a = 0x0000
dn_pad2[4] : 0x00000a0c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000a10 = (qword)0x0000000000000000
dn_used : 0x00000a18 = (qword)0x0000000000000400
dn_pad3[4] : 0x00000a20 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00000a00]> s+0x200
[0x00000c00]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000c00 = 0x2f
dn_indblkshift : 0x00000c01 = 0x0e
dn_nlevels : 0x00000c02 = 0x01
dn_nblkptr : 0x00000c03 = 0x03
dn_bonustype : 0x00000c04 = 0x00
dn_checksum : 0x00000c05 = 0x00
dn_compress : 0x00000c06 = 0x00
dn_flags : 0x00000c07 = 0x03
dn_datablkszsec : 0x00000c08 = 0x0020
dn_bonuslen : 0x00000c0a = 0x0000
dn_pad2[4] : 0x00000c0c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000c10 = (qword)0x0000000000000001
dn_used : 0x00000c18 = (qword)0x0000000000002000
dn_pad3[4] : 0x00000c20 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00000c00]> s+0x200
[0x00000e00]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000e00 = 0x13
dn_indblkshift : 0x00000e01 = 0x0e
dn_nlevels : 0x00000e02 = 0x01
dn_nblkptr : 0x00000e03 = 0x01
dn_bonustype : 0x00000e04 = 0x2c
dn_checksum : 0x00000e05 = 0x00
dn_compress : 0x00000e06 = 0x00
dn_flags : 0x00000e07 = 0x02
dn_datablkszsec : 0x00000e08 = 0x0001
dn_bonuslen : 0x00000e0a = 0x00a8
dn_pad2[4] : 0x00000e0c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000e10 = (qword)0x0000000000000000
dn_used : 0x00000e18 = (qword)0x0000000000000000
dn_pad3[4] : 0x00000e20 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00000e00]> s+0x200
[0x00001000]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00001000 = 0x13
dn_indblkshift : 0x00001001 = 0x0e
dn_nlevels : 0x00001002 = 0x01
dn_nblkptr : 0x00001003 = 0x01
dn_bonustype : 0x00001004 = 0x2c
dn_checksum : 0x00001005 = 0x00
dn_compress : 0x00001006 = 0x00
dn_flags : 0x00001007 = 0x03
dn_datablkszsec : 0x00001008 = 0x0001
dn_bonuslen : 0x0000100a = 0x00a8
dn_pad2[4] : 0x0000100c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00001010 = (qword)0x0000000000000000
dn_used : 0x00001018 = (qword)0x0000000000000200
dn_pad3[4] : 0x00001020 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00001000]> s+0x200
[0x00001200]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00001200 = 0x13
dn_indblkshift : 0x00001201 = 0x0e
dn_nlevels : 0x00001202 = 0x02
dn_nblkptr : 0x00001203 = 0x01
dn_bonustype : 0x00001204 = 0x2c
dn_checksum : 0x00001205 = 0x00
dn_compress : 0x00001206 = 0x00
dn_flags : 0x00001207 = 0x03
dn_datablkszsec : 0x00001208 = 0x0001
dn_bonuslen : 0x0000120a = 0x00a8
dn_pad2[4] : 0x0000120c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00001210 = (qword)0x0000000000000001
dn_used : 0x00001218 = (qword)0x0000000000000800
dn_pad3[4] : 0x00001220 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]


index dn_type dn_bonustype dn_bonuslen
4 0x14 DMU_OT_DIRECTORY_CONTENTS 0x2c DMU_OT_SA 0x00a8
7 0x13 DMU_OT_PLAIN_FILE_CONTENTS 0x2c DMU_OT_SA 0x00a8
8 0x13 DMU_OT_PLAIN_FILE_CONTENTS 0x2c DMU_OT_SA 0x00a8
9 0x13 DMU_OT_PLAIN_FILE_CONTENTS 0x2c DMU_OT_SA 0x00a8


Объекты 7, 8, 9 это созданные нами файлы 0B, 512B, 513B. Соответствие номера и файла можно получить из объекта 4 (DMU_OT_DIRECTORY_CONTENTS).

Считаем объект 4
# r2 os.dataset.dnode.l0.bin
[0x00001400]> 0x00000800
[0x00000800]> s+0x40
[0x00000840]> pf [2]q[2]q[2]qq[2]qqqq[4]q blk_dva_0 blk_dva_1 blk_dva_2 blk_prop blk_pad[2] blk_phys_birth blk_birth blk_fill blk_cksum
blk_dva_0 : 0x00000840 = (qword)[ 0x0100032143000000, 0x0cfd073129805300 ]
blk_dva_1 : 0x00000850 = (qword)[ 0x2e07121a00020f00, 0x4230220007801200 ]
blk_dva_2 : 0x00000860 = (qword)[ 0x08121700020f0008, 0x31353f004003002b ]
blk_prop : 0x00000870 = (qword)0x8014008f8c0001ff
blk_pad[2] : 0x00000878 = (qword)[ 0x0040091b1c004232, 0x00020f1c0040331f ]
blk_phys_birth : 0x00000888 = (qword)0x00000000000050e8
blk_birth : 0x00000890 = (qword)0x0000000000000022
blk_fill : 0x00000898 = (qword)0x0000000000000000
blk_cksum : 0x000008a0 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]

Это Embedded blkptr(бит E), структура отличается от обычного blkptr.
image

Данные хранятся непосредственно в структуре.

[0x00000840]> pf [48]bq[24]bq[40]b data_1 blk_prob data_2 txg data_3
data_1 : 0x00000840 = [ 0x00, 0x00, 0x00, 0x43, 0x21, 0x03, 0x00, 0x01, 0x00, 0x53, 0x80, 0x29, 0x31, 0x07, 0xfd, 0x0c, 0x00, 0x0f, 0x02, 0x00, 0x1a, 0x12, 0x07, 0x2e, 0x00, 0x12, 0x80, 0x07, 0x00, 0x22, 0x30, 0x42, 0x08, 0x00, 0x0f, 0x02, 0x00, 0x17, 0x12, 0x08, 0x2b, 0x00, 0x03, 0x40, 0x00, 0x3f, 0x35, 0x31 ]
blk_prob : 0x00000870 = (qword)0x8014008f8c0001ff
data_2 : 0x00000878 = [ 0x32, 0x42, 0x00, 0x1c, 0x1b, 0x09, 0x40, 0x00, 0x1f, 0x33, 0x40, 0x00, 0x1c, 0x0f, 0x02, 0x00, 0xe8, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
txg : 0x00000890 = (qword)0x0000000000000022
data_3 : 0x00000898 = [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]


Считаем эти данные в файл
Последовательно копируем 48 байт и пропустив blk_prob (8 байт) оставшиеся 23 байта (полный размер берется из поля PSIZE).
# dd if=os.dataset.dnode.l0.bin of=/tmp/emb.bin.lz4 bs=1 count=48 skip=2112
# dd if=os.dataset.dnode.l0.bin of=/tmp/emb.bin.lz4 bs=1 seek=48 count=23 skip=2168
# zdec emb.bin.lz4 emb.bin 512
Input: emb.bin.lz4
Output: emb.bin
Out size: 512
-----------------------------
Input size: 71
Real input size: 67
Decompress result: 0

# r2 emb.bin
[0x00000000]> pf qqq[5]qqxwz mz_block_type mz_salt mz_normflags mz_pad[5] mz_chunk[1]_mze_value mz_chunk[1]_mze_cd mz_chunk[1]_mze_pad mz_chunk[1]_mze_name
mz_block_type : 0x00000000 = (qword)0x8000000000000003
mz_salt : 0x00000008 = (qword)0x00000003fd073129
mz_normflags : 0x00000010 = (qword)0x0000000000000000
mz_pad[5] : 0x00000018 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
mz_chunk[1]_mze_value : 0x00000040 = (qword)0x8000000000000007
mz_chunk[1]_mze_cd : 0x00000048 = 0x00000000
mz_chunk[1]_mze_pad : 0x0000004c = 0x0000
mz_chunk[1]_mze_name : 0x0000004e = 0B
[0x00000000]> s+0x80
[0x00000080]> pf qxwz mze_value mze_cd mze_pad mze_name
mze_value : 0x00000080 = (qword)0x8000000000000008
mze_cd : 0x00000088 = 0x00000000
mze_pad : 0x0000008c = 0x0000
mze_name : 0x0000008e = 512B
[0x00000080]> s+0x40
[0x000000c0]> pf qxwz mze_value mze_cd mze_pad mze_name
mze_value : 0x000000c0 = (qword)0x8000000000000009
mze_cd : 0x000000c8 = 0x00000000
mze_pad : 0x000000cc = 0x0000
mze_name : 0x000000ce = 513B

mze_value : 0x8000000000000007
ZFS_DIRENT_TYPE : 8 // "? (0x8000000000000007>60)&((1<4)-1)" // /* 8 */ "Regular File",
ZFS_DIRENT_OBJ : 7 // "? (0x8000000000000007>0)&((1<48)-1)" // Object id

0B файл имеет номер 7
512B файл имеет номер 8
513B файл имеет номер 9

Считаем объект 7
# r2 os.dataset.dnode.l0.bin
[0x00000000]> 0x00000e00
[0x00000e00]> s+0x40
[0x00000e40]> pf [2]q[2]q[2]qq[2]qqqq[4]q blk_dva_0 blk_dva_1 blk_dva_2 blk_prop blk_pad[2] blk_phys_birth blk_birth blk_fill blk_cksum
blk_dva_0 : 0x00000e40 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_dva_1 : 0x00000e50 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_dva_2 : 0x00000e60 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_prop : 0x00000e70 = (qword)0x0000000000000000
blk_pad[2] : 0x00000e78 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_phys_birth : 0x00000e88 = (qword)0x0000000000000000
blk_birth : 0x00000e90 = (qword)0x0000000000000000
blk_fill : 0x00000e98 = (qword)0x0000000000000000
blk_cksum : 0x00000ea0 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]

Файл не содержит данных — blkptr пустой.

Считаем объект 8
[0x00000e40]> 0x00001000
[0x00001000]> s+0x40
[0x00001040]> pf [2]q[2]q[2]qq[2]qqqq[4]q blk_dva_0 blk_dva_1 blk_dva_2 blk_prop blk_pad[2] blk_phys_birth blk_birth blk_fill blk_cksum
blk_dva_0 : 0x00001040 = (qword)[ 0x0000000000000001, 0x00000000000000e9 ]
blk_dva_1 : 0x00001050 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_dva_2 : 0x00001060 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_prop : 0x00001070 = (qword)0x8013070200000000
blk_pad[2] : 0x00001078 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_phys_birth : 0x00001088 = (qword)0x0000000000000000
blk_birth : 0x00001090 = (qword)0x0000000000000020
blk_fill : 0x00001098 = (qword)0x0000000000000001
blk_cksum : 0x000010a0 = (qword)[ 0x0000003c34e2ea5c, 0x00000f3db2d3ec9f, 0x00029bdcc6458734, 0x005654ddd2b56e82 ]

image

Файл занимает на диске один сектор, т.е. 512 байт.

Считаем объект 9
[0x00001040]> 0x1200
[0x00001200]> s+0x40
[0x00001240]> pf [2]q[2]q[2]qq[2]qqqq[4]q blk_dva_0 blk_dva_1 blk_dva_2 blk_prop blk_pad[2] blk_phys_birth blk_birth blk_fill blk_cksum
blk_dva_0 : 0x00001240 = (qword)[ 0x0000000000000001, 0x000000000000009d ]
blk_dva_1 : 0x00001250 = (qword)[ 0x0000000000000001, 0x0000000000000059 ]
blk_dva_2 : 0x00001260 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_prop : 0x00001270 = (qword)0x8113070f0000001f
blk_pad[2] : 0x00001278 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_phys_birth : 0x00001288 = (qword)0x0000000000000000
blk_birth : 0x00001290 = (qword)0x0000000000000022
blk_fill : 0x00001298 = (qword)0x0000000000000002
blk_cksum : 0x000012a0 = (qword)[ 0x0000001427d4c96a, 0x000007e5038b685d, 0x000194254db44203, 0x0037093ef743abcc ]

image

Файл размером 513 байт не помещается полностью в recordsize равную 512 байтам и для его хранения задействуется косвенный блок.
Косвенный блок хранится в двух экземплярах (blk_dva_0 и blk_dva_1).
Отсюда размеры файлов на диске:
0B: dnode(512B) = 512 байт
512B: dnode(512B) + данные файла(512B) = 1024 байт
513B: dnode(512B) + 2*косвенных блока(512B) + 2*данные файла(512B) = 2560 байт

Программа для распаковки блока сжатого алгоритмом lz4
Представляет собой копию функции LZ4_uncompress_unknownOutputSize из файла lz4.c

#include <iostream>
#include <fstream>
#include <cstdint>
#include <cstring>

using namespace std;

static int LZ4_uncompress_unknownOutputSize(const char *source, char *dest,
int isize, int maxOutputSize);


#define BE_IN8(xa) \
        *((uint8_t *)(xa))

#define BE_IN16(xa) \
(((uint16_t)BE_IN8(xa) << 8) | BE_IN8((uint8_t *)(xa)+1))

#define BE_IN32(xa) \
(((uint32_t)BE_IN16(xa) << 16) | BE_IN16((uint8_t *)(xa)+2))


#define COMPRESSIONLEVEL 12
#define NOTCOMPRESSIBLE_CONFIRMATION 6

/*
 *
 * CPU Feature Detection
 */

/* 32 or 64 bits ? */
#if defined(_LP64)
#define LZ4_ARCH64 1
#else
#define LZ4_ARCH64 0
#endif

/*
 * Little Endian or Big Endian?
 * Note: overwrite the below #define if you know your architecture endianess.
 */
#if defined(_BIG_ENDIAN)
#define LZ4_BIG_ENDIAN 1
#else
/*
 * Little Endian assumed. PDP Endian and other very rare endian format
 * are unsupported.
 */
#undef LZ4_BIG_ENDIAN
#endif

/*
 * Unaligned memory access is automatically enabled for "common" CPU,
 * such as x86. For others CPU, the compiler will be more cautious, and
 * insert extra code to ensure aligned access is respected. If you know
 * your target CPU supports unaligned memory access, you may want to
 * force this option manually to improve performance
 */
#if defined(__ARM_FEATURE_UNALIGNED)
#define LZ4_FORCE_UNALIGNED_ACCESS 1
#endif

/*
 * Illumos : we can't use GCC's __builtin_ctz family of builtins in the
 * kernel
 * Linux : we can use GCC's __builtin_ctz family of builtins in the
 * kernel
 */
#undef  LZ4_FORCE_SW_BITCOUNT
#if defined(__sparc)
#define LZ4_FORCE_SW_BITCOUNT
#endif

/*
 * Compiler Options
 */
/* Disable restrict */
#define restrict

/*
 * Linux : GCC_VERSION is defined as of 3.9-rc1, so undefine it.
 * torvalds/linux@3f3f8d2f48acfd8ed3b8e6b7377935da57b27b16
 */
#ifdef GCC_VERSION
#undef GCC_VERSION
#endif

#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)

#if (GCC_VERSION >= 302) || (__INTEL_COMPILER >= 800) || defined(__clang__)
#define expect(expr, value)    (__builtin_expect((expr), (value)))
#else
#define expect(expr, value)    (expr)
#endif

#ifndef likely
#define likely(expr)    expect((expr) != 0, 1)
#endif

#ifndef unlikely
#define unlikely(expr)  expect((expr) != 0, 0)
#endif

#define lz4_bswap16(x) ((unsigned short int) ((((x) >> 8) & 0xffu) | \
        (((x) & 0xffu) << 8)))

/* Basic types */
#define BYTE    uint8_t
#define U16     uint16_t
#define U32     uint32_t
#define S32     int32_t
#define U64     uint64_t

#ifndef LZ4_FORCE_UNALIGNED_ACCESS
#pragma pack(1)
#endif

typedef struct _U16_S {
        U16 v;
} U16_S;
typedef struct _U32_S {
        U32 v;
} U32_S;
typedef struct _U64_S {
        U64 v;
} U64_S;

#ifndef LZ4_FORCE_UNALIGNED_ACCESS
#pragma pack()
#endif

#define A64(x) (((U64_S *)(x))->v)
#define A32(x) (((U32_S *)(x))->v)
#define A16(x) (((U16_S *)(x))->v)

/*
 * Constants
 */
#define MINMATCH 4

#define HASH_LOG COMPRESSIONLEVEL
#define HASHTABLESIZE (1 << HASH_LOG)
#define HASH_MASK (HASHTABLESIZE - 1)

#define SKIPSTRENGTH (NOTCOMPRESSIBLE_CONFIRMATION > 2 ? \
        NOTCOMPRESSIBLE_CONFIRMATION : 2)

#define COPYLENGTH 8
#define LASTLITERALS 5
#define MFLIMIT (COPYLENGTH + MINMATCH)
#define MINLENGTH (MFLIMIT + 1)

#define MAXD_LOG 16
#define MAX_DISTANCE ((1 << MAXD_LOG) - 1)

#define ML_BITS 4
#define ML_MASK ((1U<<ML_BITS)-1)
#define RUN_BITS (8-ML_BITS)
#define RUN_MASK ((1U<<RUN_BITS)-1)

/*
 * Architecture-specific macros
 */
#if LZ4_ARCH64
#define STEPSIZE 8
#define UARCH U64
#define AARCH A64
#define LZ4_COPYSTEP(s, d)      A64(d) = A64(s); d += 8; s += 8;
#define LZ4_COPYPACKET(s, d)    LZ4_COPYSTEP(s, d)
#define LZ4_SECURECOPY(s, d, e) if (d < e) LZ4_WILDCOPY(s, d, e)
#define HTYPE U32
#define INITBASE(base)          const BYTE* const base = ip
#else /* !LZ4_ARCH64 */
#define STEPSIZE 4
#define UARCH U32
#define AARCH A32
#define LZ4_COPYSTEP(s, d)      A32(d) = A32(s); d += 4; s += 4;
#define LZ4_COPYPACKET(s, d)    LZ4_COPYSTEP(s, d); LZ4_COPYSTEP(s, d);
#define LZ4_SECURECOPY          LZ4_WILDCOPY
#define HTYPE const BYTE *
#define INITBASE(base)          const int base = 0
#endif /* !LZ4_ARCH64 */

#if (defined(LZ4_BIG_ENDIAN) && !defined(BIG_ENDIAN_NATIVE_BUT_INCOMPATIBLE))
#define LZ4_READ_LITTLEENDIAN_16(d, s, p) \
        { U16 v = A16(p); v = lz4_bswap16(v); d = (s) - v; }
#define LZ4_WRITE_LITTLEENDIAN_16(p, i) \
        { U16 v = (U16)(i); v = lz4_bswap16(v); A16(p) = v; p += 2; }
#else
#define LZ4_READ_LITTLEENDIAN_16(d, s, p) { d = (s) - A16(p); }
#define LZ4_WRITE_LITTLEENDIAN_16(p, v)  { A16(p) = v; p += 2; }
#endif


/* Local structures */
struct refTables {
        HTYPE hashTable[HASHTABLESIZE];
};


/* Macros */
#define LZ4_HASH_FUNCTION(i) (((i) * 2654435761U) >> ((MINMATCH * 8) - \
        HASH_LOG))
#define LZ4_HASH_VALUE(p) LZ4_HASH_FUNCTION(A32(p))
#define LZ4_WILDCOPY(s, d, e) do { LZ4_COPYPACKET(s, d) } while (d < e);
#define LZ4_BLINDCOPY(s, d, l) { BYTE* e = (d) + l; LZ4_WILDCOPY(s, d, e); \
d = e; }



static int
LZ4_uncompress_unknownOutputSize(const char *source, char *dest, int isize,
    int maxOutputSize)
{
        /* Local Variables */
        const BYTE *restrict ip = (const BYTE *) source;
        const BYTE *const iend = ip + isize;
        const BYTE *ref;

        BYTE *op = (BYTE *) dest;
        BYTE *const oend = op + maxOutputSize;
        BYTE *cpy;

        size_t dec32table[] = {0, 3, 2, 3, 0, 0, 0, 0};
#if LZ4_ARCH64
        size_t dec64table[] = {0, 0, 0, (size_t)-1, 0, 1, 2, 3};
#endif

        /* Main Loop */
        while (ip < iend) {
                unsigned token;
                size_t length;

                /* get runlength */
                token = *ip++;
                if ((length = (token >> ML_BITS)) == RUN_MASK) {
                        int s = 255;
                        while ((ip < iend) && (s == 255)) {
                                s = *ip++;
                                length += s;
                        }
                }
                /* copy literals */
                cpy = op + length;
                /* CORNER-CASE: cpy might overflow. */
                if (cpy < op)
                        goto _output_error;     /* cpy was overflowed, bail! */
                if ((cpy > oend - COPYLENGTH) ||
                    (ip + length > iend - COPYLENGTH)) {
                        if (cpy > oend)
                                /* Error: writes beyond output buffer */
                                goto _output_error;
                        if (ip + length != iend)
                                /*
                                 * Error: LZ4 format requires to consume all
                                 * input at this stage
                                 */
                                goto _output_error;
                        (void) memcpy(op, ip, length);
                        op += length;
                        /* Necessarily EOF, due to parsing restrictions */
                        break;
                }
                LZ4_WILDCOPY(ip, op, cpy);
                ip -= (op - cpy);
                op = cpy;

                /* get offset */
                LZ4_READ_LITTLEENDIAN_16(ref, cpy, ip);
                ip += 2;
                if (ref < (BYTE * const) dest)
                        /*
                         * Error: offset creates reference outside of
                         * destination buffer
                         */
                        goto _output_error;

                /* get matchlength */
                if ((length = (token & ML_MASK)) == ML_MASK) {
                        while (ip < iend) {
                                int s = *ip++;
                                length += s;
                                if (s == 255)
                                        continue;
                                break;
                        }
                }
                /* copy repeated sequence */
                if (unlikely(op - ref < STEPSIZE)) {
#if LZ4_ARCH64
                        size_t dec64 = dec64table[op-ref];
#else
                        const int dec64 = 0;
#endif
                        op[0] = ref[0];
                        op[1] = ref[1];
                        op[2] = ref[2];
                        op[3] = ref[3];
                        op += 4;
                        ref += 4;
                        ref -= dec32table[op-ref];
                        A32(op) = A32(ref);
                        op += STEPSIZE - 4;
                        ref -= dec64;
                } else {
                        LZ4_COPYSTEP(ref, op);
                }
                cpy = op + length - (STEPSIZE - 4);
                if (cpy > oend - COPYLENGTH) {
                        if (cpy > oend)
                                /*
                                 * Error: request to write outside of
                                 * destination buffer
                                 */
                                goto _output_error;
                        LZ4_SECURECOPY(ref, op, (oend - COPYLENGTH));
                        while (op < cpy)
                                *op++ = *ref++;
                        op = cpy;
                        if (op == oend)
                                /*
                                 * Check EOF (should never happen, since
                                 * last 5 bytes are supposed to be literals)
                                 */
                                goto _output_error;
                        continue;
                }
                LZ4_SECURECOPY(ref, op, cpy);
                op = cpy;       /* correction */
        }

        /* end of decoding */
        return (int)(((char *)op) - dest);

        /* write overflow error detected */
        _output_error:
        return (int)(-(((char *)ip) - source));
}

/*ARGSUSED*/
int
lz4_decompress_zfs(void *s_start, void *d_start, size_t s_len,
    size_t d_len, int n)
{
        const char *src = (const char*) s_start;
        uint32_t bufsiz = BE_IN32(src);

        /* invalid compressed buffer size encoded at start */
        if (bufsiz + sizeof (bufsiz) > s_len)
                return (1);

        std::cout << "Real input size: " << bufsiz << std::endl;
        /*
         * Returns 0 on success (decompression function returned non-negative)
         * and non-zero on failure (decompression function returned negative.
         */
        return (LZ4_uncompress_unknownOutputSize(&src[sizeof (bufsiz)],
            (char*)d_start, bufsiz, d_len) < 0);
}

int main( int argc, char **argv )
{
        if (argc < 4) {
                std::cout << argv[0] << " <in> <out> <out_size>" << std::endl;

                return 1;
        }

        char* szInput = argv[1];
        char* szOutput = argv[2];
        int nOutSize = atoi(argv[3]);

        std::cout << "Input: \t\t" << szInput << std::endl;
        std::cout << "Output: \t" << szOutput << std::endl;
        std::cout << "Out size: \t" << nOutSize << std::endl;
        std::cout << "-----------------------------" << std::endl;

// READ INPUT
        fstream fs(szInput, fstream::in);
        if (!fs.is_open()) {
                std::cout << "Open error";
                return 1;
        }

        fs.seekg(0, ios::end);
        int fileSize = fs.tellg();
        std::cout << "Input size: \t" << fileSize << std::endl;

        char* src = new char[fileSize];

        fs.seekg(0, ios::beg);

        fs.read(src, fileSize);
        if (!fs) {
                std::cout << "error: only " << fs.gcount() << " could be read";
                fs.close();
                return 1;
        }
        fs.close();
// END READ INPUT

// DECOMPRESS
        char* dst = new char[nOutSize];
        std::memset(dst, 0, nOutSize);

        int nRes = lz4_decompress_zfs(src, dst, fileSize, nOutSize, 0);
        std::cout << "Decompress result: " << nRes << std::endl;
        if (nRes) {
                std::cout << "Decompress error" << std::endl;
//              return 1;
        }
// END DECOMPRESS

// OUTPUT
        fstream out(szOutput, fstream::out);
        if (!out.is_open()) {
                std::cout << "Open error";
                return 1;
        }

        out.write(dst, nOutSize);
        if (!out) {
                std::cout << "error: only " << out.gcount() << " could be write";
                out.close();
                return 1;
        }
        out.close();

// END OUTPUT

        delete[] src;
        delete[] dst;

        return 0;
}

Ads
AdBlock has stolen the banner, but banners are not teeth — they will be back

More

Comments 0

Only users with full accounts can post comments. Log in, please.