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

📄 buffer.c.txt

📁 linux内核学习笔记 希望想看的人可以很快下载到
💻 TXT
📖 第 1 页 / 共 2 页
字号:
        hash_page_buffers(page, dev, block, size);	//将这个新产生的页加入到相应的hash表中


(3)static struct page * grow_dev_page(struct block_device *bdev, unsigned long index, int size)
        page = find_or_create_page(bdev->bd_inode->i_mapping, index, GFP_NOFS);	//首先找到一个页面

        bh = page->buffers;	//先得到这个页面的buffer域
        if (bh) {		//如果buffers域中有数据
                if (bh->b_size == size)		//如果正好是这个大小的,就返回这个页面
                        return page;
                if (!try_to_free_buffers(page, GFP_NOFS))	//否则,试着释放掉这个页面
                        goto failed;
        }
	
        bh = create_buffers(page, size, 0);	//否则的话就在这个页面上产生一个新的buffer
	if (!bh)
                goto failed;
        link_dev_buffers(page, bh);
        return page;

(4)static struct buffer_head * create_buffers(struct page * page, unsigned long size, int async)
        struct buffer_head *bh, *head;
        long offset;
        head = NULL;
        offset = PAGE_SIZE;
        while ((offset -= size) >= 0) {			//把这一页都设置为size大小的buffer
                bh = get_unused_buffer_head(async);	//必须首先得到一个有效的buffer_head结构
                if (!bh)
                        goto no_grow;	//如果没有,就释放一些buffer_head结构

                bh->b_dev = NODEV;	
                bh->b_this_page = head;	//设置在一个页中的buffer环
                head = bh;
		……	//对bh进行初始化
                set_bh_page(bh, page, offset);

                bh->b_list = BUF_CLEAN;
                bh->b_end_io = NULL;
        }
        return head;


void set_bh_page (struct buffer_head *bh, struct page *page, unsigned long offset)
{
        if (offset >= PAGE_SIZE)	//进行合法性检查
                BUG();

        bh->b_data = page_address(page) + offset;	//数据的开始地址,结束地址可以使用开始
							//地址加上bh->b_size来进行计算
        bh->b_page = page;	//纪录这个buffer所处的内存页
}



(4)static inline void link_dev_buffers(struct page * page, struct buffer_head *head)
        struct buffer_head *bh, *tail;
        bh = head;
        do {
                tail = bh;
                bh = bh->b_this_page;	//寻找这个buffer所在的内存页面的所有的buffer,
        } while (bh);	

        tail->b_this_page = head;	//把属于一个内存页面的所有的buffer连接成为一个环
        page->buffers = head;
        page_cache_get(page);


()static void free_more_memory(void)
        balance_dirty();		//计算脏块所占的比例
        wakeup_bdflush();		//唤醒写脏块进程
        try_to_free_pages(GFP_NOFS);
        run_task_queue(&tq_disk);
        __set_current_state(TASK_RUNNING);
        sys_sched_yield();


(3)void balance_dirty(void)
	int state = balance_dirty_state();	//计算flush策略
        if (state < 0)				//如果脏块比例不打,返回
                return;
        wakeup_bdflush();			//唤醒flush进程
        if (state > 0) {			//如果是同步flush的话,就等待他完成
                spin_lock(&lru_list_lock);
                write_some_buffers(NODEV);
                wait_for_some_buffers(NODEV);
        }

	

//返回值-1表示不用flush
//0-->异步flush
//1-->同步flush
(4)static int balance_dirty_state(void)
	
	……	//计算脏的比例
	
        soft_dirty_limit = tot * bdf_prm.b_un.nfract;
        hard_dirty_limit = tot * bdf_prm.b_un.nfract_sync;

	//如果脏块数量占的比例不是很大,那么就异步flush,也就是仅仅唤醒flush进程
        if (dirty > soft_dirty_limit) {	
                if (dirty > hard_dirty_limit && !(current->flags & PF_NOIO))
                        return 1;	//如果脏块比例过大,那么就唤醒flush进程并等待他完成
                return 0;
        }

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


***********************异步等待操作**********************************
相关文件
	include/linux/locks.h

这个函数主要是运行块设备的运行例程,从而将传入的buffer_head上所制定的操作完成
void __wait_on_buffer(struct buffer_head * bh)
	DECLARE_WAITQUEUE(wait, tsk);	//生命等待队列
	get_bh(bh);			//buffer_head计数加一
	add_wait_queue(&bh->b_wait, &wait);	//把buffer_head加入到等待队列中
	do {
		run_task_queue(&tq_disk);	//运行磁盘操作队列,进行读写
		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
		if (!buffer_locked(bh))		//如果bh还是加锁,说明没有完成操作
			break;
		schedule();			//调度,等待
	} while (buffer_locked(bh));		//直到bh解锁
	……					//后续处理
*********************************************************************


