By: fulinux
E-mail: fulinux@sina.com
Blog: https://blog.csdn.net/fulinus
喜欢的盆友欢迎点赞和订阅!
你的喜欢就是我写作的动力!
目录
- 理论来源
- 源码
- 编译
- 测试
理论来源
ramdisk驱动,区别在与使用最新的内核版本,比如linux-4.15。只做个简单记录,理论知识我就不贴了~
参考来源:韦东山二期驱动视频-块设备驱动1
源码
代码ramdisk.c:
#include <linux/major.h>
#include <linux/vmalloc.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/blkdev.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/hdreg.h>#include <asm/setup.h>#define DEVICE_NAME "myrb"
#define MYRAMBLOCK_SIZE (1024 * 1024)static int major = 0;
static unsigned char *myrb_buf;static DEFINE_SPINLOCK(myrb_lock);static struct gendisk *myrb_gendisk;
static struct request_queue *myrb_queue;static int myrb_getgeo(struct block_device *bdev, struct hd_geometry *geo)
{/* 容量=heads * cylinders * sectors * 512 */geo->heads = 2;geo->cylinders = 32;geo->sectors = MYRAMBLOCK_SIZE / geo->heads / geo->cylinders / 512;return 0;
}static const struct block_device_operations myrb_fops = {.owner = THIS_MODULE,.getgeo = myrb_getgeo,
};static void do_myrb_request(struct request_queue *q)
{static int r_cnt = 0;static int w_cnt = 0;struct request *req;req = blk_fetch_request(q);while(req) {/* 数据传输三要素:源,目的,长度 */unsigned long offset = blk_rq_pos(req) << 9;/* 目的/源 *///req->buffer/* 长度 */unsigned long len = blk_rq_cur_bytes(req);void *buffer = bio_data(req->bio);blk_status_t err = BLK_STS_OK;if (offset + len > MYRAMBLOCK_SIZE) {pr_err(DEVICE_NAME ": bad access: block=%llu, ""count=%u\n",(unsigned long long)blk_rq_pos(req),blk_rq_cur_sectors(req));err = BLK_STS_IOERR;goto done;}if (rq_data_dir(req) == READ) {printk("do_myrb_request read %d len = %d\n", ++r_cnt, len);memcpy(buffer, myrb_buf + offset, len);} else {printk("do_myrb_request write %d\n", ++w_cnt);memcpy(myrb_buf + offset, buffer, len);}
done:if (!__blk_end_request_cur(req, err))req = blk_fetch_request(q);}
}static int __init myrb_init(void)
{int ret;printk("Hello World!\n");ret = -EBUSY;major = register_blkdev(0, DEVICE_NAME);if (major <= 0)goto err;/* 1. 分配一个gendisk结构体 */ret = -ENOMEM;myrb_gendisk = alloc_disk(1);if (!myrb_gendisk) {goto out_disk;}myrb_queue = blk_init_queue(do_myrb_request, &myrb_lock);if (!myrb_queue)goto out_queue;myrb_gendisk->major = major;myrb_gendisk->first_minor = 0;myrb_gendisk->fops = &myrb_fops;sprintf(myrb_gendisk->disk_name, DEVICE_NAME);myrb_gendisk->queue = myrb_queue;set_capacity(myrb_gendisk, MYRAMBLOCK_SIZE / 512);/* 硬件相关的操作 */myrb_buf = kzalloc(MYRAMBLOCK_SIZE, GFP_KERNEL);add_disk(myrb_gendisk);return 0;out_queue:put_disk(myrb_gendisk);
out_disk:unregister_blkdev(major, DEVICE_NAME);
err:return ret;
}static void __exit myrb_exit(void)
{printk("Goodbye Cruel World!\n");unregister_blkdev(major, DEVICE_NAME);del_gendisk(myrb_gendisk);put_disk(myrb_gendisk);blk_cleanup_queue(myrb_queue);
}module_init(myrb_init);
module_exit(myrb_exit);MODULE_LICENSE("GPL");
Makefile文件:
obj-m := ramdisk.oKERNEL_SRC := /lib/modules/`uname -r`/build
SRC := $(shell pwd)all:$(MAKE) -C $(KERNEL_SRC) M=$(SRC)modules_install:$(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_installclean:rm -f *.o *~ core .depend .*.cmd *.ko *.mod.crm -f Module.markers Module.symvers modules.orderrm -rf .tmp_versions Modules.symvers
将上述两个文件放入一个目录中,然后直接在Ubuntu上编译和加载测试:
编译
make
测试
sudo insmod ramdisk.ko
ls -l /dev/myrb
格式化和挂载:
sudo mkfs.fat /dev/myrb
mkdir test
sudo mount -t vfat /dev/myrb test/
cp hello.c test/
内核打印信息dmesg:
[6244400.196037] Hello World!
[6244485.597221] do_myrb_request read 1 len = 4096
[6244485.597325] do_myrb_request read 2 len = 4096
[6244485.597552] do_myrb_request write 1
[6244485.597564] do_myrb_request write 2
[6244485.597568] do_myrb_request write 3
[6244485.597571] do_myrb_request write 4
[6244485.597574] do_myrb_request write 5
[6244532.059986] do_myrb_request read 3 len = 512
[6244532.060033] do_myrb_request read 4 len = 512
[6244532.060038] do_myrb_request read 5 len = 512
[6244532.060040] do_myrb_request read 6 len = 512
[6244532.060045] do_myrb_request read 7 len = 512
[6244532.060048] do_myrb_request read 8 len = 512
[6244532.060050] do_myrb_request read 9 len = 512
[6244532.060053] do_myrb_request read 10 len = 512
[6244532.060055] do_myrb_request read 11 len = 512
[6244532.060057] do_myrb_request read 12 len = 512
[6244532.060060] do_myrb_request read 13 len = 512
[6244532.060062] do_myrb_request read 14 len = 512
[6244532.060066] do_myrb_request read 15 len = 512
[6244532.060068] do_myrb_request read 16 len = 512
[6244532.060070] do_myrb_request read 17 len = 512
[6244532.060073] do_myrb_request read 18 len = 512
[6244532.060075] do_myrb_request read 19 len = 512
[6244532.060077] do_myrb_request read 20 len = 512
[6244532.060079] do_myrb_request read 21 len = 512
[6244532.060082] do_myrb_request read 22 len = 512
[6244532.060085] do_myrb_request read 23 len = 512
[6244532.060088] do_myrb_request read 24 len = 512
[6244532.060090] do_myrb_request read 25 len = 512
[6244532.060092] do_myrb_request read 26 len = 512
[6244532.060095] do_myrb_request read 27 len = 512
[6244532.060097] do_myrb_request read 28 len = 512
[6244532.060099] do_myrb_request read 29 len = 512
[6244532.060101] do_myrb_request read 30 len = 512
[6244532.060104] do_myrb_request read 31 len = 512
[6244532.060107] do_myrb_request read 32 len = 512
[6244532.060109] do_myrb_request read 33 len = 512
[6244532.060111] do_myrb_request read 34 len = 512
[6244532.060113] do_myrb_request read 35 len = 512
[6244532.060117] do_myrb_request write 6
[6244562.692167] do_myrb_request write 7
[6244608.777887] do_myrb_request write 8
[6244614.492541] do_myrb_request read 36 len = 512
[6244639.979392] do_myrb_request read 37 len = 512
[6244645.123077] do_myrb_request write 9
[6244645.123101] do_myrb_request write 10
[6244645.123108] do_myrb_request write 11
[6244645.123120] do_myrb_request write 12
[6244645.123125] do_myrb_request write 13
[6244675.835181] do_myrb_request write 14
[6246576.076089] do_myrb_request write 15