Bug #4082

zfs receive gets EFBIG from dmu_tx_hold_free()

Added by Christopher Siden over 7 years ago. Updated about 7 years ago.

zfs - Zettabyte File System
Start date:
Due date:
% Done:


Estimated time:
Gerrit CR:


Analysis by Matt Ahrens (this is a regression caused by #4047):

The problem occurs when an object is reused for a new file which has a
non-power-of-2 blocksize.  In this case, 27_27.dbf (a large file with block
size=8K) was reused for initEC5.ora (a small file with a single 2.5KB block).

The problem occurs due to the following sequence of events:

First we process the OBJECT record in the send stream.
    Call dmu_object_reclaim() with the new, non-power-of-2 blocksize
        Call dmu_free_long_range() to free the entire file
            New code (#4047) in dmu_free_long_range_impl() does not pass
length=-1 to dnode_free_range()
                dnode_free_range() does not realize we are truncating, and thus
does not decrease dn_maxblkid
        Call dnode_reallocate() to change the dnode configuration
            If debug build fail ASSERT(dn_maxblkid == 0)

Assuming we didn't fail the assertion, next we will process the FREE record
which frees the remainder of the file (e.g from 2.5K to the end)
    Eventually call dmu_tx_hold_free(off=2.5K, len=<big>)
        New code (24744) calls dmu_tx_count_write() on entire specified range
        Too much space has been scheduled to write, so fail with EFBIG

The most expedient fix is to add code to zero out dn_maxblkid when doing

We can also make the code in dmu_tx_hold_free() more resilient by having it
dmu_tx_count_write() only the first block of non-power-of-2 blocksize files
(which only have one block).

The problem can be reproduced by the following script:

#!/bin/bash -x

zpool create test c1t1d0

# clean up from previous run
zfs destroy -r test/fs
zfs destroy -r test/recvd

zfs create -o recordsize=8k test/fs

dd if=/dev/zero of=/test/fs/big bs=1024k count=100

# need to create enough files that ZFS will go back and reuse
# object numbers
for (( i=0; i<4000; i=i+1 )); do
        echo >/test/fs/empty-$i

zfs snapshot test/fs@big

find /test/fs | xargs rm

# replace "big" file with a file with uneven blocksize (1.5k)
for (( i=0; i<100; i=i+1 )); do
        dd if=/dev/zero of=/test/fs/small-$i bs=1200 count=1

zfs snapshot test/fs@small

zfs send test/fs@big | zfs recv test/recvd

# this receive will fail
zfs send -i @big test/fs@small | zfs recv test/recvd

Related issues

Related to illumos gate - Bug #4047: panic from dbuf_free_range() from dmu_free_object() while doing zfs receiveClosedChristopher Siden2013-08-16


Updated by Christopher Siden about 7 years ago

  • Status changed from In Progress to Closed
commit 5253393b09789ec67bec153b866d7285a1cf1645
Author: Matthew Ahrens <>
Date:   Fri Aug 30 02:19:35 2013

    4082 zfs receive gets EFBIG from dmu_tx_hold_free()
    Reviewed by: Eric Schrock <>
    Reviewed by: Christopher Siden <>
    Reviewed by: George Wilson <>
    Approved by: Richard Lowe <>

Also available in: Atom PDF