[dm-devel] virtual device driver for help

烁 吕 lv_shuo at yahoo.com.cn
Wed Nov 14 02:30:33 UTC 2007


I am implementing a virtual device driver for learning purpose,now i find it's performance is bad,i cann't get reason for it. I read the raid0 source code,you are the author,please you help me.
   
  disk read /dev/vbd(virtual)  
  [root at server_1 vbd_test_7]# dd if=/dev/vbd0 of=/dev/zero count=1000000 bs=1k
1000000+0 records in
1000000+0 records out
1024000000 bytes (1.0 GB) copied, 15.8438 seconds, 64.6 MB/s
   
  [root at server_1 vbd_test_7]# dd if=/dev/sdb of=/dev/zero count=1000000 bs=1k
1000000+0 records in
1000000+0 records out
1024000000 bytes (1.0 GB) copied, 6.18553 seconds, 166 MB/s
   
  what make the performance difference? 
   
   
  code:
   
  MODULE_LICENSE("Dual BSD/GPL");
  static int vbd_major = 0;
module_param(vbd_major, int, 0);
static int hardsect_size = 512;
module_param(hardsect_size, int, 0);
static int nsectors = 1024*1024*2; /* How big the drive is */
module_param(nsectors, int, 0);
  #define WINDOWS_ROBOT_NUM  4
#define SNOPSHOT_EACH_WINDOWS_ROBOT 4

static int ndevices = 1;
module_param(ndevices, int, 0);
  /*
 * We can tweak our hardware sector size, but the kernel talks to us
 * in terms of small sectors, always.
 */
#define KERNEL_SECTOR_SIZE 512
#define VBD_MINORS           1
  /*
 * The internal representation of our device.
 */
struct vbd_dev 
{
    short users;                    /* How many users */
    short media_change;             /* Flag a media change? */
    spinlock_t lock;                /* For mutual exclusion */
    struct request_queue *queue;    /* The device request queue */
    struct gendisk *gd;             /* The gendisk structure */
};
  typedef struct vbd_dev vbd_dev_t ;
static vbd_dev_t *Devices = NULL;
  static struct block_device *bdev = NULL;
  
static int vbd_endio(struct bio* bio,unsigned int done,int error)
{
 struct bio*  ori_bio;
 ori_bio = bio->bi_private;
   //printk(KERN_INFO"clone_endio:%d\n",ori_bio->bi_size);
 bio_endio(ori_bio,ori_bio->bi_size,error);
 //printk(KERN_INFO"clone_endio\n");
  bio_put(bio);
   return 0;
}
  
static int vbd_make_request(request_queue_t *q, struct bio *bio)
{
 //struct bio_vec *bvec;
 struct bio* newbio;
 
 
 //sector_t sector = bio->bi_sector;
 //sector_t total_sector_num = 0;
 //int i;
  #if 0
 printk("********************start*************************\n");
 if(bio->bi_sector%8!=0)printk("**************what we need happen*********\n");
 printk("bio->bi_sector=%d\n",bio->bi_sector);
 printk("bio->bi_vcnt=%d\n",bio->bi_vcnt);
 printk("bio->bi_idx=%d\n",bio->bi_idx);
 printk("bio->bi_max_vecs=%d\n",bio->bi_max_vecs);
 printk("bio->bi_size=%d secotrs\n",(bio->bi_size)>>9); 
 for(i=0;i<bio->bi_vcnt;i++)
 {
  total_sector_num+=(bio->bi_io_vec[i].bv_len)>>9;
  printk("total sector num =%d\n",total_sector_num);
 }
 printk("********************finish*************************\n");
#endif 
  
 newbio = bio_clone(bio,GFP_NOIO); 
 newbio->bi_bdev = bdev;
 newbio->bi_end_io = vbd_endio;
 newbio->bi_private = bio; 
   newbio->bi_flags &= ~(1 << BIO_SEG_VALID);
 printk(KERN_INFO"newbio->bi_flags=%d\n",newbio->bi_flags);
 printk(KERN_INFO"bio->bi_flags=%d\n",bio->bi_flags); 
 generic_make_request(newbio); 
   return 0;
}
  
/*
 * Open and close.
 */
  static int vbd_open(struct inode *inode, struct file *filp)
{
   // static int i=10;
 vbd_dev_t *vbd_dev = inode->i_bdev->bd_disk->private_data;
 dev_t  testdev;
   filp_open("/dev/sdb",O_RDWR,0);
  
 printk("********************start*************************\n");
 testdev = MKDEV(8,16);
 bdev = bdget(testdev);
 if(bdev==NULL)
 {
  printk(KERN_INFO"notice:null device**********\n");
  return 0;
 }
  
 filp->private_data = vbd_dev;
 spin_lock(&vbd_dev->lock);
 if (! vbd_dev->users) 
 {
  check_disk_change(inode->i_bdev);
 }
 vbd_dev->users++;
 spin_unlock(&vbd_dev->lock);
 return 0;
}
  
