1.块设备只能以块为单位接受输入和返回输出,而字符设备则以字节为单位
2.块设备对于I/O请求有对应的缓冲区,因此他们可以选择以什么顺序进行响应,字符设备无须缓冲且被直接读写。对于存储设备而言调整读写的顺序作用巨大,因为读写连续的扇区比分离的扇区更快
3.字符设备只能被顺序读写,而块设备可以随机访问。虽然块设备可以随机访问,但是对于硬盘这类机械设备而言,顺序地组织块设备的访问可以提高性能
block_device_operations结构体
struct block_device_operations {
int (*open) (struct inode *, struct file *);
int (*release) (struct inode *, struct file *);
int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long);
int (*media_changed) (struct gendisk *);
int (*revalidate_disk) (struct gendisk *);
struct module *owner;
};
media_changed:被内核调用来检查是否驱动器中的介质已经改变。这个函数仅适用于支持可移动介质的驱动器,通常需要在驱动中增加一个表示介质状态是否改变的标志变量,非可移动设备的驱动不需要实现这个方法
revalidate_disk:用来响应一个介质的改变,它给驱动一个机会来进行必要的工作以实新介质准备好
gendisk结构体
用来表示一个独立的磁盘设备(或分区)
struct gendisk {
int major; /* major number of driver */
int first_minor;
int minors; //次设备号,分区数量
char disk_name[16]; /* name of major driver */
struct hd_struct **part; /* [indexed by minor] */
struct block_device_operations *fops;
struct request_queue *queue;
void *private_data;
sector_t capacity;
int flags;
char devfs_name[64]; /* devfs crap */
int number; /* more of the same */
struct device *driverfs_dev;
struct kobject kobj;
struct timer_rand_state *random;
int policy;
unsigned sync_io; /* RAID */
unsigned long stamp, stamp_idle;
int in_flight;
#ifdef CONFIG_SMP
struct disk_stats *dkstats;
#else
struct disk_stats dkstats;
#endif
};
sda:整个分区
sda*:分区(次设备号)
分配gendisk
struct gendisk *alloc_disk(int minors)
增加gendisk
void add_disk(struct gendisk *disk)
释放gendisk
void del_gendisk(struct gendisk *disk)
request_queue结构体
请求队列跟踪等候的块I/O请求。I/O调度器(也称电梯)的工作是以最优性能的方式向驱动提交I/O 请求。对于机械磁头而言,当给定顺序请求时,可是使磁盘顺序地从一头向另一头工作,也就是电梯算法
初始化请求队列
request_queue_t *blk_init_queue(request_fn_proc *rfn, spinlock_t *lock)
清除请求队列
void blk_cleanup_queue(request_queue_t * q)
分配请求队列
request_queue_t *blk_alloc_queue(int gfp_mask)
提交请求
struct request *elv_next_request(request_queue_t *q)
去除请求
void elv_remove_request(request_queue_t *q, struct request *rq)