Buffer Management in Multiprocessor Kernel
References: Bach's Chapter12: Figure 12.14
ASSUMPTIONS:
1. Buffers are maintained in a freelist and hash queues (HQs).
Initial: all buffers are in freelist, every HQ is empty.
The actual hashing scheme is NOT important, just for searching
convenience. For example, H(bp=(dev,blk)) = dev is a hashing.
But it does affect concurrency.
2. Each buffer has a lock semaphore=1.
Each HQ has a lock semaphore=1.
freelist has a lock semaphore=1;
A semaphore wantfree=0; for procs to wait for free buffers
3. CP and CV are primitive operations on semaphore:
CP(semaphore): if semaphore value > 0: lock succeeds
else return -1 immediately.
CV(semaphore): if (semaphore.queue NOT empty)
V(semaphore);
============= UNIX MP Algorithm =================
mgetblk(dev,blk)
{
retry loop:
1. P(HQ); // lock HQ of bp=(dev,bp)
2. if (bp in HQ){
if (!CP(bp)){ // if fail to lock bp
V(HQ); // release HQ lock
P(bp); // wait in bpQ
--------------------------
if (bp changed){
V(bp); // unlock bp
retry;
}
if (!CP(HQ)){
V(bp);
retry;
}
}
------------------------------
// locked bp did not change
P(freelist); // lock freelist; (BACH: while(!CP(freelist);
take bp out of freelist;
V(freelist);
V(HQ);
return bp;
}
// Bach's book does not show WHAT IF the needed buffer is NOT in HQ
// The following is only an outline of what the algorithm SHOULD DO:
3. // bp NOT in HQ; HQ still locked at (1)
3-1: Try to get a free buffer in order to create the needed buffer
3-2. If (freelist is empty), MUST unlock HQ and WAIT for free buffer
When resume to run, must retry from beginning;
3-3. if (freelist not empty)
try to get a free buffer, fbuf, off the freelist AND lock the buffer:
3-4. if (locked fbuf is for DELWRI); must write it out ASYNC and retry 3-1.
3-5. Try to reassign the locked fbuf to (dev,blk) and enter it into HQ;
(what if fbuf was in a different HQ?)
return fbuf;
}
// UNIX: releasing a bp only puts it back to freelist
// Does NOT need to access any HQ
// MAY unblock a proc who needs THIS bp and one who needs a free buffer.
// Assume: wantfree and bp are semaphores.
mbrelse(bp)
{
P(freelist);
put bp into freelist;
V(freelist)
CV(wantfree);
V(bp);
}
========================================================================
COMMENTS and NEW MP ALGORITHM:
1. Every buffer is for exclusive use (by P(bp)).
CAN YOU ALLOW CONCURRENT READERS on the same buffer?
2. In mgetblk(), a locked bp=(dev,blk) at (2) may change because:
At (2) a proc P1 finds bp in HQ and CP(bp) fails, meaning bp is
already locked (either by a proc which is using this bp now or by a proc
which has locked bp via the freelist) ==> P1 releases HQ and P(bp) to
wait in bp's queue.
If bp was locked by a proc via the freelist, bp will be reassigned to
a different (DEV,BLK).
When P1 gets up from bpQ, bp has been changed ==> P1 has to give up this
bp (by V(bp)) and retry again.
CAN YOU IMPROVE ON THIS? i.e. to ensure a "locked bp" does NOT change?
3. The max. degree of concurrency is the number of HQs but the min. degree
of concurrency is 1 because of the freelist bootleneck.
CAN YOU IMPROVE ON THIS?
=========================================================================