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

📄 buffer.c.txt

📁 linux内核学习笔记 希望想看的人可以很快下载到
💻 TXT
📖 第 1 页 / 共 2 页
字号:
any question,send email to netxiong@263.net


相关文件:
	/init/main.c	

该文件提供了文件的buffer功能的大部分实现,同时也对块设备的buffer有效

****************************基本数据结构*************************
(1):#define NR_SIZES 7	//最多由7种buffer大小的类型512,1024,2048,4096,8192,34816,

(2):static char buffersize_index[65] =
 {-1,  0,  1, -1,  2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1,
  4, -1, -1, -1, -1, -1, -1, -1, -1,-1, -1, -1, -1, -1, -1, -1,
  5, -1, -1, -1, -1, -1, -1, -1, -1,-1, -1, -1, -1, -1, -1, -1,
 -1, -1, -1, -1, -1, -1, -1, -1, -1,-1, -1, -1, -1, -1, -1, -1,
  6};//hash函数的映射表,-1处不使用,0----6代表了7种类型

(3):#define BUFSIZE_INDEX(X) ((int) buffersize_index[(X)>>9])
	#例如 4096>>9 = 8(1000)
	#buffersize_index[8] = 3

(4):static struct buffer_head **hash_table;   //hash数组,存储了所有的buffer
static rwlock_t hash_table_lock = RW_LOCK_UNLOCKED//链表的自旋锁
**********************************************************************


****************************各种内存连表的定义和函数*************************
(5):struct bh_free_head {
        struct buffer_head *list;
        spinlock_t lock;
};
(6):static struct bh_free_head free_list[NR_SIZES];

基本函数:
static void __remove_from_free_list(struct buffer_head * bh, int index)
	#将bh代表的buffer从free_list buffer池中删除
	#程序挺有意思,值得一看,很简单
	#首先将bh从双向链表中删除,
	#如果free_list指向的是bh,则将free_list指向bh的next buffer.


定义了lru数组,4个元素。(include/linux/fs.h)
	BUF_CLEAN0,BUF_LOCKED,BUF_DIRTY,BUF_PROTECTED
static struct buffer_head *lru_list[NR_LIST];	//几种不同的buffer池 
static int nr_buffers_type[NR_LIST];	//每一种相应的buffer池中的buffer数量
static unsigned long size_buffers_type[NR_LIST]; //每一种相应的池中的总量
static spinlock_t lru_list_lock = SPIN_LOCK_UNLOCKED;//链表的自旋锁

处理函数:
(1):static void __insert_into_lru_list(struct buffer_head * bh, int blist)
	#将一个buffer插入倒blist类型的lru buffer池中
	#将bh加入到 &lru_list[blist]的前面(后来的buffer加入到头部)
	#nr_buffers_type[blist]++;	//增加相应的buffer数目
	#size_buffers_type[blist] += bh->b_size;//增加相应的buffer池的容量

(2):static void __remove_from_lru_list(struct buffer_head * bh, int blist)



(8):
static struct buffer_head * unused_list;	
static int nr_unused_buffer_heads;	//为使用的buffer_head的数目
static DECLARE_WAIT_QUEUE_HEAD(buffer_wait);
static spinlock_t unused_list_lock = SPIN_LOCK_UNLOCKED;//链表的自旋锁

***************************************************************************


************************基本宏************************************
(1):#define _hashfn(dev,block)      \	//哈希映射函数
        ((((dev)<<(bh_hash_shift - 6)) ^ ((dev)<<(bh_hash_shift - 9))) ^ \
         (((block)<<(bh_hash_shift - 6)) ^ ((block) >> 13) ^ \
          ((block) << (bh_hash_shift - 12))))
(2):#define hash(dev,block) hash_table[(_hashfn(HASHDEV(dev),block) & 		bh_hash_mask)]
	#这两个宏的作用就是buffer池中取出相应的buffer。

******************************************************************





***************************基本函数*******************************
(1):void __init buffer_init(unsigned long mempages)
	#这个函数再main.c中被调用,作用是为系统提供一系列的buffer.
	#首先进行了一系列的计算
	# hash_table = (struct buffer_head **)
			__get_free_pages(GFP_ATOMIC, order);
	#然后调用__get_free_pages进行页分配,从而产生了一个buffer池
	#对hash_table的buffer池进行初始化。
	#对free_list进行初始化
	#对lru_list进行初始化
******************************************************************





****************************守护进程*******************************
(1):static int __init bdflush_init(void)
	#初始化两个守护线程
	# kernel_thread(bdflush, &sem, CLONE_FS | CLONE_FILES | CLONE_SIGNAL);
	#kernel_thread(kupdate, &sem, CLONE_FS | CLONE_FILES | CLONE_SIGNAL);

(2):int kupdate(void *sem)
	#更新进程

(3):int bdflush(void *sem)
	#守护进程,无限循环,负责将dirty数据刷新倒设备上
	#主要的函数调用是flushed = flush_dirty_buffers(0);

(4):static int flush_dirty_buffers(int check_flushtime)
	#这个函数将实际上的dirty数据写倒设备上去
	#bh = lru_list[BUF_DIRTY];	//我们值更新BUF_DIRTY的buffer.
	#ll_rw_block(WRITE, 1, &bh);	//这是最为关键的一步,将buffer中的数					//据写到块设备上去
	
*******************************************************************


**************************数据结构图********************************
hash_table
    [0]------->buffer_head
    [1]--->null
    […]
    [n]--->null
    [n+1]------>buffer_head
       |<---------b_pprev
                  b_next--------->buffer_head
		    |<---------------b_pprev
    [n+2]
    […]	 	

