现在开始试验: 编译和加载: # make make -C /lib/modules/2.6.27.4/build SUBDIRS=/mnt/host_test/simp_blkdev/simp_blkdev_step05 modules make[1]: Entering directory `/mnt/ltt-kernel‘ CC [M] /mnt/host_test/simp_blkdev/simp_blkdev_step05/simp_blkdev.o Building modules, stage 2. MODPOST 1 modules CC /mnt/host_test/simp_blkdev/simp_blkdev_step05/simp_blkdev.mod.o LD [M] /mnt/host_test/simp_blkdev/simp_blkdev_step05/simp_blkdev.ko make[1]: Leaving directory `/mnt/ltt-kernel‘ # insmod simp_blkdev.ko # 用fdisk打开设备文件 # fdisk /dev/simp_blkdev Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel Building a new DOS disklabel. Changes will remain in memory only, until you decide to write them. After that, of course, the previous content won‘t be recoverable.
Warning: invalid flag 0x0000 of partition table 4 will be corrected by w(rite)
Command (m for help): 看看设备的物理结构: Command (m for help): p
Disk /dev/simp_blkdev: 16 MB, 16777216 bytes 1 heads, 32 sectors/track, 1024 cylinders Units = cylinders of 32 * 512 = 16384 bytes
Device Boot Start End Blocks Id System
Command (m for help): 我们发现,现在的设备有1个磁头、32扇区每磁道、1024个磁道。 这是符合代码中的处理的。
申请内存的函数如下: int alloc_diskmem(void) { int ret; int i; void *p;
INIT_RADIX_TREE(&simp_blkdev_data, GFP_KERNEL);
for (i = 0; i < (SIMP_BLKDEV_BYTES + PAGE_SIZE - 1) >> PAGE_SHIFT; i++) { p = (void *)__get_free_page(GFP_KERNEL); if (!p) { ret = -ENOMEM; goto err_alloc; }
ret = radix_tree_insert(&simp_blkdev_data, i, p); if (IS_ERR_VALUE(ret)) goto err_radix_tree_insert; } return 0;
但为了表现出物理设备一次传送1个扇区数据的处理方式(这种情况下一个bio_vec可能会跨越2个以上的扇区),我们让代码支持2个以上页面的情况。 首先列出修改后的simp_blkdev_make_request()函数: static int simp_blkdev_make_request(struct request_queue *q, struct bio *bio) { struct bio_vec *bvec; int i; unsigned long long dsk_offset;
看样子长了一些,但不要被吓着了,因为读的时候我们可以对代码做一些简化: 1:去掉乱七八糟的出错处理 2:无视每行80字符限制 3:把比特运算改成等价但更易读的乘除运算 4:无视碍眼的类型转换 5:假设内核版本大于2.6.24,以去掉判断版本的宏 就会变成这样了: static int simp_blkdev_make_request(struct request_queue *q, struct bio *bio) { struct bio_vec *bvec; int i; unsigned long long dsk_offset;