From d4798926a3ca8e0ff3fe89183b3c93f590dc27bc Mon Sep 17 00:00:00 2001 From: ridethepig Date: Sat, 4 Feb 2023 14:17:55 +0000 Subject: [PATCH] make grade 80/80 with comment --- kernel/bio.c | 29 +++++++++++++++++------------ time.txt | 1 + 2 files changed, 18 insertions(+), 12 deletions(-) create mode 100644 time.txt diff --git a/kernel/bio.c b/kernel/bio.c index 692d5f3..de5db97 100644 --- a/kernel/bio.c +++ b/kernel/bio.c @@ -98,20 +98,20 @@ bget(uint dev, uint blockno) } h = h->next; } + release(&hash_locks[bucket]); + // release the unfound bucket, or there'll be deadlock acquire(&bcache.lock); + // after bcache.lock is aquired, only b->refcnt maybe out of our control + // so, have to aquire hash_locks[victim_bucket] before test refcnt for(int i = 0; i < NBUF; ++ i){ b = &bcache.buf[i]; + int victim_bucket = b->blockno % NLOCK_BUCKETS; + acquire(&hash_locks[victim_bucket]); if(b->refcnt == 0) { - int victim_bucket = b->blockno % NLOCK_BUCKETS; b->dev = dev; b->blockno = blockno; b->valid = 0; b->refcnt = 1; - // first find the victim's hash - if (victim_bucket != bucket) - { - // acquire(&hash_locks[victim_bucket]); - } // try to release hash entry from the old bucket h = hash_entry[victim_bucket]; ph = 0; @@ -124,19 +124,19 @@ bget(uint dev, uint blockno) ph = h; h = h->next; } - // add it to new hash entry + release(&hash_locks[victim_bucket]); + release(&bcache.lock); + // this should avoid deadlock and meanwhile guard the hashtable + // because after b is set, the only thing we need is hashtable rather than buf attributes h = &hash_tbls[i]; + acquire(&hash_locks[bucket]); h->next = hash_entry[bucket]; hash_entry[bucket] = h; - - if (victim_bucket != bucket) { - // release(&hash_locks[victim_bucket]); - } - release(&bcache.lock); release(&hash_locks[bucket]); acquiresleep(&b->lock); return b; } + release(&hash_locks[victim_bucket]); } #else // Is the block already cached? @@ -201,6 +201,11 @@ brelse(struct buf *b) releasesleep(&b->lock); +// if you use bcache lock, test0 fails without doubt +// the reason why this works is that, whenever b->refcnt is written or read +// its 'hash_locks[H(b->blockno)]' will always been locked +// the reason why b->blockno is valid is that, only when refcnt==0 could this field be written +// but here it must be non-zero before lock aquired int bucket = b->blockno % NLOCK_BUCKETS; acquire(&hash_locks[bucket]); b->refcnt--; diff --git a/time.txt b/time.txt new file mode 100644 index 0000000..f11c82a --- /dev/null +++ b/time.txt @@ -0,0 +1 @@ +9 \ No newline at end of file