block device ---块设备IO

块设备与卷管理:

block device  层:

linux块设备层非常灵活,支持的特性有:
可插拨的IO调度(Pluggable I/O schedulers)
I/O优先级(需IO调度器支持)
磁盘请求重映射(device Mapper)
RAID
各种技巧(multipath多路径,fault injection故障注入)
I/O跟踪(blktrace)

struct bio{
sector_tbi_sector;//开始扇区号
bi_size; // IO大小
struct bio *bi_next; /* 队列链表 */
struct block_device*bi_bdev; // 目标块设备
unsigned long bi_flags; // IO标志,status, command, etc 
unsigned long bi_rw; //低位为读写标志与高位优先级
struct bio_vec *bi_io_vec; //sg内存数组
unsigned shortbi_vcnt;/*数组大小*/
unsigned shortbi_idx;/* 数组当前索引 */
bio_end_io_t *bi_end_io; //IO完成函数
......
}
bio使用:
分配BIO: bio_alloc()
填充必要的域
初始分bio vector
填充I/O完成回调函数
调用:submit_bio()/generic_make_request()
(老的接口):
submit_bh();提交一个单buffer_head(缓存区)I/O;
ll_rw_block();提交多buffer_head I/O;

请求request:
代表一个磁盘设备的请求
包含一个bio的sg链表
被low-level低层I/O处理(I/O调度器,磁盘驱动)
Documentation/block/request.txt
 

 I/O调度:

 I/O调度器决定when and which 磁盘队列请求发送给磁盘
 调度策略能在运行时切换(/sys/block/DEVICE/queue/scheduler)
 调度器必面在最大限度的提高吞吐量与饥饿的请求之间平衡
 当前有四种调度策略:
Noop:只合并,不排队,适合没有寻道时间的设备(如:flash)
CFQ: 完全公平队列,基于优先级,(支持I/O优先级),适合桌面产品。
Deadline:最后期限调度,给每一个请求分配一个期限,期限到时放入高优先级队列,适合服务器
Anticipatory:保留I/O一段时间,以期待会有连续的I/O到来。有些情况适合(其它不适合)


block device ---块设备IO_第1张图片

I/O调度框架:

block device ---块设备IO_第2张图片

struct elevator_type{
struct kmem_cache *icq_cache;
struct elevator_ops ops;//调度器策略实现
size_t icq_size;/* see iocontext.h */
size_t icq_align;/* ditto */
struct elv_fs_entry *elevator_attrs;
char elevator_name[ELV_NAME_MAX];
struct module *elevator_owner;
char icq_cache_name[ELV_NAME_MAX + 5];/* elvname + "_io_cq" */
struct list_head list;
}
此结构实现了调度策略:获取下一个请求,合并,等。
I/O优先级:当前只有CFQ支持优先级,可以用ionice工具设置优先级。
优先级:有3类(realtime,best effort,idle),best effort有8种优先级。
相关函数:
elv_queue_empty();   检查请求队列是否为空
elv_merge(); 从请求队列中找到一个请求与BIO合并
elv_add_request(); 添加一个新请求到请求队列
elv_may_queue(); 新请求是否可以进队
elv_remove_request();从请求队列中删除一个请求
elv_next_request(); 低层调用,从请求队列中获取下一下请求
elv_completed_request(); 请求完成
elv_set_request(); 分配新请求后,设置相关变量
elv_put_request(); 请求释放后,释放调度器相关内存

I/O请求跟踪:blktrace
能在不同的层次(跟踪I/O事性,跟踪请求队列)跟踪块请求,
跟踪的事情有:插入到队列,合并,提交到设备,完成,分割,重新进队,等。

logical volume manager:Device mapper

卷管理功能使用generic device mapper框架实现。
Device mapper提供了各种重映射磁盘请求的方法。
Device mapper创建了另外的块设备,并具此块设备可继续堆叠。
Device mapper模块:dm-linear,dm-snap,dm-stripe,dm-raid1,dm-mpath,dm-crypt,dm-delay,dm-zero.

Device Mapper 使用:
struct target_type{
uint64_t features;
const char *name; //DM模块名
struct module *module;
unsigned version[3]; //DM模块版本
//DM框架函数集
dm_ctr_fn ctr; --》设备构造函数,
dm_dtr_fn dtr; --》设备的析构函数,当设备destroyed时调用
dm_map_fn map; --》I/O请求重映射函数,重映射功能的核心
dm_map_request_fn map_rq;
dm_endio_fn end_io; --》当I/O完成时调用
dm_request_endio_fn rq_end_io;
dm_presuspend_fn presuspend;
dm_postsuspend_fn postsuspend;
dm_preresume_fn preresume;
dm_resume_fn resume;
dm_status_fn status; --》设备的状态
dm_message_fn message; --》对设备的文本命令
dm_ioctl_fn ioctl; --》ioctl调用
dm_merge_fn merge;
dm_busy_fn busy;
dm_iterate_devices_fn iterate_devices;
dm_io_hints_fn io_hints;
struct list_head list;
}
模块注册一个新的设备类型:dm_register_target();
DM map()函数:在提交I/O请求前获得I/O请求,修改(更新目标块设备,扇区号,...)
返回码决定了怎么处理请求:
DM_MAPIO_SUBMITTED: map()函数已经分发了请求
DM_MAPIO_REMAPPED:请求应重新发送给重映射设备
DM_MAPIO_REQUEUE: 请求应该在之后重新提交。

RAID:

linux包含有软RAID的实现(raid0,raid1,raid5,raid5,raid6,raid10).
RAID实现不是由Device Mapper框架,有它自己的框架(personalities个性化)来实现。

RAID personality:RAID个性
struct md_personality{
char *name;
int level;
struct list_head list;
struct module *owner;
void (*make_request)(struct mddev *mddev, struct bio *bio);
int (*run)(struct mddev *mddev);
int (*stop)(struct mddev *mddev);
void (*status)(struct seq_file *seq, struct mddev *mddev);
void (*error_handler)(struct mddev *mddev, struct md_rdev *rdev);
int (*hot_add_disk) (struct mddev *mddev, struct md_rdev *rdev);
int (*hot_remove_disk) (struct mddev *mddev, struct md_rdev *rdev);
int (*spare_active) (struct mddev *mddev);
sector_t (*sync_request)(struct mddev *mddev, sector_t sector_nr, int *skipped, int go_faster);
int (*resize) (struct mddev *mddev, sector_t sectors);
sector_t (*size) (struct mddev *mddev, sector_t sectors, int raid_disks);
int (*check_reshape) (struct mddev *mddev);
int (*start_reshape) (struct mddev *mddev);
void (*finish_reshape) (struct mddev *mddev);
void (*quiesce) (struct mddev *mddev, int state);

void *(*takeover) (struct mddev *mddev);

}
注册:register_md_personality();
重要的域:
make_rquest:执行I/O请求
run: 开始RAID阵列
stop: 停止RAID阵列
hot_add_disk: 动态的添回磁盘到RAID阵列


你可能感兴趣的:(block device ---块设备IO)