Chinaunix首页 | 论坛 | 博客
  • 博客访问: 93607
  • 博文数量: 16
  • 博客积分: 359
  • 博客等级: 一等列兵
  • 技术积分: 279
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-24 22:08
文章分类
文章存档

2014年(3)

2012年(13)

我的朋友

分类: LINUX

2012-03-28 12:35:47

2012年3月25日  Sunday
 
1、内核版本号2.6.33.20
 
2、make_request()创建RAM DISK实例
 
1)block_device_operations
①struct block_device_operations在2.6.28开始发生很大变化
在上找到的英文说明
 
The block driver API has changed considerably, with the inode and file parameters being removed from most block device operations. The new API looks like this:
 
struct block_device_operations {
 int (*open) (struct block_device *bdev, fmode_t mode);
 int (*release) (struct gendisk *gd, fmode_t mode);
 int (*locked_ioctl) (struct block_device *bdev, fmode_t mode,
            unsigned cmd, unsigned long arg);
 int (*ioctl) (struct block_device *bdev, fmode_t mode,
            unsigned cmd, unsigned long arg);
 int (*compat_ioctl) (struct block_device *bdev, fmode_t mode,
            unsigned cmd, unsigned long arg);
 int (*direct_access) (struct block_device *bdev, sector_t sector,
         void **kaddr, unsigned long *pfn);
 int (*media_changed) (struct gendisk *gd);
 int (*revalidate_disk) (struct gendisk *gd);
 int (*getgeo)(struct block_device *bdev, struct hd_geometry *geo);
 struct module *owner;
};

The new prototypes do away with the file and inode structure pointers which were passed in previous kernels. Note that the ioctl() method is now called without the big kernel lock; code needing BKL protection must explicitly define a locked_ioctl() function instead.
 
在2.6.28之前的struct block_device_operations结构体

点击(此处)折叠或打开

  1. struct block_device_operations {
  2.         int (*open) (struct inode *, struct file *);
  3.         int (*release) (struct inode *, struct file *);
  4.         int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long);
  5.         long (*unlocked_ioctl) (struct file *, unsigned, unsigned long);
  6.         long (*compat_ioctl) (struct file *, unsigned, unsigned long);
  7.         int (*direct_access) (struct block_device *, sector_t,
  8.                                                 void **, unsigned long *);
  9.         int (*media_changed) (struct gendisk *);
  10.         int (*revalidate_disk) (struct gendisk *);
  11.         int (*getgeo)(struct block_device *, struct hd_geometry *);
  12.         struct module *owner;
  13. };

从2.6.28开始的struct block_device_operations结构体

