范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

Linux0。11kernel目录llrwblk。c详解

  该模块的作用是处理块设备的读写,其中最重要的函数就是电梯算法 add_request 函数和 ll_rw_block 函数。 add_requeststatic void add_request(struct blk_dev_struct * dev, struct request * req)
  该函数的作用是将块设备读写请求 插入到电梯队列 中。
  首先将数据的脏数据标志置为0。 if (req->bh) 	req->bh->b_dirt = 0;
  如果当前设备的请求为空,就将入参中的请求作为设备电梯队列的头节点。并且立即调用request_fn。request_fn对于不同的设备对应不同的回调函数,对于硬盘设备而言,request_fn指的是do_hd_request,关于do_hd_request,将在hd.c中进行讲解。 if (!(tmp = dev->current_request)) {     dev->current_request = req;     sti();     (dev->request_fn)();     return; }
  上面的部分处理了请求队列只有一个请求的场景,接下来便是当请求队列有多个请求时,如何处理优先级顺序的逻辑,也就是电梯算法部分,其中最难理解的便是宏定义IN_ORDER。IN_ORDER的定义如下所示。 #define IN_ORDER(s1,s2)  ((s1)->cmd<(s2)->cmd || ((s1)->cmd==(s2)->cmd &&  ((s1)->dev < (s2)->dev || ((s1)->dev == (s2)->dev &&  (s1)->sector < (s2)->sector))))
  上述代码是比较难懂的,可以使用if-else来帮助理解 bool inorder(request &s1, request &s2) {     if(s1.cmd < s2.cmd>){         return true;     }     else if(s1.cmd == s2.cmd){         if(s1.dev < s2.dev){             return true;         }         else if(s1.dev == s2.dev){             if(s1.sector < s2.sector){                 return true;             }             return false;//s1.sector > s2.sector         }         return false;//s1.dev > s2.dev     }     return false;//s1.cmd > s2.cmd }
  展开上面的if-else结构逻辑就清晰了很多,IN_ORDER实际上就是依次对操作类型,设备号, 扇区号作比较,并且操作类型优先级大于设备号,设备号优先级大于扇区号。
  对于操作类型而言,读操作优先级大于写操作。对于设备号而言,设备号小的设备优先级大于设备号大的设备的优先级。对于扇区而言,扇区序号小的扇区优先级高于扇区序号大的扇区。
  有了这个认识之后,再看下面的语句,就会简单很多,实际上就是根据优先级找到合适的位置插入数据。 for ( ; tmp->next ; tmp=tmp->next) 	if ((IN_ORDER(tmp,req) ||  		!IN_ORDER(tmp,tmp->next)) && 		IN_ORDER(req,tmp->next)) 		break; req->next=tmp->next; tmp->next=req;
  下面的这一段代码可以用两个if语句进行替代,即 定向扫描 和 折返扫描 两个场景。 if ((IN_ORDER(tmp,req) ||  	!IN_ORDER(tmp,tmp->next)) && 	IN_ORDER(req,tmp->next))
  条件1:定向扫描, req在当前扫描的方向上 if(tmp > req && req > tmp->next) { 	req->next=tmp->next; 	tmp->next=req;	 }
  条件2: 折返扫描,req在下一轮扫描的方向上 if(tmp < tmp->next && req > tmp->next) { 	req->next=tmp->next; 	tmp->next=req;	 }
  这里需要阐明的是,Linux-0.11实际使用的磁盘扫描算法是 C-SCAN算法 ,也是 电梯算法 (可戏称为 跳楼机 )。
  其思路就是只 单向寻道 ,到头后 直接复位 再次沿同方向寻道,这样对于所有磁盘位置的请求都是公平的。
  我们通过下面的代码实际感受一下这个过程,我们固定cmd和dev, 只让sector号有区别,依次插入50, 80, 60, 30, 20 ,看看最后的结果如何。 #include  #include    #define READ 0 #define WRITE 1   struct request { 	int dev;		/* -1 if no request */ 	int cmd;		/* READ or WRITE */ 	int errors; 	unsigned long sector; 	unsigned long nr_sectors; 	char * buffer; 	//struct task_struct * waiting; 	//struct buffer_head * bh; 	struct request * next; };   #define IN_ORDER(s1,s2)  	((s1)->cmd<(s2)->cmd || (s1)->cmd==(s2)->cmd &&  	((s1)->dev < (s2)->dev || ((s1)->dev == (s2)->dev &&  	(s1)->sector < (s2)->sector)))   // 作为解析,以明白的分支结构重写一个内容一样的inorder函数 bool inorder(struct request *s1,struct request *s2) { 	if (s1->cmdcmd) 	{ 		return true;//only when s1->cmd = READ; s2->cmd = WRITE; 	} 	else if ( s1->cmd == s2->cmd ) 	{ 		if (s1->dev < s2->dev) 		{ 			return true;// when (s1->cmd==s2->cmd) && (s1->devdev) 		} 		else if ( s1->dev == s2->dev ) 		{ 			if (s1->sectorsector) 			{ 				return true;// when when (s1->cmd==s2->cmd) && (s1->sectorsector) 			} 			return false;// when when (s1->cmd==s2->cmd) && (s1->sector>=s1->sector) 		} 		return false;// when (s1->cmd==s2->cmd) && (s1->dev>s2->dev) 	} 	return false;// when s1->cmd>s2->cmd }   void AddRequest(struct request * &head,struct request *req) { 	if (!head) 	{ 		head = req; 		head->next = 0; 		return ; 	} 	struct request * tmp = head; 	for (;tmp->next;tmp = tmp->next) 	{ 		if ( ( IN_ORDER(tmp,req)|| 			!IN_ORDER(tmp,tmp->next)) && 			IN_ORDER(req,tmp->next)) 		{ 			break; 		} 	} 	req->next = tmp->next; 	tmp->next = req; 	return; }   void PrintQueen(struct request * n) { 	while (n) 	{ 		printf("(%d,%d,%d),",n->cmd,n->dev,n->sector); 		n = n->next; 	} 	printf(" "); } int main(int argc,char ** argv) { 	struct request s1; 	struct request * pHead = 0;     struct request *req = new struct request;     req->cmd = 0;     req->dev =  0;     req->sector =  50;      AddRequest(pHead,req);     PrintQueen(pHead);         struct request *req3 = new struct request;     req3->cmd = 0;     req3->dev =  0;     req3->sector =  80;     AddRequest(pHead,req3);     PrintQueen(pHead);        struct request *req2 = new struct request;     req2->cmd = 0;     req2->dev =  0;     req2->sector =  60;     AddRequest(pHead,req2);     PrintQueen(pHead);        struct request *req5 = new struct request;     req5->cmd = 0;     req5->dev =  0;     req5->sector =  30;     AddRequest(pHead,req5);     PrintQueen(pHead);        struct request *req4 = new struct request;     req4->cmd = 0;     req4->dev =  0;     req4->sector =  20;     AddRequest(pHead,req4);     PrintQueen(pHead);    	return 0; }
  上述代码的执行结果如下所示: (0,0,50), (0,0,50),(0,0,80), (0,0,50),(0,0,60),(0,0,80), (0,0,50),(0,0,60),(0,0,80),(0,0,30), (0,0,50),(0,0,60),(0,0,80),(0,0,20),(0,0,30),
  可以看出最后的顺序是50->60->80->20->30, 实际上效果就是单方向移动到最后一个位置,再复位进行扫描,再次沿同方向扫描。
  c-san算法示意图
  make_requeststatic void make_request(int major,int rw, struct buffer_head * bh)
  该函数的作用是创建请求项并插入请求队列中。
  首先判断命令是否READA或者是WRITEA。READA代表预读取,WRITEA代表预写入。所以当命令是 预读取 或者是 预写入 ,如果bh块被锁,那么就放弃,直接返回。如果bh块没有被锁,那么就当作普通的READ和WRITE。 	struct request * req; 	int rw_ahead;  /* WRITEA/READA is special case - it is not really needed, so if the */ /* buffer is locked, we just forget about it, else it"s a normal read */ 	if ((rw_ahead = (rw == READA || rw == WRITEA))) { 		if (bh->b_lock) 			return; 		if (rw == READA) 			rw = READ; 		else 			rw = WRITE; 	}
  如果命令不是读或者写,那么就是一个致命错误,直接通过panic抛出错误。对命令校验之后,就去锁定该数据块。如果命令是写操作,但是该数据块并没有脏数据,则没有必要去写块设备,就可以对bh块进行解锁。除此以外,如果命令是读操作,但是该bh块中的内容已经是最新的,也没有必要去读块设备,就可以对bh块进行解锁。 if (rw!=READ && rw!=WRITE)     panic("Bad block dev command, must be R/W/RA/WA"); lock_buffer(bh); if ((rw == WRITE && !bh->b_dirt) || (rw == READ && bh->b_uptodate)) {     unlock_buffer(bh);     return; }
  下面需要从request数组中寻找一个位置来创建该请求。对于读请求而言,将会从数组的尾部开始搜索。对于写请求而言,将会从数组的2/3处开始搜索。 如果找到了位置,那么就开始进行创建,如果没有找到位置,就sleep_on进行等待。 	if (rw == READ) 		req = request+NR_REQUEST; 	else 		req = request+((NR_REQUEST*2)/3); /* find an empty request */ 	while (--req >= request) 		if (req->dev<0) 			break; /* if none found, sleep on new requests: check for rw_ahead */ 	if (req < request) { 		if (rw_ahead) { 			unlock_buffer(bh); 			return; 		} 		sleep_on(&wait_for_request); 		goto repeat; 	}
  当找到该位置时,就在该位置上进行构建请求。构建完之后,调用add_request插入到电梯队列中。 /* fill up the request-info, and add it to the queue */ 	req->dev = bh->b_dev; 	req->cmd = rw; 	req->errors=0; 	req->sector = bh->b_blocknr<<1; 	req->nr_sectors = 2; 	req->buffer = bh->b_data; 	req->waiting = NULL; 	req->bh = bh; 	req->next = NULL; 	add_request(major+blk_dev,req);ll_rw_blockvoid ll_rw_block(int rw, struct buffer_head * bh)
  该函数的作用就是读写数据块。
  下面一段代码用于对bh块对应的设备做相应的校验。如果主设备号不存在,或者该设备对应的请求操作函数不存在,就显示出错信息。 if ((major=MAJOR(bh->b_dev)) >= NR_BLK_DEV || !(blk_dev[major].request_fn)) {     printk("Trying to read nonexistent block-device r");     return; }
  如果校验没有问题就调用make_request建立块设备读写请求。 make_request(major,rw,bh);blk_dev_initvoid blk_dev_init(void)
  该函数的作用是 初始化块设备 。
  遍历request数组,对request数组中每一项的dev设置为-1, 对next指针设置为NULL。 for (i=0 ; ib_lock)//如果缓冲区已被锁定就睡眠,一直到缓冲区解锁     sleep_on(&bh->b_wait); bh->b_lock=1;//立即锁定缓冲区 sti();//开中断unlock_bufferstatic inline void unlock_buffer(struct buffer_head * bh)
  该函数的作用是解锁指定的缓冲块。 if (!bh->b_lock)//如果该缓冲区没有加锁,则打印出错信息     printk("ll_rw_block.c: buffer not locked r"); bh->b_lock = 0;//对缓冲区解锁 wake_up(&bh->b_wait);//唤醒等待该缓冲区的任务。

巴西队吃下定心丸!主帅确认内马尔伤情无大碍,将继续参加世界杯在北京时间11月25日凌晨结束的一场卡塔尔世界杯小组赛中,巴西队凭借里沙利松的两粒进球20击败塞尔维亚队,取得开门红。不过,巴西队头号球星内马尔在比赛中因伤离场,却让巴西球迷的心瞬贺建奎出狱7个月新实验室落户北京,从事罕见遗传病基因治疗衡宇鱼羊发自凹非寺量子位公众号QbitAI基因编辑狂人贺建奎,复出成立新实验室!他在个人微博发布实验室落户北京的最新消息实验室,北京大兴,新起点,新征程!2019年底,因基因编辑案14岁初中生被清华录取,本硕博连读,数学好的人,能有多吃香?还没到中考季,14岁的初三学生官子钦就已经接到清华大学的通知书,无需参加中考高考,明年2月份直接到清华读大学,本硕博八年连读。同龄人还在为明年的中考做准备,而官同学已经准备开启大学孕期中,千万别忽视这5个注意事项和禁忌,对准妈妈和宝宝都好孕早期,是胎儿成型最重要的时期,盲目忌口只会导致胎儿所需营养不足,但是肆无忌惮的进补,也同样会影响胎儿发育,接下来这5点对胎儿的健康十分重要,妈妈拿起小本本记好了接触有害物质怀孕初孕妇怀孕4个月坐公交车,被老人抢座位,一起身全车人冒冷汗现在的职场女性们,即使怀孕了,也依然坚持上班,她们往往舍不得自己的事业,怕怀孕生娃一旦放弃了工作,就会与社会脱节,所以,即使再难再累,依然继续工作。小陈就是一位职场女性,由于家里经垮掉的信任如何再次建立?人与人之间的交流或是彼此的认知都基于信任,你信任一个人才可能同这个人去交流深层次的东西又或是进一步合作。孩子基于对父母的信任所以在孩提时代无论大事小情都会说给爸爸妈妈听,所以这个时孕期水肿异常!这样预防可以避免流产在怀孕期间,大约有一半的孕妇会出现浮肿现象,特别是在28周以后,增大到一定程度,长大的胎儿压迫妈妈腹股沟处的大静脉。静脉回流不好的话,妈妈就很容易出现下肢浮肿。随着个月份的逐渐增大妈妈,我们的世界怎么了?妈妈,我们的世界怎么了?被小魔女突然一问,我当时怔住了,竟不知怎么回答,想着小小年纪的你怎么会这么问呢,小脑袋瓜里究竟想着什么呢?在她的心里,世界是什么?世界究竟有多大呢?(图片非吃饭可不是小事,5招1汤助你胃气足,吃得好胃病素有三分治,七分养的说法,养胃气预防调理才是首选之策,若在生活中避免上述不良生活方式,改善不良习惯,再加上药膳调理,不但胃病不会找上门,一些较轻的胃病患者也能自行痊愈。饮食规律浅谈食物对风热型感冒的影响中医认为,风热感冒是感受风热之邪所致的表证,诸病源候论风热候风热病者,风热之气,先从皮毛入于肺也。肺为五脏上盖,候身之皮毛,若服腠虚,则风热之气,先伤皮毛,乃入肺也。其状使人恶风寒前列腺增生肥大?简单五味药,拯救男人的生命腺前列腺增生症是男性老年人常见病,属于中医癃闭症的范畴。主要症状为尿频滴沥不尽,或少腹胀急出现尿潴留,或滴沥失禁。关于前列腺增生症的发病原因,西医认为是由于内分泌失调引起腺体肥大,压
今年五十大寿的8位女星,陈慧琳近照美翻天,张惠妹胖到150斤女明星们都是出了名的会保养,即使已经到了50岁,还依然有人美得惊心动魄。今年这8位女星过五十大寿,陈慧琳美到让人不敢相信是50岁,而张惠妹体重到达150斤,胖若两人。1陈慧琳近日,港姐郭羡妮当红下嫁农村小伙,11年后才知道她的选择有多明智知名演员郭羡妮,在影视剧中多以清晰脱俗的古装美人形象视人,她稳重从容,不争香斗艳随大流。曾出演过寻秦记帝女花牛郎织女争霸传奇等电视剧,相比较于演戏,她在选美方面的成绩更是让人望尘莫王新军亲情有泪水,对不起唐静,此生不会辜负小7岁妻子秦海璐妻子的浪漫旅行中,王新军把秦海璐宠成了手心宝。每天早上贴心的为她准备早餐,温柔的叫她起床,抱着她去吃饭,两人去游玩时暗自为秦海璐准备舒适的运动鞋两人的甜蜜日常让人艳羡不已。不少人都金鸡奖红毯关晓彤翻车,佟丽娅干瘪,柳岩性感,倪妮生图赢麻了每年的红毯都成了大型比美现场,今年也不例外根据不完全统计的是这一次亮相红毯的嘉宾就有数百位女星,用周迅的话说就是好多人!当天红毯现场嘉宾云集,自然是看点多多,跟着小编的脚步来看看吧突然官宣离婚!巨星夫妇恩爱13年没出轨没家暴,真实原因令人唏嘘上来先说个八卦。咱国外有一个姐姐,是挺优秀的职业模特,贼能赚那种!但她后来碰到一个男的,天雷勾动地火的爱上了。不仅接受了他和前女友生的娃,又给他生了一儿一女(当然她本身也非常爱孩子有一种穷叫童年滤镜,刘星一条泳裤250,小雪电话费就1300元有人说我踩过最大的坑,就是导演挖的坑!2005年,一部家有儿女火遍全国。打开电视耳边就充斥着那一首你的童年,我的童年,好像都一样剧中,一家人乐呵呵地坐在一起聊天吃饭,生活中的小趣事65岁元彪新片差评不断,首日票房仅140万,成龙的话又应验了01。hr棺山古墓,元彪新片!提到元彪,大家应该都很熟悉吧,作为七小福的成员,在出道55年的时间里,他参演的影视剧没有一百部,也有七八十部,大家耳熟能详的有快餐车夏日福星黄飞鸿孔雀湖南卫视小花格局变了,2人争当一姐,2人迅速上位,1人被边缘化尽管湖南卫视一直以来争议不少,不可否认其在综艺领域确实高人一筹,另外从来不缺少优秀的主持人。男主持方面,何炅和汪涵两位一哥宝刀不老。新生代的齐思钧连续主持了浪姐3和披哥2,已经可以郎朗携妻子国外办豪华私人晚宴,状态被嘲如蜡像,吉娜衣品遭嘲讽饿了吗?戳右边关注我们,每天给您送上最新出炉的娱乐硬核大餐!11月13日,有网友在社交平台上晒出郎朗在国外举办私人晚宴的照片,吉娜现身其中,两人的状态引起大家的关注与热议。该网友透曝王岳伦偷偷借住李湘豪宅被赶走?房子是王诗龄名下,网友活该啃上不足啃下有余,王岳伦自从离婚后,可以说举步维艰。近期,网上传出爆料,借小棉袄之手,王岳伦暂住李湘的豪宅,却直接被物业赶了出来。此消息一出,瞬间引发了粉丝们的热议,不少人认为,王湖南盛产美人,8位湘籍女星,亭亭玉立,甩白幼瘦网红几条街中兴将相,什九湖湘半部中国近代史由湘人写就这话绝不是夸张的。从晚清七十年间起,就出现了百位卓然命世的英雄豪杰曾国藩,左宗棠,魏源,谭嗣同,黄兴,蔡锷,宋教仁。。经世致用实事求是百折