Linux IO SchedulerCFQ2Word文件下载.docx

上传人:b****1 文档编号:4768550 上传时间:2023-05-04 格式:DOCX 页数:25 大小:25.73KB
下载 相关 举报
Linux IO SchedulerCFQ2Word文件下载.docx_第1页
第1页 / 共25页
Linux IO SchedulerCFQ2Word文件下载.docx_第2页
第2页 / 共25页
Linux IO SchedulerCFQ2Word文件下载.docx_第3页
第3页 / 共25页
Linux IO SchedulerCFQ2Word文件下载.docx_第4页
第4页 / 共25页
Linux IO SchedulerCFQ2Word文件下载.docx_第5页
第5页 / 共25页
Linux IO SchedulerCFQ2Word文件下载.docx_第6页
第6页 / 共25页
Linux IO SchedulerCFQ2Word文件下载.docx_第7页
第7页 / 共25页
Linux IO SchedulerCFQ2Word文件下载.docx_第8页
第8页 / 共25页
Linux IO SchedulerCFQ2Word文件下载.docx_第9页
第9页 / 共25页
Linux IO SchedulerCFQ2Word文件下载.docx_第10页
第10页 / 共25页
Linux IO SchedulerCFQ2Word文件下载.docx_第11页
第11页 / 共25页
Linux IO SchedulerCFQ2Word文件下载.docx_第12页
第12页 / 共25页
Linux IO SchedulerCFQ2Word文件下载.docx_第13页
第13页 / 共25页
Linux IO SchedulerCFQ2Word文件下载.docx_第14页
第14页 / 共25页
Linux IO SchedulerCFQ2Word文件下载.docx_第15页
第15页 / 共25页
Linux IO SchedulerCFQ2Word文件下载.docx_第16页
第16页 / 共25页
Linux IO SchedulerCFQ2Word文件下载.docx_第17页
第17页 / 共25页
Linux IO SchedulerCFQ2Word文件下载.docx_第18页
第18页 / 共25页
Linux IO SchedulerCFQ2Word文件下载.docx_第19页
第19页 / 共25页
Linux IO SchedulerCFQ2Word文件下载.docx_第20页
第20页 / 共25页
亲,该文档总共25页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

Linux IO SchedulerCFQ2Word文件下载.docx

《Linux IO SchedulerCFQ2Word文件下载.docx》由会员分享,可在线阅读,更多相关《Linux IO SchedulerCFQ2Word文件下载.docx(25页珍藏版)》请在冰点文库上搜索。

Linux IO SchedulerCFQ2Word文件下载.docx

cfq_activate_request, 

10. 

.elevator_deactivate_req_fn 

cfq_deactivate_request, 

11. 

.elevator_queue_empty_fn 

cfq_queue_empty, 

12. 

.elevator_completed_req_fn 

cfq_completed_request, 

13. 

.elevator_former_req_fn 

elv_rb_former_request, 

14. 

.elevator_latter_req_fn 

elv_rb_latter_request, 

15. 

.elevator_set_req_fn 

cfq_set_request, 

16. 

.elevator_put_req_fn 

cfq_put_request, 

17. 

.elevator_may_queue_fn 

cfq_may_queue, 

18. 

.elevator_init_fn 

cfq_init_queue, 

19. 

.elevator_exit_fn 

cfq_exit_queue, 

20. 

.trim 

cfq_free_io_context, 

21. 

}, 

22. 

.elevator_attrs 

cfq_attrs, 

23. 

.elevator_name 

"

cfq"

 

24. 

.elevator_owner 

THIS_MODULE, 

25.};

可以看到CFQ调度器涉及到的操作函数还是比较多的,这里我只打算选一些和提交bio以及request相关的函数进行分析。

在提交bio的时候,如果在通用层寻找可以合并bio的途径失败,要通过cfq_merge()来判断是否能够将bio插入到某个request的bio链表首部

request 

2.cfq_find_rq_fmerge(struct 

cfq_data 

*cfqd, 

bio 

*bio) 

