#include <linux/module.h> #include <linux/blkdev.h> #include <linux/hdreg.h> #include <linux/version.h>#include <linux/vmalloc.h>
/** insmod tiny4412_blkdev.ko * # or insmod tiny4412_blkdev.ko size=numK/M/G/T * fdisk /dev/tiny4412_blkdev # create 2 patitions * mkfs.ext2 /dev/tiny4412_blkdev1 * mkfs.ext2 /dev/tiny4412_blkdev2 * mount /dev/tiny4412_blkdev1 /mnt/temp1/ * mount /dev/tiny4412_blkdev2 /mnt/temp2/ * # play in /mnt/temp1/ and /mnt/temp2/ * umount /mnt/temp1/ * umount /mnt/temp2/ * rmmod tiny4412_blkdev.ko * */static int Tiny4412_block_major=0;static struct request_queue *tiny4412_blkdev_queue; static struct gendisk *tiny4412_blkdev_disk;
#define TINY4412_BLK_DEV_BYTES (1024*1024*50) /*设置块设备的大小*/static unsigned char *sizeof_p;
/** Handle an I/O request.* 实现扇区的读写
unsigned long sector: 当前扇区位置unsigned long nsect : 扇区读写数量char *buffer : 读写的缓冲区指针int write : 是读还是写*/static void Tiny4412_block_dev_sector_read_write(unsigned long sector,unsigned long nsect, char *buffer, int write){ /*块设备最小单位是一个扇区,一个扇区的字节数是512字节*/ unsigned long offset = sector; /*写入数据的位置*/ unsigned long nbytes = nsect; /*写入的长度*/ if((offset + nbytes)>TINY4412_BLK_DEV_BYTES) { printk("写超出范围,强制结束(%ld %ld)\n", offset, nbytes); return; } if(write) /*为真,表示是写*/ memcpy(sizeof_p + offset, buffer, nbytes); else /*读操作*/ memcpy(buffer,sizeof_p + offset, nbytes);}
/*处理请求*/static int tiny4412_blkdev_make_request(struct request_queue *q, struct bio *bio) { int dir; unsigned long long dsk_offset; struct bio_vec *bvec; int i; void *iovec_mem; /*判断读写方向*/ if(bio_data_dir(bio) == WRITE) dir = 1; else dir = 0; dsk_offset = bio->bi_sector << 9; bio_for_each_segment(bvec, bio, i) { iovec_mem = kmap(bvec->bv_page) + bvec->bv_offset; //起始位置,长度,源数据,方向 Tiny4412_block_dev_sector_read_write(dsk_offset,bvec->bv_len,iovec_mem,dir); kunmap(bvec->bv_page); dsk_offset += bvec->bv_len; } bio_endio(bio, 0); return 0;}
struct block_device_operations tiny4412_blkdev_fops = { .owner= THIS_MODULE, };
static int __init tiny4412_blkdev_init(void) { sizeof_p=vmalloc(TINY4412_BLK_DEV_BYTES); if(sizeof_p==NULL) { printk("空间申请失败!\n"); return 0; } /*动态分配请求队列*/ tiny4412_blkdev_queue = blk_alloc_queue(GFP_KERNEL); /*绑定请求队列*/ blk_queue_make_request(tiny4412_blkdev_queue,tiny4412_blkdev_make_request); /*动态分配次设备号结构*/ /*每一个磁盘(分区)都是使用一个gendisk结构保存*/ tiny4412_blkdev_disk = alloc_disk(64); /*磁盘名称赋值*/ strcpy(tiny4412_blkdev_disk->disk_name, "tiny4412_blkdev");
/*注册一个块设备,自动分配主设备号*/ Tiny4412_block_major = register_blkdev(0,"Tiny4412_block"); printk("Tiny4412_block_major=%d\n",Tiny4412_block_major); tiny4412_blkdev_disk->major=Tiny4412_block_major; /*主设备号*/ tiny4412_blkdev_disk->first_minor = 0; /*次设备号*/ tiny4412_blkdev_disk->fops = &tiny4412_blkdev_fops; /*文件操作结合*/ tiny4412_blkdev_disk->queue = tiny4412_blkdev_queue; /*处理数据请求的队列*/ /*设置磁盘结构 capacity 的容量*/ /*注意: 块设备的大小使用扇区作为单位设置,而扇区的大小默认是512字节。 cat /sys/block/xxxx/size 可以查看到设置的大小 把字节为单位的大小转换为以扇区为单位时,我们需要除以512,或者右移9位 */ set_capacity(tiny4412_blkdev_disk,TINY4412_BLK_DEV_BYTES>>9); //添加磁盘信息到内核 add_disk(tiny4412_blkdev_disk); return 0;}
static void __exit tiny4412_blkdev_exit(void) { //删除磁盘 del_gendisk(tiny4412_blkdev_disk); put_disk(tiny4412_blkdev_disk); //清除队列 blk_cleanup_queue(tiny4412_blkdev_queue); /*注销块设备*/ unregister_blkdev(Tiny4412_block_major, "Tiny4412_block"); vfree(sizeof_p);}
module_init(tiny4412_blkdev_init); module_exit(tiny4412_blkdev_exit);MODULE_LICENSE("GPL");
评论