点击(此处)折叠或打开

  1. struct block_device_operations {
  2.         int (*open) (struct block_device *, fmode_t);
  3.         int (*release) (struct gendisk *, fmode_t);
  4.         int (*locked_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
  5.         int (*ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
  6.         int (*compat_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
  7.         int (*direct_access) (struct block_device *, sector_t,
  8.                                                 void **, unsigned long *);
  9.         int (*media_changed) (struct gendisk *);
  10.         int (*revalidate_disk) (struct gendisk *);
  11.         int (*getgeo)(struct block_device *, struct hd_geometry *);
  12.         struct module *owner;
  13. };

参数的变化比较大,具体使用要去看源码了
②blk_queue_make_request(struct request_queue *, make_request_fn *)
在内核2.6.33.20该函数中后面的make_request_fn函数参数的原型与书中2.6.4也有所不同
 
书中(2.6.4)的定义
typedef int (make_request_fn) (request_queue_t *q, struct bio *bio);
typedef struct request_queue request_queue_t;
 
2.6.33.20中的定义
typedef int (make_request_fn) (struct request_queue *q, struct bio *bio);
 
可以看到其实原型内容是没有变化的,只是先前版本对request_queue进行了新的类型声明
(没有看更深层的代码,不知道内部是否有变化)
 
实例中make_request_fn函数中要用到bio_endio()和bio_io_error()两个函数
其在2.6.33.20原型与在书中原型的参数个数不同
 
在书中(2.6.4)两个函数的原型
void bio_endio(struct bio *bio, unsigned int bytes_done, int error)
#define bio_io_error(bio, bytes) bio_endio((bio), (bytes), -EIO)
 
在2.6.33.20两个函数的原型
void bio_endio(struct bio *bio, int error)
#define bio_io_error(bio) bio_endio((bio), -EIO)
2)修改书中实例代码
①书中实例代码(2.6.4)

点击(此处)折叠或打开

  1. #include <linux/init.h>
  2. #include <linux/kernel.h>
  3. #include <linux/module.h>

  4. #include <linux/fs.h>
  5. #include <linux/errno.h>
  6. #include <linux/types.h>
  7. #include <linux/fcntl.h>
  8. #include <linux/vmalloc.h>
  9. #include <linux/hdreg.h>
  10. #include <linux/blkdev.h>
  11. #include <linux/blkpg.h>
  12. #include <asm/uaccess.h>

  13. #define VRD_DEV_NAME "vrd"
  14. #define VRD_DEV_MAJOR "240"

  15. #define VRD_MAX_DEVICE 2

  16. #define VRD_SECTOR_SIZE 512
  17. #define VRD_SIZE (4*1024*1024)
  18. #define VRD_SECTOR_TOTAL (VRD_SIZE/VRD_SECTOR_SIZE)

  19. typedef struct{
  20.     unsigned char *data;
  21.     struct request_queue *queue;
  22.     struct gendisk *gd;
  23. }vrd_device;

  24. static char *vdisk[VRD_MAX_DEVICE];
  25. static vrd_device device[VRD_MAX_DEVICE];

  26. static int vrd_make_request(request_queue_t *q,struct bio *bio)
  27. {
  28.     vrd_device *pdevice;
  29.     char *pVHDDDdata;
  30.     char *pBuffer;
  31.     struct bio_vec *bvec;
  32.     int i;
  33.     
  34.     if(((bio-bi_sector*VRD_SECTOR_SIZE)+bio->bi_size)>VRD_SIZE){
  35.         goto fail;
  36.     }
  37.     
  38.     pdevice=(vrd_device *)bio->bi_bdev->bd_disk->private_data;
  39.     pVHDDDdata=private_data+(bio->bi_sector*VRD_SECTOR_SIZE);
  40.     
  41.     bio_for_each_segment(bvec,bio,i)
  42.     {
  43.         pBuffer=kmap(bev->bv_page)+bvec->bv_offset;
  44.         switch(bio_data_dir(bio))
  45.         {
  46.             case READA:
  47.             case READ:memcpy(pBuffer,pVHDDData,bvec->bv_len);break;
  48.             case WRITE:memcpy(pVHDDData,pBuffer,bvec->bv_len);break;
  49.             default:kunmap(bvec->bv_page);goto fail;
  50.         }
  51.         kunmap(bvec->bv_page);
  52.         pVHDDData+=bvec->bv_len;
  53.     }
  54.     bio_endio(bio,bio->bi_size,0);
  55.     return 0;
  56. fail:
  57.     bio_io_error(bio,bio->bi_size);
  58.     return 0;
  59. }

  60. int vrd_open(struct inode *inode,struct file *filp)
  61. {
  62.     return 0;
  63. }
  64. int vrd_release(struct inode *inode,struct file *filp)
  65. {
  66.     return 0;
  67. }

  68. int vrd_ioctl(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg)
  69. {
  70.     return -ENOTTY;
  71. }

  72. static struct block_device_operations vrd_fops={
  73.     .owner=THIS_MODULE,
  74.     .open=vrd_open,
  75.     .release=vrd_release,
  76.     .ioctl=vrd_ioctl,
  77. };

  78. int vrd_init(void)
  79. {
  80.     int lp;
  81.     
  82.     vdisk[0]=vmalloc(VRD_SIZE);
  83.     vdisk[1]=vmalloc(VRD_SIZE);
  84.     
  85.     register_blkdev(VRD_DEV_MAJOR,VRD_DEV_NAME);
  86.     
  87.     for(lp=0;lp<VRD_MAX_DEVICE;lp++){
  88.         device[lp].data=vdisk[lp];
  89.         device[lp].gd=alloc_disk(1);
  90.         device[lp].queue=blk_alloc_queue(GFP_KERNEL);
  91.         blk_queue_make_request(device[lp].queue,&vrd_make_request);
  92.         
  93.         device[lp].gd->major=VRD_DEV_MAJOR;
  94.         device[lp].gd->first_minor=lp;
  95.         device[lp].gd->fops=&vrd_fops;
  96.         device[lp].gd->queue=device[lp].queue;
  97.         device[lp].gd->private_data=&device[lp];
  98.         sprintf(device[lp].gd->disk_name,"vrd%c",'a'+lp);
  99.         set_capacity(device[lp].gd,VRD_SECTOR_TOTAL);
  100.         
  101.         add_disk(device[lp].gd);
  102.     }
  103.     return 0;
  104. }

  105. void vrd_exit(void)
  106. {
  107.     int lp;
  108.     
  109.     for(lp=0;lp<VRD_MAX_DEVICE;lp++){
  110.         del_gendisk(device[lp].gd);
  111.         put_disk(device[lp].gd);
  112.     }
  113.     
  114.     unregister_blkdev(VRD_DEV_MAJOR,VRD_DEV_NAME);
  115.     
  116.     vfree(vdisk[0]);
  117.     vfree(vdisk[1]);
  118. }

  119. module_init(vrd_init);
  120. module_exit(vrd_exit);

  121. MODULE_LICENSE("Dual BSD/GPL");

②修改后实例代码
后面的mkrequest.c
3、驱动模块源文件mkrequest.c

点击(此处)折叠或打开

  1. #include <linux/init.h>
  2. #include <linux/kernel.h>
  3. #include <linux/module.h>

  4. #include <linux/fs.h>
  5. #include <linux/errno.h>
  6. #include <linux/types.h>
  7. #include <linux/fcntl.h>
  8. #include <linux/vmalloc.h>
  9. #include <linux/hdreg.h>
  10. #include <linux/blkdev.h>
  11. #include <linux/blkpg.h>
  12. #include <asm/uaccess.h>

  13. #define VRD_DEV_NAME "vrd"
  14. #define VRD_DEV_MAJOR 240

  15. #define VRD_MAX_DEVICE 2

  16. #define VRD_SECTOR_SIZE 512
  17. #define VRD_SIZE (4*1024*1024)
  18. #define VRD_SECTOR_TOTAL (VRD_SIZE/VRD_SECTOR_SIZE)

  19. typedef struct{
  20.     unsigned char *data;
  21.     struct request_queue *queue;
  22.     struct gendisk *gd;
  23. }vrd_device;

  24. static char *vdisk[VRD_MAX_DEVICE];
  25. static vrd_device device[VRD_MAX_DEVICE];

  26. static int vrd_make_request(struct request_queue *q,struct bio *bio)
  27. {
  28.     vrd_device *pdevice;
  29.     char *pVHDDData;
  30.     char *pBuffer;
  31.     struct bio_vec *bvec;
  32.     int i;
  33.     
  34.     if(((bio->bi_sector*VRD_SECTOR_SIZE)+bio->bi_size)>VRD_SIZE){
  35.         goto fail;
  36.     }
  37.     
  38.     pdevice=(vrd_device *)bio->bi_bdev->bd_disk->private_data;
  39.     pVHDDData=pdevice->data+(bio->bi_sector*VRD_SECTOR_SIZE);
  40.     
  41.     bio_for_each_segment(bvec,bio,i)
  42.     {
  43.         pBuffer=kmap(bvec->bv_page)+bvec->bv_offset;
  44.         switch(bio_data_dir(bio))
  45.         {
  46.             case READA:
  47.             case READ:memcpy(pBuffer,pVHDDData,bvec->bv_len);break;
  48.             case WRITE:memcpy(pVHDDData,pBuffer,bvec->bv_len);break;
  49.             default:kunmap(bvec->bv_page);goto fail;
  50.         }
  51.         kunmap(bvec->bv_page);
  52.         pVHDDData+=bvec->bv_len;
  53.     }
  54.     bio_endio(bio,0);
  55.     return 0;
  56. fail:
  57.     bio_io_error(bio);
  58.     return 0;
  59. }

  60. int vrd_open(struct block_device *bdev, fmode_t mode)
  61. {
  62.     return 0;
  63. }
  64. int vrd_release(struct gendisk *disk, fmode_t mode)
  65. {
  66.     return 0;
  67. }

  68. int vrd_ioctl(struct block_device *bdev, fmode_t mode,unsigned int cmd,unsigned long arg)
  69. {
  70.     return -ENOTTY;
  71. }

  72. static struct block_device_operations vrd_fops={
  73.     .owner=THIS_MODULE,
  74.     .open=vrd_open,
  75.     .release=vrd_release,
  76.     .ioctl=vrd_ioctl,
  77. };

  78. int vrd_init(void)
  79. {
  80.     int lp;
  81.     
  82.     vdisk[0]=vmalloc(VRD_SIZE);
  83.     vdisk[1]=vmalloc(VRD_SIZE);
  84.     
  85.     register_blkdev(VRD_DEV_MAJOR,VRD_DEV_NAME);
  86.     
  87.     for(lp=0;lp<VRD_MAX_DEVICE;lp++){
  88.         device[lp].data=vdisk[lp];
  89.         device[lp].gd=alloc_disk(1);
  90.         device[lp].queue=blk_alloc_queue(GFP_KERNEL);
  91.         blk_queue_make_request(device[lp].queue,&vrd_make_request);
  92.         
  93.         device[lp].gd->major=VRD_DEV_MAJOR;
  94.         device[lp].gd->first_minor=lp;
  95.         device[lp].gd->fops=&vrd_fops;
  96.         device[lp].gd->queue=device[lp].queue;
  97.         device[lp].gd->private_data=&device[lp];
  98.         sprintf(device[lp].gd->disk_name,"vrd%c",'a'+lp);
  99.         set_capacity(device[lp].gd,VRD_SECTOR_TOTAL);
  100.         
  101.         add_disk(device[lp].gd);
  102.     }
  103.     return 0;
  104. }

  105. void vrd_exit(void)
  106. {
  107.     int lp;
  108.     
  109.     for(lp=0;lp<VRD_MAX_DEVICE;lp++){
  110.         del_gendisk(device[lp].gd);
  111.         put_disk(device[lp].gd);
  112.     }
  113.     
  114.     unregister_blkdev(VRD_DEV_MAJOR,VRD_DEV_NAME);
  115.     
  116.     vfree(vdisk[0]);
  117.     vfree(vdisk[1]);
  118. }

  119. module_init(vrd_init);
  120. module_exit(vrd_exit);

  121. MODULE_LICENSE("Dual BSD/GPL");

4、Makefile

点击(此处)折叠或打开

  1. obj-m += mkrequest.o

  2. CURRENT_PATH := $(shell pwd)

  3. LINUX_KERNEL := $(shell uname -r)

  4. LINUX_KERNEL_PATH := /usr/src/linux-$(LINUX_KERNEL)

  5. all:
  6.     make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
  7. clean:
  8.     #make -C $(LINUX_KERNEL_PAHT) M=$(CURRENT_PATH) clean
  9.     rm *.mod.*
  10.     rm *.order
  11.     rm *.o
  12.     rm *.symvers

5、实施方法及运行结果

点击(此处)折叠或打开

  1. ~/make_request mknod /dev/vrd0 b 240 0
  2. ~/make_request mknod /dev/vrd1 b 240 1
  3. ~/make_request insmod mkrequest.ko
  4. ~/make_request lsmod |grep mkrequest
  5. mkrequest 1498 0

  6. ~/make_request mke2fs /dev/vrd0 //格式化RAMDISK
  7. mke2fs 1.41.11 (14-Mar-2010)
  8. Filesystem label=
  9. OS type: Linux
  10. Block size=1024 (log=0)
  11. Fragment size=1024 (log=0)
  12. Stride=0 blocks, Stripe width=0 blocks
  13. 1024 inodes, 4096 blocks
  14. 204 blocks (4.98%) reserved for the super user
  15. First data block=1
  16. Maximum filesystem blocks=4194304
  17. 1 block group
  18. 8192 blocks per group, 8192 fragments per group
  19. 1024 inodes per group

  20. Writing inode tables: done
  21. Writing superblocks and filesystem accounting information: done

  22. This filesystem will be automatically checked every 31 mounts or
  23. 180 days, whichever comes first. Use tune2fs -c or -i to override.

  24. ~/make_request# mkdir testdir
  25. ~/make_request mount /dev/vrd0 testdir/
  26. ~/make_request ls
  27. block_bak.c block.c block.ko file file(1).c file.c Makefile mkrequest.c mkrequest.ko

  28. testdir
  29. ~/make_request cd testdir/
  30. ~/make_request/testdir# ls
  31. lost+found
  32. ~/make_request/testdir# mkdir test
  33. ~/make_request/testdir# touch test.c
  34. ~/make_request/testdir# ls
  35. lost+found test test.c
  36. ~/make_request/testdir# cd test/
  37. ~/make_request/testdir/test# cd ..

6、移除模块及设备文件

  1. ~/make_request# umount testdir
  2. ~/make_request# umount rmmod mkrequest

阅读(2097) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~