3.{ 

task_struct 

*tsk 

current;

cfq_io_context 

*cic;

cfq_queue 

*cfqq;

//在进程的io_context中,找到进程特定于块设备的cfq_io_context 

cic 

cfq_cic_lookup(cfqd, 

tsk->

io_context);

if 

(!

cic) 

return 

NULL;

//根据同步还是异步,确定cfq_queue 

cfqq 

cic_to_cfqq(cic, 

cfq_bio_sync(bio));

(cfqq) 

sector_t 

sector 

bio->

bi_sector 

bio_sectors(bio);

//得到末尾扇区号 

//从cfq_queue的红黑树中查找对应的节点 

elv_rb_find(&

cfqq->

sort_list, 

sector);

23.} 

cfq_find_rq_fmerge()进行实际的搜索工作,要确定bio的归属request,必须先确定进程的通信对象是谁(因为一个进程有可能和多个块设备通信),也就是要找到进程对应的cfq_io_context结构,其中包含了进程的同步请求队列和异步请求队列的地址,只要找到了相应的cfq_io_context,就可以通过bio的同异步性确定对应的cfq_queue了,最后再判断对应的cfq_queue中是否存在可以容纳bio的request。

推导cfq_io_context的关键在于以块设备CFQ调度器的描述结构cfq_data的地址为关键值,在进程的io_context的基数树中进行搜索

[html] 

1.<

span 

style="

font-size:

12px;

>

static 

24.<

/span>

通过基数树寻找对应设备的cfq_io_context:

2.cfq_cic_lookup(struct 

io_context 

*ioc) 

unsigned 

long 

flags;

void 

*k;

(unlikely(!

ioc)) 

rcu_read_lock();

/* 

we 

maintain 

last-hit 

cache, 

to 

avoid 

browsing 

over 

the 

tree 

*/ 

//由于进程很有可能连续访问同一块设备,因此先将cic中的关键值直接与cfqd比较 

rcu_dereference(ioc->

ioc_data);

(cic 

&

cic->

key 

== 

cfqd) 

rcu_read_unlock();

cic;

do 

{//在进程io_context的基数树中寻找对应访问的块设备的cfq_data结构 

25. 

radix_tree_lookup(&

ioc->

radix_root, 

(unsigned 

long) 

cfqd);

26. 

27. 

28. 

break;

29. 

->

must 

be 

copied 

race 

with 

cfq_exit_queue() 

30. 

key;

31. 

k)) 

32. 

cfq_drop_dead_cic(cfqd, 

ioc, 

cic);

33. 

34. 

continue;

35. 

36. 

37. 

//保存cic到ioc->

ioc_data 

38. 

spin_lock_irqsave(&

lock, 

flags);

39. 

rcu_assign_pointer(ioc->

ioc_data, 

40. 

spin_unlock_irqrestore(&

41. 

42. 

while 

(1);

43. 

44. 

45.}<

在通用层__make_request()函数中,如果bio找不到接收对象,那么就要重新创建一个request来接收它。

分配一个request必须进行初始化,需要调用cfq_set_request()函数。

和前面的过程比较类似的是,request要先找到接收它的cfq_queue,然后这里出现了一个问题,如果这个request是进程的第一个同步请求或者异步请求,那么就要分配新的cfq_queue来接收request。

同步请求和异步请求的处理情况有点区别,因为进程独自拥有自己的同步请求队列,而进程的异步请求都是共享cfq_data中的异步请求队列的,所以只有当request是同步请求时才需要进行cfq_queue的分配

int 

2.cfq_set_request(struct 

request_queue 

*q, 

*rq, 

gfp_t 

gfp_mask) 

*cfqd 

q->

elevator->

elevator_data;

const 

rw 

rq_data_dir(rq);

bool 

is_sync 

rq_is_sync(rq);

might_sleep_if(gfp_mask 

__GFP_WAIT);

//获取进程特定于块设备的cfq_io_context结构 

cfq_get_io_context(cfqd, 

gfp_mask);

spin_lock_irqsave(q->

queue_lock, 

goto 

queue_fail;

21.new_queue:

is_sync);

//根据同异步情况,获取进程中对应的cfq_queue 

|| 

cfqd->

oom_cfqq) 

