史上最简单的Linux块驱动block device driver 入门

今天我们使用内存来虚拟一个8M的硬盘。

驱动代码:

#include <linux/bio.h>
#include <linux/init.h> /* Needed for the macros */
#include <linux/kernel.h> /* Needed for pr_info() */
#include <linux/module.h> /* Needed by all modules */
#include <linux/sched.h>
#include <linux/blkdev.h>
#include <linux/genhd.h>
#include <uapi/linux/hdreg.h>

#define HEADS 4
#define SECTORS 16
#define CYLINDERS 256
#define SECTORS_SIZE 512
#define SECTORS_TOTAL (HEADS * SECTORS * CYLINDERS)
 //8M
#define VDISK_SZIE (SECTORS_TOTAL * SECTORS_SIZE)

#define   DEVICE_NAME  "mydisk"

/**
 *
 * https://linux-kernel-labs.github.io/refs/heads/master/labs/block_device_drivers.html
 *
 * https://www.oreilly.com/library/view/linux-device-drivers/0596005903/ch16.html
 *
 * https://bootlin.com/doc/legacy/block-drivers/block_drivers.pdf
 *
 *
 * https://kernel.dk/blk-mq.pdf
 *
 * A block is a fixed-size chunk of data, the size being determined by the kernel.
 * Blocks are often 4096 bytes, but that value can vary depending
 * on the architecture and the exact filesystem being used
 *
 *
 * sudo  fdisk /dev/mydisk
 * then n  p  w
 * sudo mkfs.ext2 /dev/mydisk1
 * sudo  mount /dev/mydisk1  /tmp
 * sudo  vi  to  write to  txt  file.
 * then use  cat  to  verify.
 *
 *
 *
 */

static int major;

struct vdsk_dev  {
	unsigned long size;
	u8 *data;
	spinlock_t lock ;
	struct gendisk *mydisk;
	struct request_queue *queue;
};

struct vdsk_dev *vdsk;

int myopen(struct block_device *dev, fmode_t mode) {
	return 0;
}

void myrelease(struct gendisk *disk, fmode_t mode) {
}

int mygetgeo(struct block_device *dev, struct hd_geometry *geo) {
	pr_err("mygetgeo");
	geo->heads = HEADS;
	geo->sectors = SECTORS;
	geo->cylinders = CYLINDERS;
	geo->start = 0;
	return 0;
}

/* This function also called from IRQ context */
static void my_request(struct request_queue *q)
{
	struct vdsk_dev  *mydev = q->queuedata;
	struct request *req;
	u32 sect_num, sect_cnt;
	struct bio *bio;
	struct bio_vec bvec;
	struct bvec_iter iter;
	char *buffer;
	unsigned long offset;
	unsigned long nbytes;
	int segment = 0;
	int  cbio =0;
	req = blk_fetch_request(q);
	pr_err("my_request start");
	while (req != NULL) {
		sect_num = blk_rq_pos(req);
		/* deal whole segments */
		sect_cnt = blk_rq_sectors(req);
		__rq_for_each_bio(bio,req){
			segment = 0;
			cbio++;
			pr_err("now process bio: %d",cbio);
			bio_for_each_segment(bvec,bio,iter){
				segment++;
				pr_err("now process segment: %d",segment);
				buffer =  __bio_kmap_atomic(bio,iter);
				offset =iter.bi_sector * SECTORS_SIZE ;
				nbytes = bvec.bv_len ;

				if (bio_data_dir(bio) == WRITE) {
					pr_err("my_request WRITE");
					memcpy(mydev->data + offset, buffer, nbytes);
				} else {
					pr_err("my_request read");
					memcpy(buffer, mydev->data + offset, nbytes);
				}
				__bio_kunmap_atomic(bio);
			}
		}

		if(!__blk_end_request_cur(req,0)){
			req = blk_fetch_request(q);
}
	}
	 pr_err("my_request end");
}

static const struct block_device_operations my_bd_ops = { .owner = THIS_MODULE,
		.open = myopen, .release = myrelease, .getgeo = mygetgeo, };

static __init int my_init(void) {
	  int ret;
	  ret = -EBUSY;
	  major = register_blkdev(0,DEVICE_NAME);
	  if(major<=0){
	 pr_err("register_blkdev fail");
	 goto err;
	  }

	pr_err("SECTORS_TOTAL %d",SECTORS_TOTAL);

	vdsk = kzalloc(sizeof(struct vdsk_dev),GFP_KERNEL);
	vdsk->size = VDISK_SZIE;
	vdsk->data = vmalloc(VDISK_SZIE);
    pr_err("00000000000000000");

    ret = -ENOMEM;
    vdsk->mydisk = alloc_disk(4);
    pr_err("alloc_disk");
    if (!vdsk->mydisk)
   	goto out_disk;
       vdsk->mydisk->major = major;
       vdsk->mydisk->first_minor = 0;
       vdsk->mydisk->fops =  &my_bd_ops;

    spin_lock_init(&vdsk->lock);
    vdsk->queue = blk_init_queue(my_request,&vdsk->lock);
    pr_err("blk_init_queue");

    if (!vdsk->queue)
   	goto out_queue;

    blk_queue_logical_block_size(vdsk->queue, SECTORS_SIZE);
    vdsk->queue->queuedata = vdsk;

    vdsk->mydisk->queue = vdsk->queue;
    vdsk->mydisk->private_data = vdsk ;
	sprintf(vdsk->mydisk->disk_name,"mydisk");

	set_capacity(vdsk->mydisk,SECTORS_TOTAL);
	add_disk(vdsk->mydisk);
	pr_err("add_disk");
	pr_err("my_init end ");
	return 0;

out_queue:
	pr_err("out_queue");
	put_disk(vdsk->mydisk);

out_disk:
	pr_err("out_disk");
	unregister_blkdev(major, DEVICE_NAME);

err:
	return ret;
}

