Linux – Unable to zfs send | zfs receive datasets in same zpool

linuxsnapshotzfs

I have two environments Staging (staging) and Development (choang). I am unable to replicate (including snapshots) from dataset zfs/staging.assets to another dataset zfs/choang.assets within the same zpool zfs.

NOTE: I am assuming I need to unmount both origin and destination datasets.

zfs unmount zfs/staging.assets
zfs unmount zfs/choang.assets

zfs send -R zfs/staging.assets | zfs receive -F zfs/choang.assets

When executed, the above commands generate the following error:

Error: Unsupported flag with filesystem or bookmark.
cannot receive: failed to read from stream

When I remove the -R option and execute the commands, it succeeds:

zfs send zfs/staging.assets | zfs receive -F  zfs/choang.assets

However, no snapshots are received and a single snapshot zfs/choang.assets@--head-- is created.

Finally, I attempted to send a snapshot– thinking maybe I might send a snapshot at a time:

zfs send zfs/staging.assets@sha512_hash | zfs receive -Fduv zfs/choang.assets

This didn't work either and generated the following error:

internal error: Invalid argument
cannot receive: failed to read from stream

How can I replicate all snapshots?

Best Answer

Several things are important here. Your errors stem from combinations of them:

  • Normally you send a specific snapshot or several snapshots instead of a whole file system. This means you do not need to unmount the datasets and disrupt your users, and you can incrementally send/recv later on.
  • If you do not specify a snapshot on the source, you will get the automatically generated snapshot @--head--, which is the state of your source at the moment of sending (if you would have sent an existing snapshot, that snapshot would take the place of @--head-- on the destination side).
  • The send -R | recv -F combination means full replication (recursive and including properties on source, destroy old stuff on destination), so you need to decide how to expand the file system hierarchy: you can use either -e, -d, or no flag on receiving (no flag means merging the contents under the new dataset without preserving the name of the parent dataset on the source side):

    The -d and -e options cause the file system name of the target snapshot
    to be determined by appending a portion of the sent snapshot's name to
    the specified target filesystem.  If the -d option is specified, all
    but the first element of the sent snapshot's file system path (usually
    the pool name) is used and any required intermediate file systems
    within the specified one are created. If the -e option is specified,
    then only the last element of the sent snapshot's file system name
    (i.e. the name of the source file system itself) is used as the target
    file system name.
    
  • Your last idea (single send, full receive) should work (I tested it in a simple environment and it did work), but it would not be what you wanted anyway.

So, to sum it up and apply to your specific situation:

  1. First recursively create a current snapshot or choose an older one that contains all the older stuff you want to replicate):

    zfs snapshot -r zfs/staging.assets@now
    
  2. Destroy any old snapshots on the destination side which are on the source side (show all snapshots with zfs list -Hr -o name -t snap zfs/choang.assets or take the hints from the error message). Alternatively destroy the destination dataset and recreate it if it does not contain anything of importance.

  3. Send recursively and fully receive, destroying all old datasets on the second dataset, merging the sub-datasets into the destination so that they mirror the source:

    zfs send -R zfs/staging.assets@now | zfs recv -Fu zfs/choang.assets
    
Related Question