idclei 发表于 2009-11-24 11:15

这样转发一个bio请求行不行?

大家好!根据论坛中一个兄弟的程序,我改写了下,实现了在内存中建立一个块设备驱动,现在想simp_blkdev_make_request函数中拷贝一个bio结构到/dev/sda2分区中(也就是将数据请求在/dev/sda2上也存储一份),下面程序不知道是否可行,我insmod后,老是死机。如果这样做不行,请问要实现这样一个功能,该如何做呢 谢谢!代码如下:


#include <linux/string.h>
#include <linux/genhd.h>
#include <linux/blkdev.h>
#include <linux/module.h>         //同kernel.h,最基本的内核模块头文件
#include <linux/kernel.h>                  //同module.h,最基本的内核模块头文件
#include <linux/sched.h>          //这里包含了进行正确性检查的宏
#include <linux/fs.h>             //文件系统所必需的头文件
#include <asm/uaccess.h>          //这里包含了内核空间与用户空间进行数据交换时的函数宏
#include <asm/io.h>               //I/O访问

#define SIMP_BLKDEV_DEVICEMAJOR      COMPAQ_SMART2_MAJOR
#define SIMP_BLKDEV_DISKNAME      "simp_blkdev"
#define SIMP_BLKDEV_BYTES      (16*1024*1024)

#define SIMP_BLKDEV_MAXPARTITIONS (2)
static struct request_queue *simp_blkdev_queue;
static struct gendisk *simp_blkdev_disk;
unsigned char simp_blkdev_data;


static void simp_blkdev_do_request(struct request_queue *q);
static int simp_blkdev_make_request(struct request_queue *q,struct bio *bio);
struct block_device_operations simp_blkdev_fops = {
      .owner                = THIS_MODULE,
};

static int __init simp_blkdev_init(void)
{
      int ret;
       // simp_blkdev_queue = blk_init_queue(simp_blkdev_do_request, NULL);
      
      simp_blkdev_queue = blk_alloc_queue(GFP_KERNEL);
       
        if (!simp_blkdev_queue) {
                ret = -ENOMEM;
                goto err_init_queue;
      }
      blk_queue_make_request(simp_blkdev_queue,simp_blkdev_make_request);
        simp_blkdev_disk = alloc_disk(SIMP_BLKDEV_MAXPARTITIONS);
      if (!simp_blkdev_disk) {
                ret = -ENOMEM;
                goto err_alloc_disk;
      }
      strcpy(simp_blkdev_disk->disk_name,SIMP_BLKDEV_DISKNAME);
      simp_blkdev_disk->major = SIMP_BLKDEV_DEVICEMAJOR;
      simp_blkdev_disk->first_minor = 0;
      simp_blkdev_disk->fops = &simp_blkdev_fops;
      simp_blkdev_disk->queue = simp_blkdev_queue;
      set_capacity(simp_blkdev_disk, SIMP_BLKDEV_BYTES>>9);
      add_disk(simp_blkdev_disk);

      return 0;

err_alloc_disk:
      blk_cleanup_queue(simp_blkdev_queue);
err_init_queue:
      return ret;
}

static void __exit simp_blkdev_exit(void)
{
      del_gendisk(simp_blkdev_disk);
      put_disk(simp_blkdev_disk);
      blk_cleanup_queue(simp_blkdev_queue);
}


static int simp_blkdev_make_request(struct request_queue *q,struct bio *bio)
{
        struct bio_vec *bvec;
       
               
        int i;
        void *dsk_mem;
       
        if((bio->bi_sector<<9)+bio->bi_size>SIMP_BLKDEV_BYTES)
        {
               printk(KERN_ERR SIMP_BLKDEV_DISKNAME ": bad request: block=%llu, count=%u \n",(unsigned long long)bio->bi_sector, bio->bi_size);
                #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
                        bio_endio(bio, 0, -EIO);
                #else
                        bio_endio(bio, -EIO);
                #endif
                return 0;
   }
       dsk_mem = simp_blkdev_data + (bio->bi_sector << 9);

               //下面这几行打算实现重定向功能
       struct file *file;
       file = filp_open("/dev/sda2",O_RDWR,0);       
       struct inode *i_node=file->f_dentry->d_inode;
       if(i_node!=NULL){
               struct block_device *bi_dev=i_node->i_bdev;
               struct bio *mbio;
               mbio = bio_clone(bio, GFP_NOIO);
               //mbio->bi_sector        = r1_bio->sector + conf->mirrors.rdev->data_offset;
               mbio->bi_bdev = bi_dev;
               generic_make_request(bio);

               printk("open block_device success!\n");

       } //重定向功能完成


       //下面是正常的数据读写
      bio_for_each_segment(bvec, bio, i) {
                void *iovec_mem;

                switch (bio_rw(bio)) {
                case READ:
                case READA:
                        iovec_mem = kmap(bvec->bv_page) + bvec->bv_offset;
                        memcpy(iovec_mem, dsk_mem, bvec->bv_len);
                        kunmap(bvec->bv_page);
                        break;
                case WRITE:
                        iovec_mem = kmap(bvec->bv_page) + bvec->bv_offset;
                        memcpy(dsk_mem, iovec_mem, bvec->bv_len);
                        kunmap(bvec->bv_page);
                        break;
                default:
                        printk(KERN_ERR SIMP_BLKDEV_DISKNAME": unknown value of bio_rw: %lu\n",bio_rw(bio));
                                #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
                        bio_endio(bio, 0, -EIO);
                                #else
                        bio_endio(bio, -EIO);
                                #endif
                        return 0;
                }
                dsk_mem += bvec->bv_len;
      }
               
        #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
      bio_endio(bio, bio->bi_size, 0);
        #else
      bio_endio(bio, 0);
        #endif
      return 0;

}


module_init(simp_blkdev_init);
module_exit(simp_blkdev_exit);

[ 本帖最后由 idclei 于 2009-11-25 09:36 编辑 ]
页: [1]
查看完整版本: 这样转发一个bio请求行不行?