In the Linux kernel, the following vulnerability has been resolved:
btrfs: scrub: handle RST lookup error correctly
[BUG] When running btrfs/060 with forced RST feature, it would crash the following ASSERT() inside scrubreadendio():
ASSERT(sector_nr < stripe->nr_sectors);
Before that, we would have tree dump from btrfsgetraidextentoffset(), as we failed to find the RST entry for the range.
[CAUSE] Inside scrubsubmitextentsectorread() every time we allocated a new bbio we immediately called btrfsmapblock() to make sure there was some RST range covering the scrub target.
But if btrfsmapblock() fails, we immediately call endio for the bbio, while the bbio is newly allocated, it's completely empty.
Then inside scrubreadendio(), we go through the bvecs to find the sector number (as bi_sector is no longer reliable if the bio is submitted to lower layers).
And since the bio is empty, such bvecs iteration would not find any sector matching the sector, and return sectornr == stripe->nrsectors, triggering the ASSERT().
[FIX] Instead of calling btrfsmapblock() after allocating a new bbio, call btrfsmapblock() first.
Since our only objective of calling btrfsmapblock() is only to update stripelen, there is really no need to do that after btrfsalloc_bio().
This new timing would avoid the problem of handling empty bbio completely, and in fact fixes a possible race window for the old code, where if the submission thread is the only owner of the pendingio, the scrub would never finish (since we didn't decrease the pendingio counter).
Although the root cause of RST lookup failure still needs to be addressed.