- 论坛徽章:
- 0
|
请求队列
struct request_queue
{
....
spinlock_t __queue_lock;
spinlock_t *queue_lock;
struct kobject kobj;
unsigned long nr_requests; //max req
unsigned int nr_congestion_on;
unsigned int nr_congestion_off;
unsigned int nr_batching;
unsigned short max_sectors ;
unsigned short max_hw_sectors;
unsigned short max_phys_segments;
unsigned short max_hw_segment;
unsigned short hardsect_size;
unsigned int max_segment_size;
unsigned long seg_boundary_mask;
unsigned dma_alignment;
struct blk_queue_tag *queue_tags;
atomic_t refcnt;
unsigned int sg_timeout;
unsigned int sg_reserved_size;
int node;
struct list_head drain_list;
struct request *flush_rq;
unsigned char ordered;
}
请求队列跟踪等候的块请求。
4个IO调度器:
No-op 基本的合并和排序
Anticipatory 默认,但复杂,且不适合 数据库
Deadline 精简上一个
CFQ Scheduler 为系统内所有任务分配相同带宽,适合桌面。
可以个kernel 添加参数 elevator= deadline 选取IO调度算法。
=======================================================
初始化请求队列
request_queue_t *blk_init_queue(request_fn_proc *rfn, spinlock_t lock);
第一个参数为请求处理函数的指针,第二个为控制访问队列的自旋锁,注意检查返回值
void blk_cleanup_queue(request_queue_t *q); blk_put_queue;
分配
request_queue_t * blk_alloc_queue(int gfp_mask);
void blk_queue_make_request(request_queue_t *q, make_request_fn *mfn);
提取请求
struct request *elv_next_request(request_queue_t *queue);
上述函数返回下一个要处理的请求。
去除请求
struct request *elv_dequeue_request(struct request *req);
struct request *elv_requeue_request(request_queue_t *queue,struct request *req);
启动停止请求队列
void blk_stop_queue(request_queue_t *queue);
void blk_start_queue(request_queue_t *queue);
参数设置
void blk_queue_max_sectors(request_queue_t *queue, unsigned short max);
任一请求可包含的最大扇区数
void blk_queue_max_phys_segments(request_queue_t *queue, unsigned short max);
可包含的物理段(内存不相连)128
void blk_queue_max_hw_segments(request_queue_t *queue, unsigned short max);
考虑系统IO内存管理单元的重映射 128
void blk_queue_max_segment_size(request_queue_t *queue, unsigned short max);
段最大字节数 65536
通告内核
void blk_queue_bounce_limit(request_queue_t *queue, u64 dma_addr);
告知内核块设备执行DMA时可使用最高物理地址dma_addr
BLK_BOUNCE_HIGH(对高端内存使用反弹缓冲)默认
BLK_BOUNCE_ISA 16M得ISA区DMA
BLK_BOUNCE_ANY 可在任何地方DMA
blk_queue_segment_boundary(request_t *queue, unsigned long mask);
如果设备无法跨越一个特殊大小的内存边界, 应该使用这个函数告知内核这个边界。
void blk_queue_dma_alignment(request_queue_t *queue, int mask) 缺省0x1ff
告知内核块设备施加于DMA传送的堆存对齐限制,所有请求都匹配这个对齐
void blk_queue_hardsect_size(request_queue_t *queue,unsigned short max);
告知内核块设备的硬件扇区大小,则产生的请求都是大小的整数倍,且对齐 512
===========================================================================
通常一个bio对应一个IO请求
struct bio
{
sector_t bi_sector;//要传送的第一个扇区
struct bio *bi_next;
struct block_device *bi_bdev;
unsigned long bi_flags;//状态命令
usnigned long bi_rw//地位RW,高位优先级
unsigned short bi_vcnt;//biovec 数量
unsigned short bi_idx;//当前bio_vec索引
unsigned short bi_phys_segments;//不相连的物理段数
unsigned short bi_hw_segments;
unsigned int bi_size;
unsigned int bi_hw_front_size;
unsigned int bi_hw_back_size;
unsigned int bi_max_vecs;//能持有最大 bvl_vecs
struct bio_vec *bio_io_vec;
bio_end_io_t *bi_end_io;
atomic bi_cnt;
void *bi_private;
bio_destructor_t *bio_destructor;
};
struct bio_vec
{struct page *bv_page;//页指针
unsigned int bv_len;//传送的字节数
unsigned int bv_offset;//偏移位置
}
应该使用bio_for_each_segment()宏来便利 bio
#define __bio_for_each_segment(bvl,bio,i,start_idx) \
for(bvl=bio_iovec_idx((bio),(start_idx)), i=(start_idx) \
ibi_vcnt; \
bvl++,i++)
#define bio_for_each_segment(bvl, bio,i) \
__bio_for_each_segment(bvl, bio, i, (bio)->bi_idx)
内核提供的函数用于bio:
int bio_data_dir(struct bio *bio);数据传送方向READ WRITE
struct page * bio_page(struct bio *bio);目前页指针
int bio_offset(struct bio *bio); 页偏移
int bio_cur_sectors(struct bio *bio); 要传送的扇区数目
char *bio_data(struct bio *bio);数据缓冲的内核虚拟地址
char *bvec_kmap_irq(struct bio *bio,unsigned long flags); 可用于存取被
给定的 bio_vec入口指向的数据缓冲区,会屏蔽中断并返回原子kamp,调用前,不该睡眠
char *bvec_kunmap_irq(char *buffer,unsigned long flags); 撤销
char * bio_kamp_irq(struct bio *bio,unsigned long flags)
返回给定BIO的当前bio_vec入口地址映射
char * __bio_kmap_atomic (struct bio *bio, int i, enum km_type type)
返回给定BIO的第i个缓冲区的虚拟地址
char * __bio_kmunap_atomic (char *addr, enum km_type type)
void bio_get
void bio_put
===============
块设备注册
int register_blkdev(unsigned int major, const char *name);0
分配主设备号/proc/devices创建入口
int unregister_blkdev(unsigned int major, const char *name);
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/69624/showart_1070271.html |
|