diff --git a/kernel/core/sleeplock.c b/kernel/core/sleeplock.c index 987dd34..f1eb5ed 100644 --- a/kernel/core/sleeplock.c +++ b/kernel/core/sleeplock.c @@ -45,11 +45,30 @@ releasesleep(struct sleeplock *lk) release(&lk->lk); } +// Does *this process* hold lk? +// +// The pid comparison is not decoration. Without it this answers "is anyone +// holding this", and every caller is an assertion of the form +// +// if (!holdingsleep(&b->lock)) panic("brelse"); +// +// whose entire purpose is to catch a process releasing a lock it never took. +// Answering the weaker question disarms all seven of them: iunlock() on an +// inode locked by another process, and brelse() on somebody else's buffer, +// both sailed through and unlocked it underneath the real holder. Two +// processes then believe they hold the same inode, and the corruption surfaces +// somewhere else entirely -- which is exactly the shape of bug these panics +// exist to prevent. +// +// myproc() is null on the boot path before the scheduler runs, and +// acquiresleep() stores 0 for that case, so compare the same way rather than +// dereferencing null here. int holdingsleep(struct sleeplock *lk) { + struct proc *p = myproc(); acquire(&lk->lk); - int r = lk->locked; + int r = lk->locked && lk->pid == (p ? p->pid : 0); release(&lk->lk); return r; }