static void __exit my_exit(void) {
	del_gendisk(vdsk->mydisk);
	blk_cleanup_queue(vdsk->queue);
	put_disk(vdsk->mydisk);
	unregister_blkdev(major,DEVICE_NAME);
	vfree(vdsk->data);
	kfree(vdsk);
}

module_init(my_init);
module_exit(my_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Andy");
MODULE_DESCRIPTION("andy one-key driver");
MODULE_ALIAS("one-key");

模块编译安装之后,执行以下命令:
1 分区
sudo fdisk /dev/mydisk
then n p w
2 建立文件系统
sudo mkfs.ext2 /dev/mydisk1
3挂载文件系统
sudo mount /dev/mydisk1 /tmp
4 测试写入以及读。
sudo vi to write to txt file.
then use cat to verify.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单Linux设备驱动代码示例,它实现了一个虚拟设备: ```c #include <linux/module.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/blkdev.h> #include <linux/version.h> #define VIRTUAL_DEVICE_NAME "virtblk" #define VIRTUAL_DEVICE_SIZE (1024 * 1024) // 1MB #define SECTOR_SIZE 512 static int major_num = 0; static struct request_queue *req_queue = NULL; static struct gendisk *virtblk_disk = NULL; static unsigned char *virtblk_data = NULL; static void virtblk_request(struct request_queue *q) { struct request *req = NULL; int err = 0; while ((req = blk_fetch_request(q)) != NULL) { if (req->cmd_type != REQ_TYPE_FS) { printk(KERN_WARNING "virtblk: Unsupported command\n"); err = -EIO; goto error; } switch (rq_data_dir(req)) { case READ: memcpy(req->buffer, virtblk_data + (req->sector << 9), req->current_nr_sectors * SECTOR_SIZE); break; case WRITE: memcpy(virtblk_data + (req->sector << 9), req->buffer, req->current_nr_sectors * SECTOR_SIZE); break; default: printk(KERN_WARNING "virtblk: Unsupported data direction\n"); err = -EIO; goto error; } if (!__blk_end_request_cur(req, err)) req = NULL; } return; error: printk(KERN_ERR "virtblk: Request error\n"); __blk_end_request_cur(req, err); while ((req = blk_fetch_request(q)) != NULL) __blk_end_request_cur(req, -EIO); } static struct block_device_operations virtblk_fops = { .owner = THIS_MODULE, }; static int __init virtblk_init(void) { virtblk_data = kzalloc(VIRTUAL_DEVICE_SIZE, GFP_KERNEL); if (!virtblk_data) { printk(KERN_ERR "virtblk: Memory allocation failed\n"); return -ENOMEM; } major_num = register_blkdev(0, VIRTUAL_DEVICE_NAME); if (major_num <= 0) { printk(KERN_ERR "virtblk: Unable to register block device\n"); kfree(virtblk_data); return -EBUSY; } req_queue = blk_init_queue(virtblk_request, NULL); if (!req_queue) { printk(KERN_ERR "virtblk: Request queue creation failed\n"); unregister_blkdev(major_num, VIRTUAL_DEVICE_NAME); kfree(virtblk_data); return -ENOMEM; } blk_queue_logical_block_size(req_queue, SECTOR_SIZE); virtblk_disk = alloc_disk(1); if (!virtblk_disk) { printk(KERN_ERR "virtblk: Disk allocation failed\n"); blk_cleanup_queue(req_queue); unregister_blkdev(major_num, VIRTUAL_DEVICE_NAME); kfree(virtblk_data); return -ENOMEM; } virtblk_disk->major = major_num; virtblk_disk->first_minor = 0; virtblk_disk->fops = &virtblk_fops; virtblk_disk->queue = req_queue; sprintf(virtblk_disk->disk_name, "virtblk%c", 'a' + virtblk_disk->first_minor); set_capacity(virtblk_disk, VIRTUAL_DEVICE_SIZE / SECTOR_SIZE); add_disk(virtblk_disk); printk(KERN_INFO "virtblk: Virtual block device registered\n"); return 0; } static void __exit virtblk_exit(void) { del_gendisk(virtblk_disk); put_disk(virtblk_disk); blk_cleanup_queue(req_queue); unregister_blkdev(major_num, VIRTUAL_DEVICE_NAME); kfree(virtblk_data); printk(KERN_INFO "virtblk: Virtual block device unregistered\n"); } module_init(virtblk_init); module_exit(virtblk_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Your Name"); MODULE_DESCRIPTION("Virtual block device driver"); ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值