Deadline算法维护5个队列,除了请求队列以外,算法还使用了四个队列。其中两个排序队列分别包含读请求和写请求,这个队列是按照起始扇区数来排序的。另外两个最后期限队列包含相同的读和写请求,只不过它们是根据其“最后期限”排序的。这两个队列的目的是为了避免请求饿死。因为电梯策略优先处理与上一个处理请求最近的请求,因而就会对摸个请求忽略很长一段时间,这时就会发生这个情况。请求的最后期限本质上就是超时定时器,当请求被传给电梯算法是开始计时。缺省情况下,Deadline算法读请求的超时时间为500ms,而写请求的超时时间为5s。也就是说,Deadline算法读请求优先于写请求,因为读请求通常阻塞发出请求的进程。而最后期限保证了调度程序照顾等待很长一段时间的那个请求,即使它位于排序队列的末尾。
Deadline算法核心数据结构如下:
struct deadline_data {
/*
* run time data
*/
/*
* requests (deadline_rq s) are present on both sort_list and fifo_list
*/
struct rb_root sort_list[2];
struct list_head fifo_list[2];
/*
* next in sort order. read, write or both are NULL
*/
struct request *next_rq[2];
unsigned int batching; /* number of sequential requests made */
sector_t last_sector; /* head position */
unsigned int starved; /* times reads have starved writes */
/*
* settings that change how the i/o scheduler behaves
*/
int fifo_expire[2];
int fifo_batch;
int writes_starved;
int front_merges;
};
sort_list:按照request中的sector号大小,把每个request组织在以sort_list为根的红黑树中。这样方便快速查找。总共有读写两棵树。
fifo_list:按照超时先后顺寻,把request链入filo_list,同样也是分为读写两个队列。
因此,任何一个request,在未提交给设备的请求队列之前,都会同时存在于以上两个结构中。
next_rq:指向sort_list中的下一个请求。
batching:调度算法可能连续提交多个请求,batching用于记录当前连续提交的request数目。当batching < fifo_batch,都可以继续进行连续提交。
starved:提交读request而造成写饥饿的次数。如果starved超过writes_starved,则需要提交写request,从而避免写饥饿。