Skip to content

Instantly share code, notes, and snippets.

@niamtokik
Created January 9, 2018 19:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save niamtokik/232a0b59857e4393793895e13eb6e9d9 to your computer and use it in GitHub Desktop.
Save niamtokik/232a0b59857e4393793895e13eb6e9d9 to your computer and use it in GitHub Desktop.
Quick and Dirty implementation of ZFS dmu_replay_record from zfs_ioctl.h (PoC)
%%%-------------------------------------------------------------------
%%% @author Mathieu Kerjouan
%%% @copyright (c) 2018, Mathieu Kerjouan
%%% @doc This is a quick and dirty zfs dmu replay record implementation
%%% in Erlang. This is only a PoC and should not be used in
%%% production. This code is an implementation of zstreamdump
%%% from OpenZFS.
%%% @end
%%%-------------------------------------------------------------------
-module(dmu_replay_record2).
-export([parse/1]).
-define(DMU_RECORD_SIZE, (304*8)).
parse(Bitstring) ->
parse(Bitstring, []).
parse(<<>>, Buf) ->
Buf;
parse(<<DMU_DRR_TYPE:32/little,
DRR_PAYLOADLEN:32/little,
D/bitstring>>, Buf) ->
% dmu_replay_record length with payloadlen
Len = (?DMU_RECORD_SIZE+DRR_PAYLOADLEN*8),
% extract only what we need
<<Data:Len/bitstring, Rest/bitstring>> = D,
% extract extra-data from datastructure with
% bonuslen or length.
Parse = fun(0, R) -> {undefined, R};
(S, R) -> Size = S*8,
<<BD:Size/bitstring, R2/bitstring>> = R,
{BD, R2}
end,
% we check the data-structure type
case DMU_DRR_TYPE of
% drr_begin
0 -> <<DRR_MAGIC:64/bitstring,
DRR_VERSIONINFO:64/bitstring,
DRR_CREATION_TIME:64/little,
DRR_TYPE:32/little,
DRR_FLAGS:32/bitstring,
DRR_TOGUID:64/bitstring,
DRR_FROMGUID:64/bitstring,
DRR_TONAME:256/bitstring,
R/bitstring>> = Data,
parse(Rest,
[{ drr_begin
, #{ magic => DRR_MAGIC
, versioninfo => DRR_VERSIONINFO
, creation_time => DRR_CREATION_TIME
, type => DRR_TYPE
, flags => DRR_FLAGS
, toguid => DRR_TOGUID
, fromguid => DRR_FROMGUID
, toname => DRR_TONAME
}
, R }|Buf]);
% drr_end
5 -> <<DRR_CHECKSUM:256/bitstring,
DRR_TOGUID:64/bitstring,
R/bitstring>> = Data,
parse(Rest,
[{ drr_end
, #{ checksum => DRR_CHECKSUM
, toguid => DRR_TOGUID
}
, R}|Buf]);
% drr_object
1 -> <<DRR_OBJECT:64,
DRR_TYPE:32/little,
DRR_BONUSTYPE:32/little,
DRR_BLKSZ:32/little,
DRR_BONUSLEN:32/little,
DRR_CHECKSUMTYPE:8/little,
DRR_COMPRESS:8/little,
_:(6*8),
DRR_TOGUID:64/bitstring,
R/bitstring>> = Data,
{BonusData, Rest2} = Parse(DRR_BONUSLEN, Rest),
parse(Rest2,
[{ drr_object
, #{ object => DRR_OBJECT
, type => DRR_TYPE
, bonustype => DRR_BONUSTYPE
, blksz => DRR_BLKSZ
, bonuslen => DRR_BONUSLEN
, checksumtype => DRR_CHECKSUMTYPE
, compress => DRR_COMPRESS
, toguid => DRR_TOGUID
, bonus => BonusData
}
, R }|Buf]);
% drr_freeobjects
2 -> <<DRR_FIRSTOBJ:64/bitstring,
DRR_NUMOBJS:64/bitstring,
DRR_TOGUID:64/bitstring,
R/bitstring>> = Data,
parse(Rest,
[{ drr_freeobjects
, #{ firstobj => DRR_FIRSTOBJ
, numobjs => DRR_NUMOBJS
, toguid => DRR_TOGUID
}
, R }|Buf]);
% drr_write
3 -> <<DRR_OBJECT:64/little,
DRR_TYPE:32/little,
_:32,
DRR_OFFSET:64/little,
DRR_LENGTH:64/little,
DRR_TOGUID:64/bitstring,
DRR_CHECKSUMTYPE:8/little,
DRR_CHECKSUMFLAGS:8/little,
_:(8*6),
DRR_KEY:(256+64)/bitstring,
R/bitstring>> = Data,
{WriteData, Rest2} = Parse(DRR_LENGTH, Rest),
parse(Rest2, [{ drr_write
, #{ object => DRR_OBJECT
, type => DRR_TYPE
, offset => DRR_OFFSET
, length => DRR_LENGTH
, toguid => DRR_TOGUID
, checksumtype => DRR_CHECKSUMTYPE
, checksumflags => DRR_CHECKSUMFLAGS
, key => DRR_KEY
, data => WriteData
}
, R}|Buf]);
% drr_free
4 -> <<DRR_OBJECT:64/little,
DRR_OFFSET:64/little,
DRR_LENGTH:64/little,
DRR_TOGUID:64/bitstring,
R/bitstring>> = Data,
parse(Rest, [{ drr_free
, #{ object => DRR_OBJECT
, offset => DRR_OFFSET
, length => DRR_LENGTH
, toguid => DRR_TOGUID
}
, R }|Buf]);
% drr_write_byref
6 -> <<DRR_OBJECT:64/little,
DRR_OFFSET:64/little,
DRR_LENGTH:64/little,
DRR_TOGUID:64/bitstring,
DRR_REFGUID:64/bitstring,
DRR_REFOBJECT:64/bitstring,
DRR_REFOFFSET:64/bitstring,
DRR_CHECKSUMTYPE:8/little,
DRR_CHECKSUMFLAGS:8/little,
_:(6*8),
DRR_KEY:(256+64)/bitstring,
R/bitstring>> = Data,
parse(Rest, [{ drr_write_byref
, #{ object => DRR_OBJECT
, offset => DRR_OFFSET
, length => DRR_LENGTH
, toguid => DRR_TOGUID
, refguid => DRR_REFGUID
, refobject => DRR_REFOBJECT
, refoffset => DRR_REFOFFSET
, checksumtype => DRR_CHECKSUMTYPE
, checksumflags => DRR_CHECKSUMFLAGS
, key => DRR_KEY
}
, R }|Buf]);
% drr_spill
7 -> <<DRR_OBJECT:64/little,
DRR_LENGTH:64/little,
DRR_TOGUID:64/bitstring,
_:(64*4), R/bitstring>> = Data,
parse(Rest, [{ drr_spill
, #{ object => DRR_OBJECT
, length => DRR_LENGTH
, toguid => DRR_TOGUID
}
, R }|Buf]);
% drr_numtypes
_ -> not_supported
end.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment