summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs.c31
1 files changed, 18 insertions, 13 deletions
diff --git a/fs.c b/fs.c
index cc1e60b..ebe377a 100644
--- a/fs.c
+++ b/fs.c
@@ -330,22 +330,27 @@ iunlock(struct inode *ip)
void
iput(struct inode *ip)
{
- acquiresleep(&ip->lock);
- if(ip->valid && ip->nlink == 0){
- acquire(&icache.lock);
- int r = ip->ref;
+ acquire(&icache.lock);
+
+ if(ip->ref == 1 && ip->valid && ip->nlink == 0){
+ // inode has no links and no other references: truncate and free.
+
+ // ip->ref == 1 means no other process can have ip locked,
+ // so this acquiresleep() won't block (or deadlock).
+ acquiresleep(&ip->lock);
+
release(&icache.lock);
- if(r == 1){
- // inode has no links and no other references: truncate and free.
- itrunc(ip);
- ip->type = 0;
- iupdate(ip);
- ip->valid = 0;
- }
+
+ itrunc(ip);
+ ip->type = 0;
+ iupdate(ip);
+ ip->valid = 0;
+
+ releasesleep(&ip->lock);
+
+ acquire(&icache.lock);
}
- releasesleep(&ip->lock);
- acquire(&icache.lock);
ip->ref--;
release(&icache.lock);
}