杂记
一. 块设备相关结构体
块设备结构体
struct block_device {
dev_t bd_dev; //设备号
struct inode * bd_inode; /* will die */
struct super_block * bd_super; //超级块
int bd_openers;
struct mutex bd_mutex; /* open/close mutex */
struct list_head bd_inodes;
void * bd_claiming;
void * bd_holder;
int bd_holders;
#ifdef CONFIG_SYSFS
struct list_head bd_holder_list;
#endif
struct block_device * bd_contains;
unsigned bd_block_size;
struct hd_struct * bd_part;
/* number of times partitions within this device have been opened. */
unsigned bd_part_count;
int bd_invalidated;
struct gendisk * bd_disk;
struct list_head bd_list;
unsigned long bd_private;
/* The counter of freeze processes */
int bd_fsfreeze_count;
/* Mutex for freeze */
struct mutex bd_fsfreeze_mutex;
};
通用磁盘gendisk结构体
struct gendisk {
int major; //主设备号
int first_minor; //第一个分区的次设备号
int minors; //次设备个数,分区数
char disk_name[DISK_NAME_LEN]; //设备名
char *(*devnode)(struct gendisk *gd, mode_t *mode);
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 work_struct async_notify;
#ifdef CONFIG_BLK_DEV_INTEGRITY
struct blk_integrity *integrity;
#endif
int node_id;
};
request请求项
struct request {
struct list_head queuelist;
struct call_single_data csd;
struct request_queue *q;
unsigned int cmd_flags;
enum rq_cmd_type_bits cmd_type;
unsigned long atomic_flags;
int cpu;
unsigned int __data_len;
sector_t __sector;
struct bio *bio;
struct bio *biotail;
struct hlist_node hash;
union {
struct rb_node rb_node;
void *completion_data;
};
void *elevator_private;
void *elevator_private2;
void *elevator_private3;
struct gendisk *rq_disk;
unsigned long start_time;
#ifdef CONFIG_BLK_CGROUP
unsigned long long start_time_ns;
unsigned long long io_start_time_ns;
#endif
unsigned short nr_phys_segments;
#if defined(CONFIG_BLK_DEV_INTEGRITY)
unsigned short nr_integrity_segments;
#endif
unsigned short ioprio;
int ref_count;
void *special;
char *buffer;
int tag;
int errors;
unsigned char __cmd[BLK_MAX_CDB];
unsigned char *cmd;
unsigned short cmd_len;
unsigned int extra_len;
unsigned int sense_len;
unsigned int resid_len;
void *sense;
unsigned long deadline;
struct list_head timeout_list;
unsigned int timeout;
int retries;
rq_end_io_fn *end_io;
void *end_io_data;
struct request *next_rq;
};
bio I/O请求块
struct bio {
sector_t bi_sector; //要传输的第一个扇区
struct bio *bi_next;//下一个bio
struct block_device *bi_bdev;
unsigned long bi_flags; //状态标志
unsigned long bi_rw; //高位表示优先级,低位标志读写
unsigned short bi_vcnt; //bio_vec数量
unsigned short bi_idx; //当前bio_vec索引
unsigned int bi_phys_segments;
unsigned int bi_size;
unsigned int bi_seg_front_size;
unsigned int bi_seg_back_size;
unsigned int bi_max_vecs;
unsigned int bi_comp_cpu;
atomic_t bi_cnt;
struct bio_vec *bi_io_vec; //实际的vec列表
bio_end_io_t *bi_end_io;
void *bi_private;
#if defined(CONFIG_BLK_DEV_INTEGRITY)
struct bio_integrity_payload *bi_integrity;
#endif
bio_destructor_t *bi_destructor;
struct bio_vec bi_inline_vecs[0];
};
bio_vec
struct bio_vec {
struct page *bv_page; //页指针
unsigned int bv_len; //传输字节数
unsigned int bv_offset; //偏移位置
};
块设备操作函数集
struct block_device_operations {
int (*open) (struct block_device *, fmode_t); //打开
int (*release) (struct gendisk *, fmode_t); //释放
int (*ioctl) (struct block_device *, fmode_t, unsigned, unsigned long); //控制
int (*compat_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
int (*direct_access) (struct block_device *, sector_t,void **, unsigned long *);
int (*media_changed) (struct gendisk *); //判断介质是否改变
void (*unlock_native_capacity) (struct gendisk *);
int (*revalidate_disk) (struct gendisk *); //使介质有效(针对可移动设备)
int (*getgeo)(struct block_device *, struct hd_geometry *); //填充hd_geometry结构体
/* this callback is with swap_lock and sometimes page table lock held */
void (*swap_slot_free_notify) (struct block_device *, unsigned long);
struct module *owner; //模块所有者
};
注册主设备号
int register_blkdev(unsigned int major, const char *name)
{
struct blk_major_name **n, *p;
int index, ret = 0;
mutex_lock(&block_class_lock);
/* temporary */
if (major == 0) {
for (index = ARRAY_SIZE(major_names)-1; index > 0; index--) {
if (major_names[index] == NULL)
break;
}
if (index == 0) {
printk("register_blkdev: failed to get major for %s\n",name);
ret = -EBUSY;
goto out;
}
major = index;
ret = major;
}
p = kmalloc(sizeof(struct blk_major_name), GFP_KERNEL);
if (p == NULL) {
ret = -ENOMEM;
goto out;
}
p->major = major;
strlcpy(p->name, name, sizeof(p->name));
p->next = NULL;
index = major_to_index(major);
for (n = &major_names[index]; *n; n = &(*n)->next) {
if ((*n)->major == major)
break;
}
if (!*n)
*n = p;
else
ret = -EBUSY;
if (ret < 0) {
printk("register_blkdev: cannot get major %d for %s\n",major, name);
kfree(p);
}
out:
mutex_unlock(&block_class_lock);
return ret;
}
注销主设备号
void unregister_blkdev(unsigned int major, const char *name)
{
struct blk_major_name **n;
struct blk_major_name *p = NULL;
int index = major_to_index(major);
mutex_lock(&block_class_lock);
for (n = &major_names[index]; *n; n = &(*n)->next)
if ((*n)->major == major)
break;
if (!*n || strcmp((*n)->name, name)) {
WARN_ON(1);
} else {
p = *n;
*n = p->next;
}
mutex_unlock(&block_class_lock);
kfree(p);
}
分配gendisk
struct gendisk *alloc_disk(int minors)
{
return alloc_disk_node(minors, -1);
}
struct gendisk *alloc_disk_node(int minors, int node_id)
{
struct gendisk *disk;
disk = kmalloc_node(sizeof(struct gendisk),GFP_KERNEL | __GFP_ZERO, node_id);
if (disk) {
if (!init_part_stats(&disk->part0)) {
kfree(disk);
return NULL;
}
disk->node_id = node_id;
if (disk_expand_part_tbl(disk, 0)) {
free_part_stats(&disk->part0);
kfree(disk);
return NULL;
}
disk->part_tbl->part[0] = &disk->part0;
disk->minors = minors;
rand_initialize_disk(disk);
disk_to_dev(disk)->class = &block_class;
disk_to_dev(disk)->type = &disk_type;
device_initialize(disk_to_dev(disk));
INIT_WORK(&disk->async_notify,media_change_notify_thread);
}
return disk;
}
初始化块设备请求队列
struct request_queue *blk_init_queue(request_fn_proc *rfn, spinlock_t *lock)
{
return blk_init_queue_node(rfn, lock, -1);
}
blk_init_queue_node(request_fn_proc *rfn, spinlock_t *lock, int node_id)
{
struct request_queue *uninit_q, *q;
uninit_q = blk_alloc_queue_node(GFP_KERNEL, node_id);
if (!uninit_q)
return NULL;
q = blk_init_allocated_queue_node(uninit_q, rfn, lock, node_id);
if (!q)
blk_cleanup_queue(uninit_q);
return q;
}
清除块设备请求队列
void blk_cleanup_queue(struct request_queue *q)
{
blk_sync_queue(q);
del_timer_sync(&q->backing_dev_info.laptop_mode_wb_timer);
mutex_lock(&q->sysfs_lock);
queue_flag_set_unlocked(QUEUE_FLAG_DEAD, q);
mutex_unlock(&q->sysfs_lock);
if (q->elevator)
elevator_exit(q->elevator);
blk_put_queue(q);
}
添加disk
void add_disk(struct gendisk *disk)
{
struct backing_dev_info *bdi;
dev_t devt;
int retval;
WARN_ON(disk->minors && !(disk->major || disk->first_minor));
WARN_ON(!disk->minors && !(disk->flags & GENHD_FL_EXT_DEVT));
disk->flags |= GENHD_FL_UP;
retval = blk_alloc_devt(&disk->part0, &devt);
if (retval) {
WARN_ON(1);
return;
}
disk_to_dev(disk)->devt = devt;
disk->major = MAJOR(devt);
disk->first_minor = MINOR(devt);
/* Register BDI before referencing it from bdev */
bdi = &disk->queue->backing_dev_info;
bdi_register_dev(bdi, disk_devt(disk));
blk_register_region(disk_devt(disk), disk->minors, NULL,exact_match, exact_lock, disk);
register_disk(disk);
blk_register_queue(disk);
retval = sysfs_create_link(&disk_to_dev(disk)->kobj, &bdi->dev->kobj,"bdi");
WARN_ON(retval);
}