14

Is there a way in zfs to find out where blocks for a particular file are stored? I'd like to be able to ask for the locations of all the blocks for a file, including ditto blocks.

(Yes, I understand that this is low-level stuff not normally exposed to users.)

(v0.6.0.56-rc8, ZFS pool version 28, ZFS filesystem version 5, Ubuntu 11.10)

4 Answers 4

15

This is non trivial and possibly beyond the scope of an SF question/answer as the tools required don't appear well documented. You can probably use zdb(1m) in conjunction with the on disk format doc to find the information you want. There is a blog on how to do this here

Essentially

use ls -i to get the initial inode.

use zdb -ddddd <inodenum> to get the block information and decode it using the ODF

1
  • To specify a pool and dataset: zdb -ddddd <pool>/<dataset> <inodenum>
    – gsgx
    Commented Jun 23 at 20:08
8

ZFS physically stores data using DVA (Device Virtual Addresses) offset + length. You can get the relevant data using something as zdb -bbb -vvv <dataset> -O <filename>. You should keep in mind that:

  • while ZFS stores DVA offset in 512-byte sectors on disk, zdb translate them in bytes
  • zdb output such numbers in hex format
  • offset 0 start after a 4 MB header on each disk.

For example, on a just created (and otherwise empty) test pool:

root@localhost:~# zpool status
  pool: tank
 state: ONLINE
config:

        NAME                     STATE     READ WRITE CKSUM
        tank                     ONLINE       0     0     0
          /root/disks/disk1.img  ONLINE       0     0     0

root@localhost:~# cp /etc/services /tank/
root@localhost:~# zdb -bbb -vvv tank -O services
...
Indirect blocks:
               0 L0 DVA[0]=<0:10007000:4000> [L0 ZFS plain file]

# some math:
# 0x10007000 == 268464128 == 65543 4K blocks
# 65543 + 1024 4K blocks (header) == 66567 4K blocks
# our file starts at 4k offset 66567

# check with dd over the raw device (a backing file, in this test)
root@localhost:~# dd if=/root/disks/disk1.img bs=4k count=1 skip=66567 | head -3
1+0 records in
1+0 records out
4096 bytes (4.1 kB, 4.0 KiB) copied, 2.3434e-05 s, 175 MB/s
# Network services, Internet style
#
# Updated from https://www.iana.org/assignments/service-names-port-numbers...

Some references:

https://utcc.utoronto.ca/~cks/space/blog/solaris/ZFSDVAOffsetVdevDetails https://utcc.utoronto.ca/~cks/space/blog/solaris/ZFSDVAOffsetsInBytesII

2
  • Wow - a new and useful answer more than a decade after the question was asked! Commented Sep 10, 2023 at 1:43
  • It's not only useful, but vastly more useful than two other answers only mentioning the inode.
    – iBug
    Commented Oct 24, 2023 at 12:33
3

You can use ls -i to see the initial inode, after that I'd suggest reading the source code published to understand the on-disk data structures. After you've completed that I'd suggest writing your own tools to read the raw device and assemble all the block layout information you're interested in. There is a small-ish ZFS API (libzfs) project that only offers basic ZFS configuration like listing, creating etc. zpools.

-1

On FreeBSD, you can obtain the file's object ID with stat(1):

stat -f %i /your/file

Of course, ls -i works as well, but then the number has to be parsed from ls's output with a command like grep.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .