(edited to add block-by-block, 1:1)
Well, looks like there's yet another thing I can't seem to understand or grasp my head around. I've been trying to do this for several days and just can't get it right. Many mistakes were made, but I just can't figure out the right solution. .
What I'm trying to do sounds rather simple: I have a hard disk with 512 byte sectors. It's an old one, from before 4k sectors were even a consideration. Now I want to block-by-block 1:1 copy the entire disk to a ZFS volume on a pool which has a minimum ashift of 12, aka 4096. This sounds pretty much what ZFS volumes were intented to do to me. I've been searching the internet but either I'm looking at all the wrong info or I'm the first to try this rather trivial sounding task.
So, I started with the following (modified for simplicity):
*
*
*
At this point, I understood what happened. The 512 byte blocks were copied onto 8K blocks with 16 at a time (or 4K blocks with 8 at a time), leaving the filesystem without the correct number of blocks. Logically the next step was to reduce the size of the blocks in the newly created volume to 512. From that point things just didn't work out as planned.
Doing the exact same steps, but with block size 512. This time I used dd with a smaller blocksize because of something in the manpage on the "bs" operand: "...then each input block is copied to the output as a single block without any aggregation of short blocks." Great, sounds like what I need, right?
*
*
I didn't get to the point where I can import the old pool because my volume pool ran out of space, I checked and apparently the new volume used 8 times (4096/512, not 8192/512) more disk space then it should. I'm fairly certain that if I had had the disk space it would have worked because at least the amount of blocks should be correct. Still that's a massive overhead.
So, I thought that maybe I should somehow use 4K or 8K blocks together with ZLE (runs of zeroes) compression and pad every 512 byte block simply with zeroes. I scoured the dd(1) page and it looks like I found options which would do exactly that: ibs/obs/conv=sync. Especially after I read on an IBM manpage (which I thought were the original creators of dd - apparently it's AT&T):
I started experimenting and have probably - hopefully - tried every single combination of these 3 options many times over (and others, like fsync etc) hoping to get the right output. I tried piping dd from one reading process to a writing process
Disappointed I looked back to the metaphorical other side of the equation: the ZFS volume itself. In the OpenZFS documentation I read the following: "It’s meaningless to set volblocksize less than guest FS’s block size or ashift". Ok, fine, maybe that's the reason. Next experimentation:
And that's pretty much where I hit 2 dead ends. Somehow I need to solve this, but I'm all out of ideas. If anyone has a suggestion, or can help me get my ZFS or DD command line right, I'm all for it.
For the record: there is a simple solution and that is to forego ZFS volumes and use a simple dd image on a filesystem/ZFS dataset. That's perfectly fine to work with, but I have this feeling that this is what ZFS volumes are intended for and it should be possible. Especially folks trying to virtualize physical machines should hit this over and over again right? I can't understand why the internet isn't filled with this question so either it must be extremely trivial and I'm just dense, or people resorted to workarounds like I'm probably going to.
If it helps to try out some things, here's the last script I used to try out the ashift idea:
Well, looks like there's yet another thing I can't seem to understand or grasp my head around. I've been trying to do this for several days and just can't get it right. Many mistakes were made, but I just can't figure out the right solution. .
What I'm trying to do sounds rather simple: I have a hard disk with 512 byte sectors. It's an old one, from before 4k sectors were even a consideration. Now I want to block-by-block 1:1 copy the entire disk to a ZFS volume on a pool which has a minimum ashift of 12, aka 4096. This sounds pretty much what ZFS volumes were intented to do to me. I've been searching the internet but either I'm looking at all the wrong info or I'm the first to try this rather trivial sounding task.
So, I started with the following (modified for simplicity):
*
zfs create -V 1T pool/volume
: create volume, leaving blocksize untouched (resulting in 8K blocks default setting on top of ashift 12 sysctl created pool)*
dd if=/dev/harddisk of=/dev/zvol/pool/volume bs=256m
: copy the data, blocksize set to speed up the process*
zpool import ...
: import the zpool on the disk, which shows me this: "UNAVAIL insufficient replicas"At this point, I understood what happened. The 512 byte blocks were copied onto 8K blocks with 16 at a time (or 4K blocks with 8 at a time), leaving the filesystem without the correct number of blocks. Logically the next step was to reduce the size of the blocks in the newly created volume to 512. From that point things just didn't work out as planned.
Doing the exact same steps, but with block size 512. This time I used dd with a smaller blocksize because of something in the manpage on the "bs" operand: "...then each input block is copied to the output as a single block without any aggregation of short blocks." Great, sounds like what I need, right?
*
zfs create -b 512 -V 1g pool/volume
: create volume, leaving blocksize untouched (resulting in 8K blocks)*
dd if=/dev/harddisk of=/dev/zvol/pool/volume bs=512
: copy the data, blocksize set to speed up the processI didn't get to the point where I can import the old pool because my volume pool ran out of space, I checked and apparently the new volume used 8 times (4096/512, not 8192/512) more disk space then it should. I'm fairly certain that if I had had the disk space it would have worked because at least the amount of blocks should be correct. Still that's a massive overhead.
So, I thought that maybe I should somehow use 4K or 8K blocks together with ZLE (runs of zeroes) compression and pad every 512 byte block simply with zeroes. I scoured the dd(1) page and it looks like I found options which would do exactly that: ibs/obs/conv=sync. Especially after I read on an IBM manpage (which I thought were the original creators of dd - apparently it's AT&T):
The conv=sync is required when reading from disk and when the file size is not a multiple of the diskette block size. Do not try this if the input to the dd command is a pipe instead of a file, it will pad most of the input with nulls instead of just the last block.
I started experimenting and have probably - hopefully - tried every single combination of these 3 options many times over (and others, like fsync etc) hoping to get the right output. I tried piping dd from one reading process to a writing process
dd if=... | dd of=..
testing out all of these options on both sides (again, I hope). But nothing, absolutely nothing. Whatever I tried, I couldn't get the output of dd to pad blocks (I checked this thoroughly by using test files and hexdump
).Disappointed I looked back to the metaphorical other side of the equation: the ZFS volume itself. In the OpenZFS documentation I read the following: "It’s meaningless to set volblocksize less than guest FS’s block size or ashift". Ok, fine, maybe that's the reason. Next experimentation:
sysctl vfs.zfs.min_auto_ashift=9
. That should solve things, right? ... Spoiler alert: I would be writing a tutorial instead of a question if it did.And that's pretty much where I hit 2 dead ends. Somehow I need to solve this, but I'm all out of ideas. If anyone has a suggestion, or can help me get my ZFS or DD command line right, I'm all for it.
For the record: there is a simple solution and that is to forego ZFS volumes and use a simple dd image on a filesystem/ZFS dataset. That's perfectly fine to work with, but I have this feeling that this is what ZFS volumes are intended for and it should be possible. Especially folks trying to virtualize physical machines should hit this over and over again right? I can't understand why the internet isn't filled with this question so either it must be extremely trivial and I'm just dense, or people resorted to workarounds like I'm probably going to.
If it helps to try out some things, here's the last script I used to try out the ashift idea:
Code:
#!/bin/sh
# provide "off" as parameter to simply turn compression off; doesn't make a difference as far as I could see
COMPRESS=${1:-zle}
# restore ashift just in case I ctrl+c'ed in the middle of the script or hit an error
sysctl vfs.zfs.min_auto_ashift=12
SRC=$(mdconfig -s 32m -S 512)
dd if=/dev/random bs=512 of=/dev/${SRC} status=progress
POOL=$(mdconfig -s 1g -S 4096)
#POOL=$(mdconfig -s 128m -S 4096)
zpool create mem ${POOL}
sysctl vfs.zfs.min_auto_ashift=9
zfs create -b 512 -o compression=${COMPRESS} -V 32m mem/volume
#zfs create -b 4096 -o compression=${COMPRESS} -V 32m mem/volume
#zfs create -b 8192 -o compression=${COMPRESS} -V 32m mem/volume
dd if=/dev/zero of=/dev/zvol/mem/volume ibs=512 obs=4096 conv=sync
#HEX=$(mdconfig -s 250m)
HEX=$(mdconfig -s 2g)
newfs /dev/${HEX}
mount /dev/${HEX} /mnt
hexdump -v /dev/${SRC} > /mnt/orig.hex
dd if=/dev/${SRC} bs=512 of=/dev/zvol/mem/volume status=progress
#dd if=/dev/${SRC} of=/dev/zvol/mem/volume status=progress ibs=512 obs=4096 conv=sync
hexdump -v /dev/zvol/mem/volume > /mnt/volume.hex
echo "=========== COMPARISON ==========="
diff -sq /mnt/orig.hex /mnt/volume.hex
echo "=========== /COMPARISON =========="
sysctl vfs.zfs.min_auto_ashift=12
zfs get all mem/volume
zpool destroy mem
umount /mnt
mdconfig -d -u $(echo ${HEX} | sed 's/md//')
mdconfig -d -u $(echo ${POOL} | sed 's/md//')
mdconfig -d -u $(echo ${SRC} | sed 's/md//')