make grade 80/80 with comment
This commit is contained in:
parent
c67450b32b
commit
d4798926a3
29
kernel/bio.c
29
kernel/bio.c
@ -98,20 +98,20 @@ bget(uint dev, uint blockno)
|
|||||||
}
|
}
|
||||||
h = h->next;
|
h = h->next;
|
||||||
}
|
}
|
||||||
|
release(&hash_locks[bucket]);
|
||||||
|
// release the unfound bucket, or there'll be deadlock
|
||||||
acquire(&bcache.lock);
|
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){
|
for(int i = 0; i < NBUF; ++ i){
|
||||||
b = &bcache.buf[i];
|
b = &bcache.buf[i];
|
||||||
|
int victim_bucket = b->blockno % NLOCK_BUCKETS;
|
||||||
|
acquire(&hash_locks[victim_bucket]);
|
||||||
if(b->refcnt == 0) {
|
if(b->refcnt == 0) {
|
||||||
int victim_bucket = b->blockno % NLOCK_BUCKETS;
|
|
||||||
b->dev = dev;
|
b->dev = dev;
|
||||||
b->blockno = blockno;
|
b->blockno = blockno;
|
||||||
b->valid = 0;
|
b->valid = 0;
|
||||||
b->refcnt = 1;
|
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
|
// try to release hash entry from the old bucket
|
||||||
h = hash_entry[victim_bucket];
|
h = hash_entry[victim_bucket];
|
||||||
ph = 0;
|
ph = 0;
|
||||||
@ -124,19 +124,19 @@ bget(uint dev, uint blockno)
|
|||||||
ph = h;
|
ph = h;
|
||||||
h = h->next;
|
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];
|
h = &hash_tbls[i];
|
||||||
|
acquire(&hash_locks[bucket]);
|
||||||
h->next = hash_entry[bucket];
|
h->next = hash_entry[bucket];
|
||||||
hash_entry[bucket] = h;
|
hash_entry[bucket] = h;
|
||||||
|
|
||||||
if (victim_bucket != bucket) {
|
|
||||||
// release(&hash_locks[victim_bucket]);
|
|
||||||
}
|
|
||||||
release(&bcache.lock);
|
|
||||||
release(&hash_locks[bucket]);
|
release(&hash_locks[bucket]);
|
||||||
acquiresleep(&b->lock);
|
acquiresleep(&b->lock);
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
release(&hash_locks[victim_bucket]);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
// Is the block already cached?
|
// Is the block already cached?
|
||||||
@ -201,6 +201,11 @@ brelse(struct buf *b)
|
|||||||
|
|
||||||
releasesleep(&b->lock);
|
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;
|
int bucket = b->blockno % NLOCK_BUCKETS;
|
||||||
acquire(&hash_locks[bucket]);
|
acquire(&hash_locks[bucket]);
|
||||||
b->refcnt--;
|
b->refcnt--;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user