{//如果还没有相应的cfqq则进行分配 

cfq_get_queue(cfqd, 

is_sync, 

//分配cfq_queue 

cic_set_cfqq(cic, 

cfqq, 

//设置cic->

cfqq[is_sync] 

else 

If 

queue 

was 

seeky 

for 

too 

long, 

break 

it 

apart. 

(cfq_cfqq_coop(cfqq) 

should_split_cfqq(cfqq)) 

cfq_log_cfqq(cfqd, 

breaking 

apart 

cfqq"

);

split_cfqq(cic, 

cfqq);

cfqq) 

new_queue;

Check 

see 

this 

is 

scheduled 

merge 

another, 

closely 

cooperating 

queue. 

The 

merging 

of 

queues 

happens 

here 

as 

done 

in 

process 

context. 

reference 

on 

new_cfqq 

taken 

merge_cfqqs. 

(cfqq->

new_cfqq) 

cfq_merge_cfqqs(cfqd, 

cic, 

45. 

46. 

47. 

allocated[rw]++;

48. 

atomic_inc(&

ref);

49. 

50. 

spin_unlock_irqrestore(q->

51. 

52. 

rq->

elevator_private 

//保存cfq_io_context到request 

53. 

elevator_private2 

cfqq;

//保存cfq_queue到request 

54. 

0;

55. 

56.queue_fail:

57. 

(cic) 

58. 

put_io_context(cic->

ioc);

59. 

60. 

cfq_schedule_dispatch(cfqd);

61. 

62. 

cfq_log(cfqd, 

set_request 

fail"

63. 

1;

64.} 

当一个request创建初始化,就要将其插入到相应的队列中,cfq_insert_request()函数完成这个功能,和deadline调度器相似,request会被放入两个队列里,一个是按照起始扇区号排列的红黑树(sort_list),一个是按响应期限排列的链表(fifo)

cfq_insert_request(struct 

*rq) 

2.{ 

*cfqq 

RQ_CFQQ(rq);

insert_request"

cfq_init_prio_data(cfqq, 

RQ_CIC(rq)->

//根据ioc设定cfq_queue的优先级类和优先级 

cfq_add_rq_rb(rq);

//将rq添加到cfq_queue的红黑树 

//设置期限值 

rq_set_fifo_time(rq, 

jiffies 

cfq_fifo_expire[rq_is_sync(rq)]);

list_add_tail(&

queuelist, 

fifo);

//添加至fifo 

cfq_rq_enqueued(cfqd, 

rq);

16.} 

当一个request纳入一个新的bio后,要考虑能否和其他request进行合并,假如是将bio插入到链表的末尾,那么就要在sort_list中获取request后面的一个request(通过函数elv_rb_latter_request()来获取),然后判断前者的结束扇区和前者的起始扇区是否一样,这些工作都是再通用层代码中完成的,当两个request通过了通用层的审核和,并完成合并操作后,将调用cfq_merged_requests进行一些针对队列的额外工作

1.tatic 

2.cfq_merged_requests(struct 

*next) 

4.{ 

reposition 

fifo 

next 

older 

than 

rq 

list_empty(&

queuelist) 

!

next->

time_before(rq_fifo_time(next), 

rq_fifo_time(rq))) 

list_move(&

queuelist);

rq_fifo_time(next));

cfq_remove_request(next);

15.} 

这里主要是考察两个request的期限,因为合并时都是将后者合并入前者,因此当后者的期限时间小于前者时,要进行相应的调整,这一点和deadline调度器是一样的。

最后分析的依然是每个调度器最重要的函数--elevator_dispatch_fn

CFQ调度器在发送request到底层块设备时的流程大致如下:

1.选择一个cfq_queue

2.从cfq_queue中选择一个request进行发送

选择cfq_queue的思路如下:

1.如果当前的cfq_queue的时间片还没用完,则继续当前的cfq_queue

2.如果当前的cfq_queue的时间片消耗完了,则优先在对应的prio_tree中选择一个cfq_queue,该cfq_queue的第一个访问扇区与整个调度器最后处理的扇区之间的差值必须小于一个阈值,如果OK的话就选择这个cfq_queue

3.如果找不到这样的cfq_queue,再从service_tree中调度其他的cfq_queue

cfq_dispatch_requests(struct 

force) 

elevat

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 人文社科 > 法律资料

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2