我做的主要是ssd驱动,ssd驱动通过FTL转换成对一个磁盘的操作,也就相当于一个磁盘的块设备驱动。块设备驱动程序主要通过传输固定大小的随机数据来访问设备。
注册块设备
和字符设备驱动一样,都必须先到内核注册下,才能操作设备;在头文件<linux/fs.h>中
注册函数: int register_blkdev(unsigned int major, const char *name);
参数:major 是主设备号,name是设备的名称,在/proc/devices中显示。
如果major传递的是0,则由内核来分配一个主设备号给设备,并且返回给调用者。如果返回值为负数,则表示函数注册失败;
注:其实如果major不为0的话就相当于字符设备中的静态设备号申请,如果为0,则相当于动态设备申请了;
销毁函数:int unregister_blkdev(unsigned int major, const char *name);
参数一定要和注册函数的参数匹配,否则出错;
gendisk结构体
结构体
结构体如下:
struct gendisk {
/* major, first_minor and minors are input parameters only,
* don't use directly. Use disk_devt() and disk_max_parts().
*/
int major; /* major number of driver */
int first_minor;
int minors; /* maximum number of minors, =1 for
* disks that can't be partitioned. */
char disk_name[DISK_NAME_LEN]; /* name of major driver */
char *(*devnode)(struct gendisk *gd, mode_t *mode);
unsigned int events; /* supported events */
unsigned int async_events; /* async events, subset of all */
/* Array of pointers to partitions indexed by partno.
* Protected with matching bdev lock but stat and other
* non-critical accesses use RCU. Always access through
* helpers.
*/
//整个块设备的分区信息都包含在里面,其核心结构是一个struct hd_struct的指针数组,每一项都指向一个描述分区的hd_struct结构
struct disk_part_tbl __rcu *part_tbl;
struct hd_struct part0;// 第一个分区的信息,如果没有分区则指向整个设备
const struct block_device_operations *fops;//操作函数指针集合
struct request_queue *queue;//请求队列
void *private_data;
int flags;
struct device *driverfs_dev; // FIXME: remove
struct kobject *slave_dir;
struct timer_rand_state *random;
atomic_t sync_io; /* RAID */
struct disk_events *ev;
#ifdef CONFIG_BLK_DEV_INTEGRITY
struct blk_integrity *integrity;
#endif
int node_id;
};
int minors 次设备号,一个驱动器至少使用一个次设备号,如果驱动器是可分区的,则为每一个分区分配一个次设备号;
char disk_name[32] 设置磁盘设备的名称,该名字在/proc/partitions和sysfs中显示;
struct request_queue *queue 请求队列,为设备管理I/O请求;
sector_t capacity 以512为一个扇区,该驱动器可以包含的扇区数,一般通过set_capacity设置;
set_capacity(dev->gd, nsectors*(hardsect_size/KERNEL_SECTOR_SIZE));KERNEL_SECTOR_SIZE是一个常量,使用该常量进行内核的512字节扇区到实际使用扇区大小的转换。
分区表
//分区列表
struct disk_part_tbl {
struct rcu_head rcu_head;
int len;
struct hd_struct __rcu *last_lookup;
struct hd_struct __rcu *part[];
};
分区结构体
// 分区信息
struct hd_struct {
sector_t start_sect;// 当前分区的起始扇区
sector_t nr_sects;// 分区的大小,多少个扇区
sector_t alignment_offset;
unsigned int discard_alignment;
struct device __dev;// 一个分区对应一个设备
struct kobject *holder_dir;
int policy, partno;// partno分区编号
struct partition_meta_info *info;
#ifdef CONFIG_FAIL_MAKE_REQUEST
int make_it_fail;
#endif
unsigned long stamp;
atomic_t in_flight[2];
#ifdef CONFIG_SMP
struct disk_stats __percpu *dkstats;
#else
struct disk_stats dkstats;
#endif
atomic_t ref;
st