**************************异步读操作**********************************
struct buffer_head * bread(kdev_t dev, int block, int size)
	bh = getblk(dev, block, size);	//的到一个buffer_head结构
	touch_buffer(bh);		
	if (buffer_uptodate(bh))	//如果的缓存结构中的buffer_head已经是更新的了,就直接返回
		return bh;
	ll_rw_block(READ, 1, &bh);	//否则进行读操作
	wait_on_buffer(bh);		//等待读操作完成
	if (buffer_uptodate(bh))
		return bh;
	brelse(bh);			//释放bh
	return NULL;			//失败的读操作
**********************************************************************



***************************direct I/O操作*****************************
(1)
int brw_kiovec(int rw, int nr, struct kiobuf *iovec[],
		kdev_t dev, unsigned long b[], int size)
	for (i = 0; i < nr; i++) {	//对于每一个输入的kiobuf的结构
		iobuf = iovec[i];	
		……			//都要进行合法性检查	
	}
		
	bufind = bhind = transferred = err = 0;
	for (i = 0; i < nr; i++) {		//可以walk这些vec来进行读写了
		iobuf = iovec[i];
		offset = iobuf->offset;		//
		length = iobuf->length;		//取出这个kiobuf要读写的数据长度
		if (!bhs)
			bhs = iobuf->bh;	//取出这个kiobuf的bh池
	
		for (pageind = 0; pageind < iobuf->nr_pages; pageind++) { //遍历kiobuf中所有的页
			map  = iobuf->maplist[pageind];		//得到一个页面结构
			while (length > 0) {			//如果读写的长度不是0
				blocknr = b[bufind];		//挨个查询块号
				if (blocknr == -1UL) {		//如果块号是负数
					if (rw == READ) {
						memset(kmap(map) + offset, 0, size);
						flush_dcache_page(map);
						kunmap(map);
						transferred += size;
						goto skip_block;
					} else
						BUG();
				}				//????
				if (iobuf->dovary && (offset == 0)) {
					iosize = RAWIO_BLOCKSIZE; 
					if (iosize > length)
						iosize = length;
				}				//????
				bufind += (iosize/size);	//得到下一个读写的这个设备的块号。
				tmp = bhs[bhind++];		//从kiobuf的bh池中取出一个bh结构
				
				tmp->b_size = iosize;		//设置bh的读写大小
				set_bh_page(tmp, map, offset);	//将取到的页面挂在bh上
				tmp->b_this_page = tmp;		//
				
				init_buffer(tmp, end_buffer_io_kiobuf, iobuf);	//设置回调函数
				tmp->b_dev = dev;		//设置读写设备号
				tmp->b_blocknr = blocknr;	//设置读写的块号
				……				//其它设置
					
				/*
				 * 这行代码很重要。使用这个io_count来对这个kiobuf
				 * 中所提交的bh进行计数跟踪。
				 */
				atomic_inc(&iobuf->io_count);	
				
				submit_bh(rw, tmp);		//进行实际读写
			
				/*
				 * 如果kiobuf中的bh池(kiobuf->bh)中已经没有bh了,就等待
				 * 先前做的kiobuf的读写完成,释放一部分bh。
				 */
				if (bhind >= KIO_MAX_SECTORS) {
					kiobuf_wait_for_io(iobuf); /* wake-one */
					err = wait_kio(rw, bhind, bhs, size);	
					if (err >= 0)
						transferred += err;
					else
						goto finished;
					bhind = 0;	//释放原来的bh结构,供后续操作使用
				}
				
				length -= iosize;	//从要读取的总长度中减去已经做过的
				offset += iosize;	//偏移量也增加相应的长度

				if (offset >= PAGE_SIZE) {	//如果偏移量已经超出了一个页面
					offset = 0;		//偏移量置为0
					break;			//推出这个页面的循环,取新页面。
				}
			}
		}
	}
		
	if (bhind) {	//如果bhind不为0,说明还有剩余的bh没有完成
		kiobuf_wait_for_io(iobuf); 
		err = wait_kio(rw, bhind, bhs, size);	//等待这些bh的完成
		if (err >= 0)
			transferred += err;
		else
			goto finished;
	}

	
(2)
static void end_buffer_io_kiobuf(struct buffer_head *bh, int uptodate)
	mark_buffer_uptodate(bh, uptodate);	//标志数据块已经更新

	kiobuf = bh->b_private;			//取出kiobuf结构
	end_kio_request(kiobuf, uptodate);	//完成kiobuf请求
	unlock_buffer(bh);			//解锁bh。
			


(3)
/*
 * 这个函数很简单,就是对于参数指定数目nr的bh结构数据,遍历这些bh结构,等待,
 * 直到所有的bh都更新了。
 */
static int wait_kio(int rw, int nr, struct buffer_head *bh[], int size)
	
**********************************************************************


⌨️ 快捷键说明

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