Chapter 4 bcacheÖÐÔ໺³åÇøµÄͬ²½»úÖÆ
Unix£¯Linuxϵͳ¶ÔÔ໺³åÇøµÄͬ²½ÎÊÌâ²ÉÓÃÁËÑÓ³ÙдµÄ°ì·¨¡£µ±½ø³Ì·¢³ö¿éÉ豸I/OдÇëÇóʱ£¬Êý¾ÝÄÚÈÝʵ¼ÊÉÏÊÇÏȱ»Ð´µ½Ä³¸ö¶ÔÓ¦µÄ»º³åÇøÖУ¨Òò¶øÒ²ÊǶÔÓ¦µÄ»º³åÇø±äÔࣩ£¬¶ø²»ÊÇÁ¢¼´Ð´µ½ÎïÀí¿éÉ豸ÖС£ÒòÎªËæºó¶ÔÕâÒ»ÏàͬµÄ¿é»¹¿ÉÄܻᷢÉúЩ²Ù×÷£¬ËùÒÔµ±Ç°ÄÚÈÝ¿ÉÄܻᱻ¸²¸Ç¡£´Ó¶øÒ²±ÜÃâÁ˶àÓàµÄ´ÅÅÌÎïÀíд²Ù×÷¡£
ÓÉÓÚÔ໺³åÇø¿ÉÄÜÖ±µ½×îºóÒ»¿Ì£¨¼´Ö±µ½ÏµÍ³¹Ø±Õʱ£©¶¼Ò»Ö±¶ºÁôÔÚÖ÷´æÖС£Òò´ËÕâÖÖÑÓ³Ùд·½·¨ÓÐÁ½¸öȱµã£º
1. Èç¹û·¢ÉúÓ²¼þ´íÎó»òµçÔ´µôµçµÄÇé¿ö£¬ÄǾÍÎÞ·¨Ôڵõ½RAMÖеÄÄÚÈÝ¡£Òò´Ë£¬´ÓϵͳÆô¶¯ÒÔÀ´ËùÓжÔÎļþ½øÐеĺܶàÐ޸ͼ½«¶ªÊ§¡£
2. bcacheÖеÄÔ໺³åÇø»áÔ½À´Ô½¶à£¬Òò´Ë»áʹbcacheÖеĿÕÏлº³åÇø±äµÃ½ôȱ¡£
ÓÉÓÚÒÔÉÏȱµã£¬Òò´Ë±ØÐëÔÚijЩÌõ¼þÏ£¬ÓÐÄں˰ÑbcacheÖеÄÔ໺³åÇøÕæÕýµØ»ØÐ´µ½´ÅÅÌ¡£Îª´ËbcacheÌṩÁËÈýÖÖ·½·¨£º
(1) µ±Ô໺³åÇø±äµÃÌ«Âú£¬µ«ÄÚºËÓÉ»¹ÐèÒª¸ü¶àµÄ»º³åÇøÊ±£¬¾Í»á¼¤»îbdflushÄÚºËỊ̈߳¬½«Ò»²¿·ÖÔ໺³åÇø»ØÐ´µ½´ÅÅÌÖС£
(2)Èç¹û×Ô´ÓÔ໺³åÇø±äÔàÒÔÀ´ÒѾ¹ýȥ̫³¤Ê±¼ä£¬kupdateÄÚºËÏ̻߳áÖÜÆÚÐÔµØË¢Ð¡¸Ä곤¡¹£¨old£©µÄÔ໺³åÇø¡£
(3) ½ø³Ì¿ÉÒÔÏÔʾµØÍ¨¹ýϵͳµ÷ÓÃsync()¡¢fsync()»òfdatasync()À´Ë¢ÐÂÌØ¶¨¿éÉ豸µÄËùÓлº³åÇø»òÌØ¶¨ÎļþµÄËùÓлº³åÇø¡£
4£®1 bcacheÖеÄÔ໺³åÇøÍ¬²½²Ù×÷
º¯Êýsync_buffers()ÓÃÀ´ÊµÏÖ½«ÊôÓÚij¸öÌØ¶¨¿éÉ豸µÄËùÓÐÔ໺³åÇøÕæÕýµØ»ØÐ´µ½¿éÉ豸ÖС£ÆäÔÐÍÈçÏ£º
static int sync_buffers(kdev_t dev, int wait)
²ÎÊýdevÖ¸¶¨Âß¼¿éÉ豸µÄÉ豸±êʶ·û£¬²ÎÊýwaitÖ¸¶¨ÊÇ·ñµÈ´ýËùÓÐÔ໺³åÇøµÄ»ØÐ´²Ù×÷Íê³Éºóº¯Êý²Å·µ»Ø¡£
¶ÔÓÚwait=0µÄÇé¿ö£¬sync_buffers()º¯Êý½ö½öÖ»ÊÇɨÃéBUF_DIRTYÁ´±í£¬²¢¶ÔÆäÖеÄÔ໺³åÇø°²ÅÅ»ØÐ´²Ù×÷¼´¿É£¨Í¨¹ýµ÷ÓÿéÉ豸Çý¶¯³ÌÐòµÄll_rw_block()º¯Êý£©¡£
¶ÔÓÚwait·Ç0µÄÇé¿ö£¬´¦Àí¾Í±È½Ï¸´ÔÓЩ¡£Sync_buffers()º¯ÊýÔÚÒ»¸ödo{}whileÑ»·ÖзÖÈý´ÎɨÃé´¦ÀíBUF_DIRTYÁ´±íºÍBUF_LOCKEDÁ´±í£º
(1)µÚÒ»±éɨÃ飬½ö½ö¶ÔBUF_DIRTYÁ´±íÖеÄDirtyÇÒunlockedµÄ»º³åÇøÍ¨¹ýll_rw_block()º¯Êý°²ÅÅ»ØÐ´²Ù×÷£»
(2)µÚ¶þ±àÑ»·ÖÐÖ÷Òªµ÷ÓÃwait_on_buffer()º¯ÊýµÈ´ýµÚÒ»±éËù°²ÅŵĻØÐ´²Ù×÷ÕæÕýÍê³É¡£ÓÉÓÚÔڵȴý¹ý³ÌÖУ¬¿ÉÄÜ»áÓÐеÄÔ໺³åÇø²åÈëµ½BUF_DIRTYÁ´±íÖУ¬Òò´ËÔÚµÚ¶þ±àÑ»·ÖУ¬¶ÔBUF_DIRTYÁ´±íºÍBUF_LOCKEDÁ´±íµÄɨÃéÿ´Î×ÜÊÇ´ÓÁ´±íµÄ±íÍ·¿ªÊ¼£¬Èç¹ûɨÃéµÄ¹ý³ÌÖÐÅöµ½Dirty»º³åÇø£¬ÄÇôҲҪͨ¹ýll_rw_block()º¯Êý¶ÔÆä°²ÅÅ»ØÐ´²Ù×÷¡£ÔÚµÚ¶þ±àÑ»·½áÊøÊ±£¬BUF_DIRTYÁ´±íÖн«²»ÔÙÓÐÈκÎDirty»º³åÇø¡£
(3)µÚÈý±ãÑ»·Ê±Õâ½ö½öÊÇΪÁ˵ȴýµÚ¶þ±éËù°²ÅŵĻØÐ´²Ù×÷½áÊø¡£
º¯ÊýµÄÔ´´úÂëÈçÏÂ(fs/buffer.c):
/* Godamity-damn. Some buffers (bitmaps for filesystems)
* spontaneously dirty themselves without ever brelse being called.
* We will ultimately want to put these in a separate list, but for
* now we search all of the lists for dirty buffers.
*/
static int sync_buffers(kdev_t dev, int wait)
{
int i, retry, pass = 0, err = 0;
struct buffer_head * bh, *next;
/* One pass for no-wait, three for wait:
* 0) write out all dirty, unlocked buffers;
* 1) write out all dirty buffers, waiting if locked;
* 2) wait for completion by waiting for all buffers to unlock.
*/
do {
retry = 0;
/* We search all lists as a failsafe mechanism, not because we expect
* there to be dirty buffers on any of the other lists.
*/
repeat:
spin_lock(&lru_list_lock);
bh = lru_list[BUF_DIRTY];
if (!bh)
goto repeat2;
// nr_buffers_type[BUF_DIRTY]*2ÓÉÓÚBUF_DIRTYÁ´±íÊÇÒ»¸öË«ÏòÑ»·Á´±í
for (i = nr_buffers_type[BUF_DIRTY]*2 ; i-- > 0 ; bh = next) {
next = bh->b_next_free;
if (!lru_list[BUF_DIRTY])
break;
if (dev && bh->b_dev != dev)
continue;
if (buffer_locked(bh)) {
/* Buffer is locked; skip it unless wait is
* requested AND pass > 0.
*/
if (!wait || !pass) {
retry = 1;
continue;
}
atomic_inc(&bh->b_count);
spin_unlock(&lru_list_lock);
wait_on_buffer (bh);
atomic_dec(&bh->b_count);
goto repeat;
}
/* If an unlocked buffer is not uptodate, there has
* been an IO error. Skip it.
*/
if (wait && buffer_req(bh) && !buffer_locked(bh) &&
!buffer_dirty(bh) && !buffer_uptodate(bh)) {
err = -EIO;
continue;
}
/* Don't write clean buffers. Don't write ANY buffers
* on the third pass.
*/
if (!buffer_dirty(bh) || pass >= 2)
continue;
atomic_inc(&bh->b_count);
spin_unlock(&lru_list_lock);
ll_rw_block(WRITE, 1, &bh);
atomic_dec(&bh->b_count);
retry = 1;
goto repeat;
}
repeat2:
bh = lru_list[BUF_LOCKED];
if (!bh) {
spin_unlock(&lru_list_lock);
break;
}
for (i = nr_buffers_type[BUF_LOCKED]*2 ; i-- > 0 ; bh = next) {
next = bh->b_next_free;
if (!lru_list[BUF_LOCKED])
break;
if (dev && bh->b_dev != dev)
continue;
if (buffer_locked(bh)) {
/* Buffer is locked; skip it unless wait is
* requested AND pass > 0.
*/
if (!wait || !pass) {
retry = 1;
continue;
}
atomic_inc(&bh->b_count);
spin_unlock(&lru_list_lock);
wait_on_buffer (bh);
spin_lock(&lru_list_lock);
atomic_dec(&bh->b_count);
goto repeat2;
}
}
spin_unlock(&lru_list_lock);
/* If we are waiting for the sync to succeed, and if any dirty
* blocks were written, then repeat; on the second pass, only
* wait for buffers being written (do not pass to write any
* more buffers on the second pass).
*/
} while (wait && retry && ++pass<=2);
return err;
}
¶Ô¸Ãº¯ÊýµÄÏêϸעÊÍÈçÏ£º
(1)º¯ÊýµÄÖ÷Ìå¾ÍÊÇÒ»¸ödo{}whileÑ»·£¬²¢ÒÀ¾ÝwaitµÄÖµ¾ö¶¨Ñ»·´ÎÊý£¨1or3£©¡£
(2)Ê×ÏÈ£¬Í¨¹ýÒ»¸öforÑ»·À´É¨ÃéBUF_DIRTYÁ´±í¡£ForÑ»·µÄÑ»·´ÎÊýÊÇI=nr_buffers_type¡²BUF_DIRTY¡³¡Á2¡£ÓÉÓÚBUF_DIRTYÁ´±íÊÇÒ»¸öË«ÏòÑ»·Á´±í£¬Òò´ËforÑ»·½«Á´±íɨÃéÁ½´Î(why? I don¡»t know^_^ If you know, please tell me.)¶ÔÓÚÿһ´Î±»É¨ÃéµÄ»º³åÇø£¬Ñ»·Ì彫×÷ÈçÏ´¦Àí£º
n Ê×ÏÈÅжÏlru_list[BUF_DIRTY]Á´±íÊÇ·ñΪ¿Õ¡£Èç¹ûΪNULL£¬ÔòÖÕֹɨÃé¹ý³Ì¡£ÒòΪÿһ¸ö±»°²ÅÅ»ØÐ´µÄÔ໺³åÇø¶¼»á±»ÒƵ½BUF_LOCKEDÁ´±íÖУ¬´Ó¶øÊ¹BUF_DIRTYÁ´±íÖеÄÔªËØ»áÔ½À´Ô½ÉÙ¡£Òò´ËÕâÀïÔÚ¿ªÊ¼´¦Àí֮ǰÓбØÒª½øÐÐÒ»ÏÂÅжϡ£
n Èç¹û²ÎÊýdev·Ç0£¬Ôò½øÒ»²½Åжϵ±Ç°±»É¨ÃéµÄ»º³åÇøÊÇ·ñÊôÓÚÖ¸¶¨µÄ¿éÉ豸¡£Èç¹û²»ÊÇ£¬ÔòɨÃéÁ¿±íÖеÄÏÂÒ»¸öÔªËØ¡£µ±dev=0ʱ£¬sync_buffers()º¯Êýͬ²½ËùÓÐÔ໺³åÇø£¨²»ÂÛËüÊÇÊôÓÚÄĸö¿éÉ豸£©¡£
n ͨ¹ýbuffer_locked()ºêÅжϱ»É¨ÃéµÄ»º³åÇøÊÇ·ñÒѾ±»¼ÓËø£¨ÊÇ·ñÒÔ±»Ñ¡ÖÐÈ¥×ö»ØÐ´²Ù×÷£©¡£Èç¹ûÊÇ£¬Ôò½øÒ»²½ÅжÏwaitºÍpassµÄÖµ¡£Èç¹ûwait=0»òpass=0£¨¼´µÚÒ»±édo{}whileÑ»·£©£¬Ôò²»µÈ´ý¸Ã»º³åÇøµÄ»ØÐ´²Ù×÷Íê³É£¬¶øÊǼÌÐøÉ¨ÃéÁ´±íÖеÄÏÂÒ»¸öÔªËØ¡£·ñÔò£¨wait!=0ÇÒpass!=0£©¾Íµ÷ÓÃwait_on_buffer()º¯ÊýµÈ´ý¸Ã»º³åÇø±»½âËø£¬È»ºóÖ´ÐÐgoto repeatÓï¾ä£¬ÖØÐ´ÓÁ´±íµÄ¿ªÍ·¿ªÊ¼É¨Ã飨ÔÒòÈçǰËùÊö£©¡£
n ·ñÔò¾Í¼ì²éÕâ¸öunlocked»º³åÇøµÄ״̬ÊÇ·ñÕýÈ·¡£Èç¹û²»ÕýÈ·£¬¾ÍºöÂÔËü£¬¼ÌÐøÉ¨ÃéÏÂÒ»¸öÁ´±íÔªËØ¡£
n Èç¹ûÕâ¸öunlocked»º³åÇøµÄ״̬ÕýÈ·£¬Ôò½øÒ»²½Åжϻº³åÇøÊÇ·ñ²»ÎªÔ࣬»òÕßÊÇΪµÚÈý±àÑ»·£¨ÔÚµÚÈý±àÑ»·ÖУ¬¼´Ê¹Óöµ½Ô໺³åÇø£¬Ò²²»