free_list	(使用b_next_free字段进行连接)
    [0](512)--------->buffer_head-------->buffer_head
    [1](1024)-------->buffer_head-------->buffer_head
    […]

		(使用b_next_free字段进行连接)
unused_list------>buffer_head--------->buffer_head
********************************************************************


**************************getblk函数集******************************
(1):struct buffer_head * getblk(kdev_t dev, int block, int size) (2.4.2)
	#函数的作用是从设备号dev和请求的块号block来得到所请求的buffer池入口
	# bh = __get_hash_table(dev, block, size);//从hash表中取出buffer入口
	# if (bh)
                goto out;	//如果能够找到,就到出口处
	#否则bh = free_list[isize].list;//从free_list表中取出一个空闲的head
	#if (bh) {	//如果free_list表中还有buffer_head
                __remove_from_free_list(bh, isize);
                atomic_set(&bh->b_count, 1);	//buffer_head的使用者加一
          }//如果空闲的head表中又buffer_head,则把他从空闲表中删除并加一
	#如果bh有效init_buffer(bh, NULL, NULL)//对bh进行初始化
	# __insert_into_queues(bh);	//加入到hash_table相应的入口中
	#out:
		 touch_buffer(bh);	//将buffer中的page位置位(?)
                 return bh;		//返回bh
	#如果没有相应的buffer_head
	#refill_freelist(size)	//从新对free_list进行处理,等待一个可用的free
	#跳转到函数头,从新执行。

(2):static void refill_freelist(int size)
	# balance_dirty(NODEV);//对dirty数据页进行平衡,计算是否要想设备写
	# grow_buffers(size);	//增加buffers。

(3):static int grow_buffers(int size)(2.4.2)
	#在free_list[]上扩建一页块长为blocksize的备用缓冲区;
	#page = alloc_page(GFP_BUFFER);//申请一个页
	#bh = create_buffers(page, size, 0);//在页上生成一个size的缓冲区
	#insert_point = free_list[isize].list;//得到插入点
	#if (insert_point) {//插到头节点的后面
                        tmp->b_next_free = insert_point->b_next_free;
                        tmp->b_prev_free = insert_point;
                        insert_point->b_next_free->b_prev_free = tmp;
                        insert_point->b_next_free = tmp;
                } else {//如果是第一个话,就插入倒后面
                        tmp->b_prev_free = tmp;
                        tmp->b_next_free = tmp;
                }


(4):static struct buffer_head * create_buffers(struct page * page, unsigned 	long size, int async)
	#创建块长为blocksize的buffer_head结构来描述页面page.
	#bh = get_unused_buffer_head(async);//得到一个buffer_head
	# if (!bh)
                        goto no_grow;	//如果没有buffer_head,等待
	#否则的话就对bh进行设置
	#no_grow:
	# wait_event(buffer_wait, nr_unused_buffer_heads >= 					MAX_BUF_PER_PAGE);//等待

():static struct buffer_head * get_unused_buffer_head(int async)
	#得到一个空闲的buffer_head

():static __inline__ void __put_unused_buffer_head(struct buffer_head * bh)
	#将buffer_head加入到unused_list中去
	# if (nr_unused_buffer_heads >= MAX_UNUSED_BUFFERS)
		 kmem_cache_free(bh_cachep, bh);//如果buffer太多,释放
	#否则   nr_unused_buffer_heads++;
                bh->b_next_free = unused_list;
                bh->b_this_page = NULL;
                unused_list = bh;//将新buffer_head加入到unused_list中去
	#注意:unused_list就是在这里被赋值的。无论unused_list是什么。
********************************************************************



************************缓存的申请和释放过程*************************
union bdflush_param {
        struct {
                int nfract;     /* 脏块比例达到多少唤醒bdflush进程 */
                int dummy1;     /* old "ndirty" */
                int dummy2;     /* old "nrefill" */
                int dummy3;     /* unused */
                int interval;   /* jiffies delay between kupdate flushes */
                int age_buffer; /* Time for normal buffer to age before we flush it */
                int nfract_sync;/* 脏块比例达到多少唤醒bdflush进程进行同步flush */
                int dummy4;     /* unused */
                int dummy5;     /* unused */
        } b_un;
        unsigned int data[N_PARAM];
} bdf_prm = {{40, 0, 0, 0, 5*HZ, 30*HZ, 60, 0, 0}};	//默认值是40%和60%



(1)struct buffer_head * getblk(kdev_t dev, int block, int size)
        for (;;) {				//循环一直到申请成功
                struct buffer_head * bh;

                bh = get_hash_table(dev, block, size);	//从hash表中得到一个bh
                if (bh)
                        return bh;			//如果可以的话就返回

                if (!grow_buffers(dev, block, size))	//如果
                        free_more_memory();		//释放一部分buffers
        }

(2)static int grow_buffers(kdev_t dev, unsigned long block, int size)
        /* size大小必须是设备硬扇区大小的整数倍 */
        if (size & (get_hardsect_size(dev)-1))
                BUG();
        /* Size大小必须在512字节和PAGE_SIZE之间 */
        if (size < 512 || size > PAGE_SIZE)
                BUG();

	//将块的序号进行页对齐,例如页大小为4K,块设备的大小为1K,那么第5块的index就是
	//2,这里的index就是以4K页来计算的号码
        sizebits = -1;
        do {
                sizebits++;
        } while ((size << sizebits) < PAGE_SIZE);
        index = block >> sizebits;
        block = index << sizebits;

        page = grow_dev_page(bdev, index, size);	//产生一页
	

⌨️ 快捷键说明

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