ZFS recv doesn't properly skip existing snapshots

James R. Van Artsdalen james-freebsd-fs2 at jrv.org
Fri Mar 13 14:30:13 PDT 2009


/home/james# uname -a
FreeBSD bigtex.housenet.jrv 8.0-CURRENT FreeBSD 8.0-CURRENT #0 r189099:
Fri Feb 27 07:09:47 CST 2009    
james at bigtex.housenet.jrv:/usr/obj/usr/src/sys/GENERIC  amd64

"zfs recv" doesn't properly skip existing snapshots in a replication stream.

I'm working on a way to keep a remote pool in sync with a local pool
using zfs send/recv.  It appears that "zfs recv" may not be atomic
across the input stream but only within each individual filesystem. 
This means that the pool replication script must be prepared to handle
the situation where a parent filesystem may have received a snapshot
that a child did not.

It appears "zfs recv" is supposed to simply skip any snapshot it already
has, making me think that it should pick up at the next snapshot record
in the input stream.  But instead "zfs recv" appears to never get in
sync with the input stream again and simple exits.

Comments embedded with hashed below.

/home/james# zfs create bigtex/foo
/home/james# zfs create bigtex/foo/bar
/home/james# zfs snapshot -r bigtex/foo at a
/home/james# zfs snapshot -r bigtex/foo at b
/home/james# zfs snapshot -r bigtex/foo at c
/home/james# zfs snapshot -r bigtex/foo at d
/home/james# zfs list -t snapshot
...
bigtex/foo at a                                                                           
0      -    18K  -
bigtex/foo at b                                                                           
0      -    18K  -
bigtex/foo at c                                                                           
0      -    18K  -
bigtex/foo at d                                                                           
0      -    18K  -
bigtex/foo/bar at a                                                                       
0      -    18K  -
bigtex/foo/bar at b                                                                       
0      -    18K  -
bigtex/foo/bar at c                                                                       
0      -    18K  -
bigtex/foo/bar at d                                                                       
0      -    18K  -

# send initial data.  Works as expected.
/home/james# /root/zfs send -v -R bigtex/foo at b | /root/zfs recv -dv
bigtmptex
sending from @ to bigtex/foo at a
receiving full stream of bigtex/foo at a into bigtmptex/foo at a
sending from @a to bigtex/foo at b
sending from @ to bigtex/foo/bar at a
sending from @a to bigtex/foo/bar at b
received 13.6KB stream in 1 seconds (13.6KB/sec)
receiving incremental stream of bigtex/foo at b into bigtmptex/foo at b
received 312B stream in 1 seconds (312B/sec)
receiving full stream of bigtex/foo/bar at a into bigtmptex/foo/bar at a
received 13.6KB stream in 1 seconds (13.6KB/sec)
receiving incremental stream of bigtex/foo/bar at b into bigtmptex/foo/bar at b
received 312B stream in 1 seconds (312B/sec)

# send incremental update.  Works as expected.
/home/james# /root/zfs send -RvI @b bigtex/foo at d | /root/zfs recv -dvF
bigtmptex
sending from @b to bigtex/foo at c
sending from @c to bigtex/foo at d
sending from @b to bigtex/foo/bar at c
sending from @c to bigtex/foo/bar at d
receiving incremental stream of bigtex/foo at c into bigtmptex/foo at c
received 312B stream in 1 seconds (312B/sec)
receiving incremental stream of bigtex/foo at d into bigtmptex/foo at d
received 312B stream in 1 seconds (312B/sec)
receiving incremental stream of bigtex/foo/bar at c into bigtmptex/foo/bar at c
received 312B stream in 1 seconds (312B/sec)
receiving incremental stream of bigtex/foo/bar at d into bigtmptex/foo/bar at d
received 312B stream in 1 seconds (312B/sec)

# The results are correct.
/home/james# zfs list -t snapshot
...
bigtex/foo at a                                                                           
0      -    18K  -
bigtex/foo at b                                                                           
0      -    18K  -
bigtex/foo at c                                                                           
0      -    18K  -
bigtex/foo at d                                                                           
0      -    18K  -
bigtex/foo/bar at a                                                                       
0      -    18K  -
bigtex/foo/bar at b                                                                       
0      -    18K  -
bigtex/foo/bar at c                                                                       
0      -    18K  -
bigtex/foo/bar at d                                                                       
0      -    18K  -
bigtmptex/foo at a                                                                        
0      -    18K  -
bigtmptex/foo at b                                                                        
0      -    18K  -
bigtmptex/foo at c                                                                        
0      -    18K  -
bigtmptex/foo at d                                                                        
0      -    18K  -
bigtmptex/foo/bar at a                                                                    
0      -    18K  -
bigtmptex/foo/bar at b                                                                    
0      -    18K  -
bigtmptex/foo/bar at c                                                                    
0      -    18K  -
bigtmptex/foo/bar at d                                                                    
0      -    18K  -

# pretend that the incremental send/recv above was interrupted after
bigtex/foo at d was received but before bigtex/foo/bar at d
/home/james# zfs destroy bigtmptex/foo/bar at d

# a clever script might realize that we need to start at @c because @d
has not been received by some child filesystems.  But zfs recv doesn't
work right.
/home/james# /root/zfs send -RvI @c bigtex/foo at d | /root/zfs recv -dvF
bigtmptex
sending from @c to bigtex/foo at d
receiving incremental stream of bigtex/foo at d into bigtmptex/foo at d
snap bigtmptex/foo at d already exists; ignoring
sending from @c to bigtex/foo/bar at d
warning: cannot send 'bigtex/foo/bar at d': Broken pipe

/home/james# zfs list -t snapshot
...
bigtmptex/foo at a                                                                        
0      -    18K  -
bigtmptex/foo at b                                                                        
0      -    18K  -
bigtmptex/foo at c                                                                        
0      -    18K  -
bigtmptex/foo at d                                                                        
0      -    18K  -
bigtmptex/foo/bar at a                                                                    
0      -    18K  -
bigtmptex/foo/bar at b                                                                    
0      -    18K  -
bigtmptex/foo/bar at c                                                                    
0      -    18K  -



More information about the freebsd-fs mailing list