openzfs / zfs

OpenZFS on Linux and FreeBSD
https://openzfs.github.io/openzfs-docs
Other
10.69k stars 1.76k forks source link

[FreeBSD only] ERESTART and TRAVERSE_VISIT_NO_CHILDREN have the same value #16748

Open avg-I opened 2 weeks ago

avg-I commented 2 weeks ago

System information

Type Version/Name
Distribution Name FreeBSD
Distribution Version 14.2 / any recent
Kernel Version 14.2
Architecture any
OpenZFS Version zfs-2.2.6-FreeBSD_g33174af15

Describe the problem you're observing

On FreeBSD ERESTART and TRAVERSE_VISIT_NO_CHILDREN have the same value of -1. Both can be returned from traversal callbacks. TRAVERSE_VISIT_NO_CHILDREN has special handling within the traversal code. So, it's possible that ERESTART returned from a callback like dsl_scan_free_block_cb would be handled as TRAVERSE_VISIT_NO_CHILDREN.

Describe how to reproduce the problem

I do not have a clear demonstrator but I suspect that the problem could be triggered when destroying a large dataset such that dsl_scan_free_block_cb would have to return ERESTART .

As a result traverse_dnode could skip remaining blocks under a dnode where ERESTART is triggered. Those blocks would be leaked.

Possible solution

Change value of TRAVERSE_VISIT_NO_CHILDREN to something even "more magic" to avoid conflict with low numbered negative return values used in FreeBSD (defined in errno.h). For example, a value of -100 should work fine.