Fix getblk() with GB_NOCREAT returning false-negatives.

It is possible for a buf to be reassigned between the dirty and clean
lists while gbincore_unlocked() looks in each list.  Avoid creating
a buffer in that case and fallback to a locked lookup.

This fixes a regression from r363482.

More discussion on potential improvements to the clean and dirty lists
handling is in the review.

Reviewed by:	cem, kib, markj, vangyzen, rlibby
Reported by:	Suraj.Raju at dell.com
Submitted by:	Suraj.Raju at dell.com, cem, [based on both]
MFC after:	2 weeks
Sponsored by:	Dell EMC
Differential Revision:	https://reviews.freebsd.org/D28375
This commit is contained in:
Bryan Drewery 2021-01-27 09:59:50 -08:00
parent ae257282ae
commit c926114f2f

View File

@ -3888,8 +3888,15 @@ getblkx(struct vnode *vp, daddr_t blkno, daddr_t dblkno, int size, int slpflag,
/* Attempt lockless lookup first. */
bp = gbincore_unlocked(bo, blkno);
if (bp == NULL)
if (bp == NULL) {
/*
* With GB_NOCREAT we must be sure about not finding the buffer
* as it may have been reassigned during unlocked lookup.
*/
if ((flags & GB_NOCREAT) != 0)
goto loop;
goto newbuf_unlocked;
}
error = BUF_TIMELOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL, "getblku", 0,
0);