My ThinkPad P50 has two ZFS storage pools: one for the root file system and another that serves as an archive. I’ve been taking daily recursive snapshots of the root file system for a while now and it was time to start placing the snapshots of my /home on the archive pool for safekeeping. I ran into a problem and this is how I solved it.

When I’d execute the following to create the destination file system for the initial snapshot, it seemed to work as expected:

zfs send rpool/home/david@1557936000 | zfs recv archive/backup/david

However, when executing the following command to copy the subsequent snapshot:

zfs send -i @1557936000 rpool/home/david@1558022401 | zfs recv archive/backup/david

I’d get this error:

cannot receive incremental stream: destination archive/backup/david has been modified

Of course, I hadn’t touched that file system at all and have no idea what could have possibly modified it. From what I’ve seen online, this issue doesn’t only occur on Linux but also FreeBSD. One recommendation was to disable atime on the file system but that didn’t solve the problem.

I solved the problem by using the -F option with zfs recv:

zfs send -i @1557936000 rpool/home/david@1558022401 | zfs recv -F archive/backup/david

That completed successfully.

According to the zfs manpage, zfs recv -F “forces a rollback of the file system to the most recent snapshot before performing the receive operation.”

There was some confusion in the forums whether the -F would destroy snapshots on the receiving side, but that depends on whether you’ve destroyed snapshots on the sending side along with using -R with zfs send when sending incremental snaphots. If that is the case, then the -R flag (for replicate) will tell the receiving side that is using zfs recv -F to destroy the snapshots that have been destroyed on the sending side.

For additional verification that my incremental snapshots are being received properly, I destroyed archive/backup/david, recreated it with the initial snapshot (the first command above), and then used the -I option with zfs send to send all incremental snapshots since my first snapshot to the most recent. That also completed successfully.

The next step was to add the new snapshots created by cron to my archive. For that, I wrote the following script:

#!/usr/bin/env zsh
PREVSNAP=~/.zfsprevsnapshot
HOMEFS=rpool/home/david
ARCHFS=archive/backup/david

DATE=$(date +%s)
PREVIOUS=$(<$PREVSNAP)

sudo zfs snapshot ${HOMEFS}@${DATE}
sudo zfs send -I ${HOMEFS}@${PREVIOUS} ${HOMEFS}@${DATE} | sudo zfs recv -F $ARCHFS

printf "$DATE" > $PREVSNAP

And added my most recent snapshot’s name to ~/.zfsprevsnapshot:

printf "1558281601" > ~/.zfsprevsnapshot

When I tackle destroying old snapshots via cron, I’ll be sure to post how I did it.