块设备
来源:互联网 发布:office 2013 mac 编辑:程序博客网 时间:2024/04/28 16:46
一 。注册模块
1。注册 register_blkdev(major,name,struct block_device_operation *p);
2.初始化队列:
多队列 blk_init_queue(request_queue_t *,request_fn);
blk_dev[major]=sbull_find_queue;
无队列 blk_queue_make_request(BLK_DEFAULT_QUEUE(major),sbull_make_request);
单队列 blk_init_queue(BLK_DEFAULT_QUEUE(major),sbull_request);
3.注册分区设备 register_disk(NULL,MKDEV(major,i),1,&sbull_bdops,sbull_size<<1);
二 。结构
struct block_device_operation sbull_bdops={
open: sbull_open,
release: sbull_release,
ioctl: sbull_ioctl,
check_media_change: sbull_check_change,
revalidate: sbull_revalidate,
};
在linux/blk.h (MAJOR_NR,CURRENT等macro变量);linux/blkdev.h(blk_dev[MAX],blk_size, blksize_size,request_queue_t等结构申明);在drivers/block/ll_rw_blk.c(包含 blk_init_queue等函数的实现);
三 请求处理函数
sbull_request(request_queue_t *p);
四 支持常用的对快设备操作的命令
fdisk mount mkfs
例如 mount 的过程 1。open设备;2。调用request处理方法,传输数据块。
五 可分区设备
1。在driver/block/genhd.c中的struct gendisk *gendisk_head 为static 所以虽然在linux/genhd.h中申明为extern struct gendisk *gendisk_head ;但在我们的程式中还是出现unresolved symbol ,所以在我们的程式中还得申明一下struct gendisk *gendisk_head 。
2。申明一个struct gendisk spull_gendisk 并初始化各成员。
3。在revalidate函数中重新调用register_disk(struct gendisk *gd,int driver,unsigned minors,struct block_device_operation *ops,long size)注册分区。
4。模块注册过程和sbull相同。
5. 中断处理过程,在请求处理函数中启动定时器,然后在定时器函数中end_request(1);
普通的请求处理函数是在本函数中直接调用end_request(1)的。
假如驱动程式是中断驱动的,request 函数应该提交一次数据传输并立即返回,而无需调用 end_request。但是,在没有调用 end_request(或其组成部分)之前,不会认为请求已 完成。因此,在设备告诉驱动程式已完成数据传输时,顶半或底半中断处理程式需要调用 end_request。
请求队列
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) /
i< ((bio)->bi_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);
- 块设备
- 块设备
- 块设备
- 块设备
- 块设备
- 块设备--块设备文件系统
- 块设备 字符设备
- 字符设备 块设备
- 块设备、字符设备
- 块设备--块设备的架构
- 块设备--块设备的打开流程
- linux 块设备,字符设备
- 块设备和字符设备
- 字符设备和块设备
- 字符设备与块设备
- 块设备与字符设备
- 字符设备与块设备
- 符设备与块设备
- .NET OracleLob 读写操作
- SQLServer 2005中Sa用户可以登录进去,Windows管理员却无法登陆进去
- 高端人才必看,生意人必读!
- 自动化测试 - RFT系列教程9:最复杂的控件:TABLE(二) 表格的行数是不确定的
- ifconfig 源码分析
- 块设备
- VC如何获取QQ好友发来的信息
- 中嵌协会举办第一期“嵌入式与物联网”主题论坛
- Oracle 10g Exception: ORA-12638 Solution
- 系统服务_时间同步服务器
- mysql 中文乱码
- 关于vc调试出现One or more breakpoints cannot be set and have been disabled解决方法
- jQuery分页插件(jQuery Pagination)
- org.apache.catalina.core.StandardContext filterStart 严重: Exception starting filter Acegi Filter Chain Proxy