⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 035_fs_buffer_c.html

📁 重读linux 2.4.2o所写的笔记
💻 HTML
📖 第 1 页 / 共 5 页
字号:
        #define<font color=#006600> BUF_CLEAN</font>&nbsp;&nbsp;&nbsp; 0<br>
        #define <font color=#006600>BUF_LOCKED&nbsp;</font>&nbsp;&nbsp;
        1&nbsp;&nbsp;&nbsp; /* Buffers scheduled for write */<br>
        #define<font color=#006600> BUF_DIRTY</font>&nbsp;&nbsp;&nbsp;
        2&nbsp;&nbsp;&nbsp; /* Dirty buffers, not yet scheduled for write */<br>
        #define <font color=#006600>BUF_PROTECTED</font>&nbsp;&nbsp;&nbsp;
        3&nbsp;&nbsp;&nbsp; /* Ramdisk persistent storage */<br>
        #define NR_LIST&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 4<br>
        static void <font color=#006600>__insert_into_lru_list</font>(struct
        buffer_head * bh, int blist)<br>
        static void <font color=#009900>__remove_from_lru_list</font>(struct
        buffer_head * bh, int blist)<br>
        <br>
        static void <font color=#006600>__refile_buffer</font>(struct
        buffer_head *bh)<br>
        void <font color=#009900>refile_buffer</font>(struct buffer_head *bh)<br>
        static __inline__ void <font color=#006600>__mark_dirty</font>(struct
        buffer_head *bh)<br>
        void <font color=#006600>__mark_buffer_dirty</font>(struct buffer_head
        *bh)<br>
        static inline void <font color=#006600>__mark_buffer_clean</font>(struct
        buffer_head *bh)<br>
        static inline void <font color=#006600>mark_buffer_clean</font>(struct
        buffer_head * bh)<br>
        static inline void
        <font color=#006600>__mark_buffer_protected</font>(struct buffer_head
        *bh)<br>
        static inline void
        <font color=#006600>mark_buffer_protected</font>(struct buffer_head *
        bh)<br>
        <br>
        这些mark函数当然是标记buffer 的各种状态,然后通过
        refile_buffer在各种类型的lru队列间移动。比较简单,就算是考虑的同步和互斥<br>
        啥的也不能算作是复杂吧?<br>
        <br>
        <br>
        <b>有时需要一些打包函数</b>,将buffer head 同时加入hash 和lru队列。<br>
        static void <font color=#006600>__remove_from_queues</font>(struct
        buffer_head *bh)<br>
        static void <font color=#006600>__insert_into_queues</font>(struct
        buffer_head *bh)<br>
        <font color=#006600><br>
        __refile_buffer<font color=#000000>
        中有个</font></font><font color=#006600><font color=#000000>
        remove_inode_queue(bh) 的操作值得注意一下。</font></font><font color=#006600><br>
        <font color=#000000>/*<br>
        &nbsp;* A buffer may need to be moved from one buffer list to another<br>
        &nbsp;* (e.g. in case it is not shared any more). Handle this.<br>
        &nbsp;*/<br>
        static void __refile_buffer(struct buffer_head *bh)<br>
        {<br>
        &nbsp;&nbsp;&nbsp; int dispose = BUF_CLEAN;<br>
        &nbsp;&nbsp;&nbsp; if (buffer_locked(bh))<br>
        &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; dispose = BUF_LOCKED;<br>
        &nbsp;&nbsp;&nbsp; if (buffer_dirty(bh))<br>
        &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; dispose = BUF_DIRTY;<br>
        &nbsp;&nbsp;&nbsp; if (buffer_protected(bh))<br>
        &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; dispose = BUF_PROTECTED;<br>
        &nbsp;&nbsp;&nbsp; if (dispose != bh-&gt;b_list) {<br>
        &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; __remove_from_lru_list(bh,
        bh-&gt;b_list);<br>
        &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; bh-&gt;b_list = dispose;<br>
        &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;<b>&nbsp; if (dispose ==
        BUF_CLEAN)</b><br style=FONT-WEIGHT:bold>
        <b>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
        &nbsp;&nbsp;&nbsp;</b><font color=#006600><b>
        remove_inode_queue</b></font><b>(bh);</b><br>
        &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; __insert_into_lru_list(bh,
        dispose);<br>
        &nbsp;&nbsp;&nbsp; }<br>
        }</font><br>
        &nbsp;i<font color=#000000>node 中有个</font>inode-&gt;i_dirty_buffers
        <font color=#000000>记录了这个inode中所有dirty的数据。稍后我们再分析这个dirty的数据是什么:元数据还是文件<br>
        数据。</font><br>
        </font>/* The caller must have the lru_list lock before calling the<br>
        &nbsp;&nbsp; remove_inode_queue functions.&nbsp; */<br>
        static void __remove_inode_queue(struct buffer_head *bh)<br>
        {<br>
        &nbsp;&nbsp;&nbsp; bh-&gt;b_inode = NULL;<br>
        &nbsp;&nbsp;&nbsp; list_del(&amp;bh-&gt;b_inode_buffers);<br>
        }<br>
        <br>
        static inline void remove_inode_queue(struct buffer_head *bh)<br>
        {<br>
        &nbsp;&nbsp;&nbsp;<b> if (bh-&gt;b_inode)&nbsp; //可以看出,并不是每个buffer
        都和一个inode 相对应的,只有以部分才有.</b><br>
        &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; __remove_inode_queue(bh);<br>
        }<br>
        int inode_has_buffers(struct inode *inode);//这个简单。。<br>
        <br>
        到底什么buffer才有inode与之对应,等分析万buffer cache的创建就会清楚了。<br>
        我们先来看看buffer cache 的创建,藉此研究buffer cache 中的内容以及buffer cache
        和系统其他几个部分之间的关系:<br>
        <br>
        <div style=TEXT-ALIGN:center>
          <b>3)buffer cache 的创建与buffer head 的回收<br>
          <br>
          </b>
        </div>
        <b>&nbsp;&nbsp;&nbsp;&nbsp;</b> 实际上,<b>有两种类型的buffer_head
        存在于系统中</b>,<b>一种存在于buffer cache</b>, 存在于buffer cache 中的 buffer(head)<br>
        必然存在于lur list。<font color=#990000><b>这中类型的buffer 其唯一的分配途径就是</b></font>
        <font color=#006600><b>getblk</b></font>, 然后通过bread(kdev_t dev, int
        block, int size)被广泛用于读取文件的元数据:<br>
        struct buffer_head * <font color=#006600><b>getblk</b></font>(kdev_t
        dev, int block, int size)<br>
        {<br>
        &nbsp;&nbsp;&nbsp; ....<br>
        repeat:<br>
        &nbsp;&nbsp;&nbsp; spin_lock(&amp;lru_list_lock);<br>
        &nbsp;&nbsp;&nbsp; write_lock(&amp;hash_table_lock);<br>
        &nbsp;&nbsp;&nbsp; bh = __get_hash_table(dev, block, size); <b>//look up
        in hash first </b><br>
        &nbsp;&nbsp;&nbsp; if (bh)<br>
        &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; goto out; <b>//找到就简单了</b><br>
        <br>
        &nbsp;&nbsp;&nbsp; isize = BUFSIZE_INDEX(size);<br>
        &nbsp;&nbsp;&nbsp; spin_lock(&amp;free_list[isize].lock);<br>
        &nbsp;&nbsp;&nbsp; bh = free_list[isize].list;&nbsp;&nbsp; <b>//尝试在free
        list 中分配一个</b><br>
        &nbsp;&nbsp;&nbsp; if (bh) {<br>
        &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; __remove_from_free_list(bh,
        isize);<br>
        &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; atomic_set(&amp;bh-&gt;b_count,
        1);<br>
        &nbsp;&nbsp;&nbsp; }<br>
        &nbsp;&nbsp;&nbsp; spin_unlock(&amp;free_list[isize].lock);<br>
        <br>
        &nbsp;&nbsp;&nbsp; /*<br>
        &nbsp;&nbsp;&nbsp; &nbsp;* OK, FINALLY we know that this buffer is the
        only one of<br>
        &nbsp;&nbsp;&nbsp; &nbsp;* its kind, we hold a reference (b_count&gt;0),
        it is unlocked,<br>
        &nbsp;&nbsp;&nbsp; &nbsp;* and it is clean.<br>
        &nbsp;&nbsp;&nbsp; &nbsp;*/<br>
        &nbsp;&nbsp;&nbsp; if (bh) {<br>
        &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; init_buffer(bh, NULL, NULL);<br>
        &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; bh-&gt;b_dev = dev;<br>
        &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; bh-&gt;b_blocknr = block;<br>
        &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; bh-&gt;b_state = 1 &lt;&lt;
        BH_Mapped; <b>//mapped buffer 已经有设备上的sector和之相对应</b><br>
        <br>
        &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; /* Insert the buffer into the
        regular lists */<br>
        &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; __insert_into_queues(bh);&nbsp;
        <b>//进入hash 和 lru队列</b><br>
        &nbsp;&nbsp;&nbsp; out:<br>
        &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
        write_unlock(&amp;hash_table_lock);<br>
        &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; spin_unlock(&amp;lru_list_lock);<br>
        &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; touch_buffer(bh);<br>
        &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return bh;<br>
        &nbsp;&nbsp;&nbsp; }<br>
        <br>
        &nbsp;&nbsp;&nbsp; /*<br>
        &nbsp;&nbsp;&nbsp; &nbsp;* If we block while refilling the free list,
        somebody may<br>
        &nbsp;&nbsp;&nbsp; &nbsp;* create the buffer first ... search the hashes
        again.<br>
        &nbsp;&nbsp;&nbsp; &nbsp;*/<br>
        &nbsp;&nbsp;&nbsp; write_unlock(&amp;hash_table_lock);<br>
        &nbsp;&nbsp;&nbsp; spin_unlock(&amp;lru_list_lock);<br>
        &nbsp;&nbsp;&nbsp;<b> refill_freelist</b>(size);&nbsp;<b>
        //分配失败的话,重新分配一批buffer 进来,再试</b><br>
        &nbsp;&nbsp;&nbsp; goto repeat;<br>
        }<br>
        /*<br>
        &nbsp;* We used to try various strange things. Let's not.<br>
        &nbsp;* We'll just try to balance dirty buffers, and possibly<br>
        &nbsp;* launder some pages.<br>
        &nbsp;*/<br>
        static void <b>refill_freelist</b>(int size)<br>
        {<br>
        &nbsp;&nbsp;&nbsp; balance_dirty(NODEV); // buffer 的回收策略,后面分析<br>
        &nbsp;&nbsp;&nbsp; if (free_shortage())&nbsp; //看看空闲物理页面是否足够
        (以前分析过这个函数...)<br>
        &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; page_launder(GFP_BUFFER, 0);
        //不够的话先释放一些buffer出来<br>
        &nbsp;&nbsp;&nbsp; grow_buffers(size); //然后再创建buffer 到free list中<br>
        }<br>
        static int <b>grow_buffers</b>(int size)<br>
        {<br>
        &nbsp;&nbsp;&nbsp; ....<br>
        &nbsp;&nbsp;&nbsp; page = alloc_page(GFP_BUFFER); //分配页面<br>
        &nbsp;&nbsp;&nbsp; if (!page)<br>
        &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; goto out;<br>
        &nbsp;&nbsp;&nbsp; LockPage(page);<br>
        &nbsp;&nbsp;&nbsp; bh = create_buffers(page, size, 0);
        <b>//创建buffer,看看前面的概念,就是建立三元组(buffer_head, page, data buffer)</b><br>
        &nbsp;&nbsp;<br>
        &nbsp;&nbsp;&nbsp; insert_point = free_list[isize].list;<br>
        &nbsp;&nbsp;&nbsp; .......<br>
        &nbsp;&nbsp;&nbsp; free_list[isize].list = bh;&nbsp;&nbsp;<b>&nbsp;
        //insert 到free list</b><br>
        &nbsp;&nbsp;&nbsp; spin_unlock(&amp;free_list[isize].lock);<br>
        <br>
        &nbsp;&nbsp;&nbsp; page-&gt;buffers = bh;<br>
        &nbsp;&nbsp;&nbsp; page-&gt;flags &amp;= ~(1 &lt;&lt; PG_referenced);<br>
        &nbsp;&nbsp;&nbsp; lru_cache_add(page);
        <b><font color=#ff0000>//注意这里把page加入page cache的lru队列</font></b><br>
        &nbsp;&nbsp;&nbsp; ......<br>
        }<br>
        <font color=#cc0000>为啥吧page加入page cache的lru队列?</font>目的是让page cache
        帮助进行buffer
        head的老化回收:你注意到__put_unused_buffer_head的话,会发现只有<font color=#006600><b>try_to_free_buffers</b></font>才会调用这个函数(brw_kiovec也调用,但是不进入"主干",大部分buffer走不到那个分支上),秘密就在这里.
        算是知道为啥page cache 和buffer cache纠缠不清了,真的是一个阴阳鱼啊.<br>
        <br>
        static struct buffer_head * create_buffers(struct page * page, unsigned
        long size, int async) //略过<br>
        <br>
        <font color=#660000><b>另外一种buffer,并不存在于buffer cache
        中</b>,</font><b><font color=#660000>仅仅作为磁盘rw的中介</font>,主要的创建接口函数</b>:<br>
        static void
        <font color=#006600><b>create_empty_buffers</b></font>(struct page
        *page, kdev_t dev, unsigned long blocksize)<br>
        create_empty_buffers为在给定的page上建立buffer,只是没有将buffer
        映射的具体的磁盘块上,就是unmaped的buffer具体的映射操作交给具体的文件系统来处理。待会看个例子。<br>
        <font color=#006600> create_empty_buffers</font>
        为各种具体文件系统的文件读写(非元数据)提供一个和磁盘驱动交互的bh序列(把这个page切割成buffer),<br>
        是文件系统和磁盘驱动交换数据的具体形式。据传,2.6系统中取消了buffer cache,仅仅保留这种类型的buffer,蜕变成一个io
        entry。<br>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -