linux块设备驱动

本文深入探讨了Linux操作系统中块设备的结构、通用磁盘gendisk、请求请求项request、bioI/O请求块、块设备操作函数集及主设备号注册与管理的相关技术细节,提供了一站式的理解框架。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

杂记

一. 块设备相关结构体

块设备结构体

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);
}


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值