static int vbd_release(struct inode *inode, struct file *filp)
{
 struct vbd_dev *dev = inode->i_bdev->bd_disk->private_data;
   spin_lock(&dev->lock);
 dev->users--;
 spin_unlock(&dev->lock);
   return 0;
}
  /*
 * Look for a (simulated) media change.
 */
int vbd_media_changed(struct gendisk *gd)
{
 struct vbd_dev *dev = gd->private_data;
 
 return dev->media_change;
}
  /*
 * Revalidate.  WE DO NOT TAKE THE LOCK HERE, for fear of deadlocking
 * with open.  That needs to be reevaluated.
 */
int vbd_revalidate(struct gendisk *gd)
{
 struct vbd_dev *dev = gd->private_data;
 
 if (dev->media_change) 
 {
  dev->media_change = 0;  
 }
 return 0;
}
   
  /*
 * The ioctl() implementation
 */
  int vbd_ioctl (struct inode *inode, struct file *filp,
                 unsigned int cmd, unsigned long arg)
{
   struct hd_geometry geo;
 //struct vbd_dev *dev = filp->private_data;
    //static int i=0;
 
 switch(cmd) {
     case HDIO_GETGEO:
         /*
   * Get geometry: since we are a virtual device, we have to make
   * up something plausible.  So we claim 16 sectors, four heads,
   * and calculate the corresponding number of cylinders.  We set the
   * start of data at sector four.
   */
    geo.heads = 4;
  geo.sectors = 16;
  geo.start = 4;
  if (copy_to_user((void __user *) arg, &geo, sizeof(geo)))
   return -EFAULT;
  return 0;
 }
 printk(KERN_INFO"ioctl:%d\n",cmd);
 
 return -ENOTTY; /* unknown command */
}
   
  /*
 * The device operations structure.
 */
static struct block_device_operations vbd_ops = {
 .owner           = THIS_MODULE,
 .open           = vbd_open,
 .release   = vbd_release,
 .media_changed   = vbd_media_changed,
 .revalidate_disk = vbd_revalidate,
 .ioctl          = vbd_ioctl
};
  
/*
 * Set up our internal device.
 */
static void setup_device(struct vbd_dev *dev, int which)
{
 /*
  * Get some memory.
  */
 memset (dev, 0, sizeof (struct vbd_dev));
 spin_lock_init(&dev->lock);
   dev->queue = blk_alloc_queue(GFP_KERNEL);
 if (dev->queue == NULL)
  return;
   /**/
 blk_queue_make_request(dev->queue, vbd_make_request);
  
 blk_queue_hardsect_size(dev->queue, hardsect_size);
 dev->queue->queuedata = dev;
   /*
  * And the gendisk structure.we just want 1 minor here
  */
 dev->gd = alloc_disk(VBD_MINORS);
 if (! dev->gd) 
 {
  printk (KERN_NOTICE "alloc_disk failure\n");
  return;
 }
   /*
  * Set some other parameters
  */
 dev->gd->major = vbd_major;
 dev->gd->first_minor = which*VBD_MINORS;
 dev->gd->fops = &vbd_ops;
 dev->gd->queue = dev->queue;
 dev->gd->private_data = dev;
 snprintf (dev->gd->disk_name, 32, "vbd%d", which );
 set_capacity(dev->gd, nsectors*(hardsect_size/KERNEL_SECTOR_SIZE));
 add_disk(dev->gd);
 return;
 
}
   
  static int __init vbd_init(void)
{
 int i;
 /*
  * Get registered.
  */
 vbd_major = register_blkdev(vbd_major, "vbd");
 if (vbd_major <= 0) {
  printk(KERN_WARNING "vbd: unable to get major number\n");
  return -EBUSY;
 }
 /*
  * Allocate the device array, and initialize each one.
  */
 Devices = kmalloc(ndevices*sizeof (struct vbd_dev), GFP_KERNEL);
 if (Devices == NULL)
 {
  goto out_unregister;
 }
 for (i = 0; i < ndevices; i++) 
 {
  setup_device(Devices + i, i);
 }
    
 return 0;
    out_unregister:
 unregister_blkdev(vbd_major, "vbd");
 return -ENOMEM;
}
  static void vbd_exit(void)
{
 int i;
   for (i = 0; i < ndevices; i++) 
 {
  struct vbd_dev *dev = Devices + i;
  if (dev->gd) 
  {
   del_gendisk(dev->gd);
   put_disk(dev->gd);
  }
  if (dev->queue) 
  {
   blk_cleanup_queue(dev->queue);
  }   
 }
 unregister_blkdev(vbd_major, "vbd");
 kfree(Devices);
}
 
module_init(vbd_init);
module_exit(vbd_exit

       
---------------------------------
 @yahoo.cn 新域名、无限量,快来抢注!
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://listman.redhat.com/archives/dm-devel/attachments/20071114/fa0fdb0e/attachment.htm>


More information about the dm-devel mailing list