Bug #8408

dsl_props_set_sync_impl() does not handle nested nvlists correctly

Added by Ezomori Nozomu 4 months ago.

Status:NewStart date:2017-06-17
Priority:LowDue date:
Assignee:Ezomori Nozomu% Done:

100%

Category:zfs - Zettabyte File System
Target version:-
Difficulty:Bite-size Tags:

Description

When iterating over the input nvlist in dsl_props_set_sync_impl() when we don't preserve the nvpair name before looking up ZPROP_VALUE, so when we later go to process it nvpair_name() is always "value" instead of the actual property name.

This results in a couple of bugs in the recv code:

  • received properties are not restored correctly when failing to receive an incremental send stream
  • received properties are not completely replaced by the new ones when successfully receiving an incremental send stream

This was discovered on ZFS on Linux (fixed in https://github.com/zfsonlinux/zfs/commit/5f1346c29997dd4e02acf4c19c875d5484f33b1e)

Reproducer:

# misc functions
function is_linux() {
   if [[ "$(uname)" == "Linux" ]]; then
      return 0
   else
      return 1
   fi
}
# setup
POOLNAME='testpool'
if is_linux; then
   TMPDIR='/var/tmp'
   mountpoint -q $TMPDIR || mount -t tmpfs tmpfs $TMPDIR
   zpool destroy $POOLNAME
   fallocate -l 65m $TMPDIR/zpool.dat
   zpool create $POOLNAME $TMPDIR/zpool.dat
else
   TMPDIR='/tmp'
   zpool destroy $POOLNAME
   mkfile 65m $TMPDIR/zpool.dat
   zpool create $POOLNAME $TMPDIR/zpool.dat
fi
# send first stream, received compression is 'on'
zfs create $POOLNAME/send
zfs set compression=on $POOLNAME/send
zfs snap $POOLNAME/send@snap1
zfs send -p $POOLNAME/send@snap1 > $TMPDIR/snap_full.dat
zfs recv $POOLNAME/recv < $TMPDIR/snap_full.dat
zfs get -o all compression $POOLNAME/recv
# send second stream, compression is 'lz4'
zfs set compression=lz4 $POOLNAME/send
dd if=/dev/urandom of=/$POOLNAME/send/urandom bs=1M count=10
zfs snap $POOLNAME/send@snap2
zfs send -pI $POOLNAME/send@snap1 $POOLNAME/send@snap2 > $TMPDIR/snap_incr.dat
# truncate the stream, fail to receive incremental
dd if=/dev/null of=$TMPDIR/snap_incr.dat bs=1 count=1 seek=9M
zfs recv -F $POOLNAME/recv < $TMPDIR/snap_incr.dat
# zfs receive failed, compression should be 'on'
zfs get -o all compression $POOLNAME/recv

This is the resulting properties on "testpool/recv": we have a "value" property instead of "compression"

[root@52-54-00-d3-7a-01 ~]# zdb -dddd testpool 49
Dataset mos [META], ID 0, cr_txg 4, 114K, 64 objects, rootbp DVA[0]=<0:17b2e00:200> DVA[1]=<0:17b3000:200> DVA[2]=<0:17b3200:200> [L0 DMU objset] fletcher4 lz4 LE contiguous unique triple size=800L/200P birth=498L/498P fill=64 cksum=11413d065e:672e12e9d76:13ff1f57e066a:2ac3890cc2454c

    Object  lvl   iblk   dblk  dsize  lsize   %full  type
        49    1   128K    512      0    512  100.00  DSL props
    dnode flags: USED_BYTES 
    dnode maxblkid: 0
    microzap: 512 bytes, 2 entries

        value$recvd = 1 
        $hasrecvd = 0

Also available in: Atom