reference resources drivers\block\xd.c and drivers\block\z2ram.c
ls /dev/sd* -l view all disk devices. The disk with secondary device number 0 represents the whole disk, and the device numbers 1, 2 and 3 represent the partitions of the disk.
Program 1 uses memory to simulate disk to simply process request do_ramblock_request
#include <linux/module.h> #include <linux/errno.h> #include <linux/interrupt.h> #include <linux/mm.h> #include <linux/fs.h> #include <linux/kernel.h> #include <linux/timer.h> #include <linux/genhd.h> #include <linux/hdreg.h> #include <linux/ioport.h> #include <linux/init.h> #include <linux/wait.h> #include <linux/blkdev.h> #include <linux/blkpg.h> #include <linux/delay.h> #include <linux/io.h> #include <asm/system.h> #include <asm/uaccess.h> #include <asm/dma.h> static struct gendisk *ramblock_disk; static request_queue_t *ramblock_queue; // queue static DEFINE_SPINLOCK(ramblock_lock); // Spin lock static int major; static struct block_device_operations ramdisk_fops = { .owner = THIS_MODULE, }; #define RAMBLOCK_SIZE (1024*1024) // 1M static void do_ramblock_request(request_queue_t * q) { static int cnt = 0; printk("do_ramblock_request: %d\n", ++cnt); // To prevent jamming after insmod, take out the request here and pretend that the processing is completed struct request *req; while ((req = elv_next_request(q)) != NULL) { // Take out the next request with elevator scheduling algorithm end_request(req, 1); // It is considered that the request processing has been completed. 1 succeeded and 0 failed } } static int ramblock_init(void) { // 1. Assign a gendisk structure ramblock_disk = alloc_disk(16); // Number of secondary equipment number partitions up to 15 partitions // 2. Setting // 2.1 allocate / set queue: provide read-write function // You need to provide a function to process the queue ramblock_queue = blk_init_queue(do_ramblock_request, &ramblock_lock); ramblock_disk->queue = ramblock_queue; // 2.2 set other attributes, such as capacity major = register_blkdev(0, "ramdisk"); // Registration, only the master device number and name, no fops ramblock_disk->major = major; ramblock_disk->first_minor = 0; // 15 secondary devices starting from 0 sprintf(ramblock_disk->disk_name, "ramdisk"); ramblock_disk->fops = ramdisk_fops; set_capacity(ramblock_disk, RAMBLOCK_SIZE / 512); // Set the capacity of 1M in sectors // In the kernel file system, the sector is considered to be 512Byte // 3. Registration add_disk(ramblock_disk); return 0; } static void ramblock_exit(void) { unregister_blkdev(major, "ramdisk"); del_gendisk(ramblock_disk); put_disk(ramblock_disk); blk_cleanup_queue(ramblock_queue); } module_init(ramblock_init); module_exit(ramblock_exit); MODULE_LICENSE("GPL");
Test program 1 simple view block device information
Program 2 allocates memory to copy data between the analog disk and req - > buffer
#include <linux/module.h> #include <linux/errno.h> #include <linux/interrupt.h> #include <linux/mm.h> #include <linux/fs.h> #include <linux/kernel.h> #include <linux/timer.h> #include <linux/genhd.h> #include <linux/hdreg.h> #include <linux/ioport.h> #include <linux/init.h> #include <linux/wait.h> #include <linux/blkdev.h> #include <linux/blkpg.h> #include <linux/delay.h> #include <linux/io.h> #include <asm/system.h> #include <asm/uaccess.h> #include <asm/dma.h> static struct gendisk *ramblock_disk; static request_queue_t *ramblock_queue; // queue static DEFINE_SPINLOCK(ramblock_lock); // Spin lock static int major; static struct block_device_operations ramdisk_fops = { .owner = THIS_MODULE, }; #define RAMBLOCK_SIZE (1024*1024) // 1M static unsigned char *ramblock_buf; // Allocated memory static void do_ramblock_request(request_queue_t * q) { // static int cnt = 0; // printk("do_ramblock_request: %d\n", ++cnt); // Simulate the block device with memory and copy the data in the request struct request *req; // Process the request after it is taken out while ((req = elv_next_request(q)) != NULL) { // Take out the next request with elevator scheduling algorithm // Three elements of data transmission: source destination length unsigned long offset = req->sector << 9; // *512 the size of one sector of the source is 512 and restored to Byte unsigned long len = req->current_nr_sectors << 9; // *512 length if (rq_data_dir(req) == READ) { // Read request memcpy(req->buffer, ramblock_buf+offset, len); // Read data from disk memory simulated disk } else { memcpy(ramblock_buf+offset, req->buffer, len); // Write buffer data to disk memory } end_request(req, 1); // Request processing has been completed. 1 succeeded. 0 failed } } static int ramblock_init(void) { // 1. Assign a gendisk structure ramblock_disk = alloc_disk(16); // Number of secondary equipment number partitions up to 15 partitions // 2. Setting // 2.1 allocate / set queue: provide read-write function // You need to provide a function to process the queue ramblock_queue = blk_init_queue(do_ramblock_request, &ramblock_lock); ramblock_disk->queue = ramblock_queue; // 2.2 set other attributes, such as capacity major = register_blkdev(0, "ramdisk"); // Registration, only the master device number and name, no fops ramblock_disk->major = major; ramblock_disk->first_minor = 0; // 15 secondary devices starting from 0 sprintf(ramblock_disk->disk_name, "ramdisk"); ramblock_disk->fops = ramdisk_fops; set_capacity(ramblock_disk, RAMBLOCK_SIZE / 512); // Set the capacity of 1M in sectors // In the kernel file system, the sector is considered to be 512Byte // 3. Hardware related operations ramblock_buf = kzalloc(RAMBLOCK_SIZE, GFP_KERNEL); // Allocate a block of memory // 4. Registration add_disk(ramblock_disk); return 0; } static void ramblock_exit(void) { unregister_blkdev(major, "ramdisk"); del_gendisk(ramblock_disk); put_disk(ramblock_disk); blk_cleanup_queue(ramblock_queue); kfree(ramblock_buf); } module_init(ramblock_init); module_exit(ramblock_exit); MODULE_LICENSE("GPL");
Test procedure 2
- insmod ramblock.ko load new block
Prompt unknown partition table after loading because ramblock_buf = kzalloc(RAMBLOCK_SIZE, GFP_KERNEL); The allocated memory is cleared, not the partition table. There is nothing.
- Format mkdosfs /dev/ramblock
- mount /dev/ramblock /tmp/
- Read and write files, cd /tmp / and then VI 1 Txt add content hello; Copy the file cp /etc/inittab
- cd / umount /tmp/
- Reconnect mount /dev/ramblock /tmp / to see if the two files are still in ls /tmp/
- Put the whole disk into the Bin file, cat / dev / ramblock > / MNT / ramblock bin
- View on ram pc.block bin,sudo mount -o loop ramblock.bin /mnt loop attaches a normal file as a block device
Program 3 adds printing when reading and writing
Just print on program 2,
static void do_ramblock_request(request_queue_t * q) { static int rd_cnt = 0; static int wt_cnt = 0; // printk("do_ramblock_request: %d\n", ++cnt); // Simulate the block device with memory and copy the data in the request struct request *req; // Process the request after it is taken out while ((req = elv_next_request(q)) != NULL) { // Take out the next request with elevator scheduling algorithm // Three elements of data transmission: source destination length unsigned long offset = req->sector << 9; // *512 the size of one sector of the source is 512 and restored to Byte unsigned long len = req->current_nr_sectors << 9; // *512 length if (rq_data_dir(req) == READ) { // Read request printk("do_ramblock_request read: %d\n", ++rd_cnt); memcpy(req->buffer, ramblock_buf+offset, len); // Read data from disk memory simulated disk } else { printk("do_ramblock_request write: %d\n", ++wt_cnt); memcpy(ramblock_buf+offset, req->buffer, len); // Write buffer data to disk memory } end_request(req, 1); // Request processing has been completed. 1 succeeded. 0 failed } }
Procedure 3 test
- insmod xxx.ko
- Format mkdosfs /dev/ramblock is write
- mount /dev/ramblock /tmp is all read
- Copy a file cp /etc/inittab /tmp. It is read but not written. It will be written later. The hard disk is not really finished when the read-write prompt is completed.
- Copy another file CP / etc / init D / RCS / tmp does not write immediately. Write immediately after sync. Sync is a system call
Either read or write, elevator scheduling algorithm,
Procedure 3 is then tested
Partition / dev/ramblock. Unknown value for: cylinders occurs. In order to be compatible with old devices, you need to set the number of virtual cylinders and obtain geometric properties,
On the basis of program 3, remove the printing information and add the code to obtain the geometric properties of the disk,
// Provides geometric information about the disk static int ramblock_getgeo(struct block_device *bdev, struct hd_geometry *geo) { // Capacity = heads x cylinders x sectors x 512 geo->heads = 2; // How many sides of the head geo->sectors = 32; // How many rings on the cylinder geo->cylinders = RAMBLOCK_SIZE/2/32/512; // How many sectors are there in a ring 1024 * 1024 / 2 / 512 / 32 return 0; } static struct block_device_operations ramdisk_fops = { .owner = THIS_MODULE, .getgeo = ramblock_getgeo, // Obtain geometric information and provide cylinders when partitioning };
- insmod xxx.ko
- ls /dev/ramblock* -l has only one whole disk
- Partition fdsk/dev/ramblock
summary
If the future disk can be accessed like memory, the device will be simple.
Write your own queue processing function, ramblock_ queue = blk_ init_ queue(do_ramblock_request, &ramblock_lock);.