getblk: Avoid sleeping on wrong buf in lockless path

If the buffer identity changed during lookup, sleeping could introduce a
lock order reversal.  Since we do not know if the identity changed until we
get the lock, we must try-lock (LK_NOWAIT) only.  EINTR and ERESTART error
handling becomes irrelevant, as we no longer sleep.

Reported by:	kib
Reviewed by:	kib
X-MFC-With:	r363482
Sponsored by:	Dell EMC Isilon
Differential Revision:	https://reviews.freebsd.org/D25898
This commit is contained in:
Conrad Meyer 2020-07-31 00:07:01 +00:00
parent 9119bafbaf
commit 59d13f6154
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=363721

View File

@ -3844,7 +3844,7 @@ getblkx(struct vnode *vp, daddr_t blkno, daddr_t dblkno, int size, int slpflag,
struct buf *bp;
struct bufobj *bo;
daddr_t d_blkno;
int bsize, error, maxsize, vmio, lockflags;
int bsize, error, maxsize, vmio;
off_t offset;
CTR3(KTR_BUF, "getblk(%p, %ld, %d)", vp, (long)blkno, size);
@ -3865,14 +3865,9 @@ getblkx(struct vnode *vp, daddr_t blkno, daddr_t dblkno, int size, int slpflag,
if (bp == NULL)
goto newbuf_unlocked;
lockflags = LK_EXCLUSIVE | LK_SLEEPFAIL |
((flags & GB_LOCK_NOWAIT) ? LK_NOWAIT : 0);
error = BUF_TIMELOCK(bp, lockflags, NULL, "getblku", slpflag,
slptimeo);
if (error == EINTR || error == ERESTART)
return (error);
else if (error != 0)
error = BUF_TIMELOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL, "getblku", 0,
0);
if (error != 0)
goto loop;
/* Verify buf identify has not changed since lookup. */
@ -3886,6 +3881,8 @@ getblkx(struct vnode *vp, daddr_t blkno, daddr_t dblkno, int size, int slpflag,
BO_RLOCK(bo);
bp = gbincore(bo, blkno);
if (bp != NULL) {
int lockflags;
/*
* Buffer is in-core. If the buffer is not busy nor managed,
* it must be on a queue.