lbmRead() waits for read I/O completion by testing l_flag with an
unlocked wait_event() condition. The completion path updates l_flag
under the JFS lcache lock and sets lbmDONE before it clears lbmREAD,
leaving a transient lbmREAD | lbmDONE state.
The existing condition only checks that l_flag is no longer exactly
lbmREAD. It can therefore treat that transient state as completion and
return while lbmIODone() is still handling the same buffer. Callers may
then reuse the lbuf before the read completion has cleared lbmREAD.
Wait for the real read-completion condition, lbmREAD being clear, and
use the existing lcache wait helper so the condition is evaluated under
the same lock as the completion update.
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
---
fs/jfs/jfs_logmgr.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c
index ada00d5bc214..a09b979b4224 100644
--- a/fs/jfs/jfs_logmgr.c
+++ b/fs/jfs/jfs_logmgr.c
@@ -1962,6 +1962,7 @@ static int lbmRead(struct jfs_log * log, int pn, struct lbuf ** bpp)
{
struct bio *bio;
struct lbuf *bp;
+ unsigned long flags;
/*
* allocate a log buffer
@@ -1986,7 +1987,9 @@ static int lbmRead(struct jfs_log * log, int pn, struct lbuf ** bpp)
submit_bio(bio);
}
- wait_event(bp->l_ioevent, (bp->l_flag != lbmREAD));
+ LCACHE_LOCK(flags);
+ LCACHE_SLEEP_COND(bp->l_ioevent, !(bp->l_flag & lbmREAD), flags);
+ LCACHE_UNLOCK(flags);
return 0;
}