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.o
KERNEL_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_install
clean:
rm -f *.o *~ core .depend .*.cmd *.ko *.mod.c
rm -f Module.markers Module.symvers modules.order
rm -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