Skip to content

Conversation

@nedbass
Copy link
Contributor

@nedbass nedbass commented Sep 29, 2017

Description

When receiving a FREEOBJECTS record, receive_freeobjects()
incorrectly skips a freed object in some cases. This leaves an object
allocated on disk on the receiving side which is unallocated on the
sending side, which may cause receiving subsequent incremental
streams to fail.

The bug was caused by an incorrect increment of the object index
variable when current object being freed doesn't exist. The
increment is incorrect because incrementing the object index is
handled by a call to dmu_object_next() in the increment portion of
the for loop statement.

Motivation and Context

Receive backup streams correctly.

How Has This Been Tested?

Added test case rsend/send_freeobjects.ksh.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Performance enhancement (non-breaking change which improves efficiency)
  • Code cleanup (non-breaking change which makes code smaller or more readable)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation (a change to man pages or other documentation)

Checklist:

  • My code follows the ZFS on Linux code style requirements.
  • I have updated the documentation accordingly.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes.
  • All new and existing tests passed.
  • All commit messages are properly formatted and contain Signed-off-by.
  • Change has been approved by a ZFS on Linux member.

@gmelikov
Copy link
Member

I think it would be better to add this test.

@codecov
Copy link

codecov bot commented Sep 29, 2017

Codecov Report

❗ No coverage uploaded for pull request base (master@01ff0d7). Click here to learn what that means.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff            @@
##             master    #6695   +/-   ##
=========================================
  Coverage          ?   74.02%           
=========================================
  Files             ?      295           
  Lines             ?    93878           
  Branches          ?        0           
=========================================
  Hits              ?    69495           
  Misses            ?    24383           
  Partials          ?        0
Flag Coverage Δ
#kernel 74.3% <100%> (?)
#user 63.31% <0%> (?)
Impacted Files Coverage Δ
module/zfs/dmu_send.c 75.17% <100%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 01ff0d7...d79b4b3. Read the comment docs.

@nedbass nedbass force-pushed the b_6694 branch 3 times, most recently from 904de02 to 2a0b774 Compare September 29, 2017 17:11
@nedbass
Copy link
Contributor Author

nedbass commented Sep 29, 2017

Added test case.

Copy link
Member

@gmelikov gmelikov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

Copy link
Contributor

@behlendorf behlendorf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense and looks good. Just a few nits.


log_must zfs create $POOL/$sendds

while :; do
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does the : here do? Why not while true; do? Or better yet put large limit on this so can can't spin forever.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

touch $f1 $f2 $f3
o1=`ls -li $f1 | awk '{print $1}'`
o2=`ls -li $f2 | awk '{print $1}'`
o3=`ls -li $f3 | awk '{print $1}'`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you switch the legacy backticks to the preferred $() syntax.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

o3=`ls -li $f3 | awk '{print $1}'`

if [[ $o2 -ne $(( $o1 + 1 )) ]] || [[ $o3 -ne $(( $o2 + 1 )) ]]; then
rm $f1 $f2 $f3
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add -f to handle the unlike case where one of these files failed to be created and is missing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

log_must zfs create $POOL/$sendds

tries=100
for ((i=0; i<$tries; i++)); do
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, it looks like this did happen in the last test run.

http://build.zfsonlinux.org/builders/CentOS%206%20x86_64%20%28TEST%29/builds/489/steps/shell_8/logs/stdio

Test: /usr/share/zfs/zfs-tests/tests/functional/rsend/send_freeobjects (run as root) [10:00] [KILLED]
19:19:53.38 ASSERTION: Verify FREEOBJECTS record frees sequential objects
19:19:53.42 SUCCESS: zfs create testpool/sendfo

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sigh. Of course it almost always exits the loop on the first or second iteration in manual testing. I may have to push a more verbose version to debug the builders.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Turns out SELinux xattrs were consuming the intervening object numbers. Updated test case to force xattr=sa to work around this.

When receiving a FREEOBJECTS record, receive_freeobjects()
incorrectly skips a freed object in some cases. Specifically, this
happens when the first object in the range to be freed doesn't exist,
but the second object does. This leaves an object allocated on disk
on the receiving side which is unallocated on the sending side, which
may cause receiving subsequent incremental streams to fail.

The bug was caused by an incorrect increment of the object index
variable when current object being freed doesn't exist.  The
increment is incorrect because incrementing the object index is
handled by a call to dmu_object_next() in the increment portion of
the for loop statement.

Add test case that exposes this bug.

Fixes openzfs#6694
Signed-off-by: Ned Bass <bass6@llnl.gov>
@behlendorf behlendorf merged commit 39f5662 into openzfs:master Oct 2, 2017
aerusso pushed a commit to aerusso/zfs that referenced this pull request Oct 11, 2017
When receiving a FREEOBJECTS record, receive_freeobjects()
incorrectly skips a freed object in some cases. Specifically, this
happens when the first object in the range to be freed doesn't exist,
but the second object does. This leaves an object allocated on disk
on the receiving side which is unallocated on the sending side, which
may cause receiving subsequent incremental streams to fail.

The bug was caused by an incorrect increment of the object index
variable when current object being freed doesn't exist.  The
increment is incorrect because incrementing the object index is
handled by a call to dmu_object_next() in the increment portion of
the for loop statement.

Add test case that exposes this bug.

Reviewed-by: George Melikov <mail@gmelikov.ru>
Reviewed-by: Giuseppe Di Natale <dinatale2@llnl.gov>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Ned Bass <bass6@llnl.gov>
Closes openzfs#6694
Closes openzfs#6695
tonyhutter pushed a commit that referenced this pull request Oct 16, 2017
When receiving a FREEOBJECTS record, receive_freeobjects()
incorrectly skips a freed object in some cases. Specifically, this
happens when the first object in the range to be freed doesn't exist,
but the second object does. This leaves an object allocated on disk
on the receiving side which is unallocated on the sending side, which
may cause receiving subsequent incremental streams to fail.

The bug was caused by an incorrect increment of the object index
variable when current object being freed doesn't exist.  The
increment is incorrect because incrementing the object index is
handled by a call to dmu_object_next() in the increment portion of
the for loop statement.

Add test case that exposes this bug.

Reviewed-by: George Melikov <mail@gmelikov.ru>
Reviewed-by: Giuseppe Di Natale <dinatale2@llnl.gov>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Ned Bass <bass6@llnl.gov>
Closes #6694
Closes #6695
FransUrbo pushed a commit to FransUrbo/zfs that referenced this pull request Apr 28, 2019
When receiving a FREEOBJECTS record, receive_freeobjects()
incorrectly skips a freed object in some cases. Specifically, this
happens when the first object in the range to be freed doesn't exist,
but the second object does. This leaves an object allocated on disk
on the receiving side which is unallocated on the sending side, which
may cause receiving subsequent incremental streams to fail.

The bug was caused by an incorrect increment of the object index
variable when current object being freed doesn't exist.  The
increment is incorrect because incrementing the object index is
handled by a call to dmu_object_next() in the increment portion of
the for loop statement.

Add test case that exposes this bug.

Reviewed-by: George Melikov <mail@gmelikov.ru>
Reviewed-by: Giuseppe Di Natale <dinatale2@llnl.gov>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Ned Bass <bass6@llnl.gov>
Closes openzfs#6694 
Closes openzfs#6695
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants