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:
parent
c9e86bdc3f
commit
b07ca90399
@ -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 @@ loop:
|
||||
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.
|
||||
|
Loading…
x
Reference in New Issue
Block a user