Merge to Fedora kernel-2.6.17-1.2187_FC5 patched with stable patch-2.6.17.13-vs2...
[linux-2.6.git] / drivers / xen / blkfront / vbd.c
index b5f2b14..8aa453d 100644 (file)
@@ -7,8 +7,11 @@
  * Modifications by Mark A. Williamson are (c) Intel Research Cambridge
  * Copyright (c) 2004-2005, Christian Limpach
  * 
- * This file may be distributed separately from the Linux kernel, or
- * incorporated into other software packages, subject to the following license:
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
  * 
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this source file (the "Software"), to deal in the Software without
@@ -33,6 +36,9 @@
 #include <linux/blkdev.h>
 #include <linux/list.h>
 
+#define BLKIF_MAJOR(dev) ((dev)>>8)
+#define BLKIF_MINOR(dev) ((dev) & 0xff)
+
 /*
  * For convenience we distinguish between ide, scsi and 'other' (i.e.,
  * potentially combinations of the two) in the naming scheme and in a few other
 #define NUM_SCSI_MAJORS 9
 #define NUM_VBD_MAJORS 1
 
-struct lvdisk
-{
-    blkif_sector_t capacity; /*  0: Size in terms of 512-byte sectors.   */
-    blkif_vdev_t   device;   /*  8: Device number (opaque 16 bit value). */
-    u16            info; 
-    struct list_head list;
-};
-
 static struct xlbd_type_info xlbd_ide_type = {
-    .partn_shift = 6,
-    .partn_per_major = 2,
-    .devname = "ide",
-    .diskname = "hd",
+       .partn_shift = 6,
+       .disks_per_major = 2,
+       .devname = "ide",
+       .diskname = "hd",
 };
 
 static struct xlbd_type_info xlbd_scsi_type = {
-    .partn_shift = 4,
-    .partn_per_major = 16,
-    .devname = "sd",
-    .diskname = "sd",
+       .partn_shift = 4,
+       .disks_per_major = 16,
+       .devname = "sd",
+       .diskname = "sd",
 };
 
 static struct xlbd_type_info xlbd_vbd_type = {
-    .partn_shift = 4,
-    .partn_per_major = 16,
-    .devname = "xvd",
-    .diskname = "xvd",
+       .partn_shift = 4,
+       .disks_per_major = 16,
+       .devname = "xvd",
+       .diskname = "xvd",
 };
 
 static struct xlbd_major_info *major_info[NUM_IDE_MAJORS + NUM_SCSI_MAJORS +
-                                         NUM_VBD_MAJORS];
+                                        NUM_VBD_MAJORS];
 
-#define XLBD_MAJOR_IDE_START    0
-#define XLBD_MAJOR_SCSI_START   (NUM_IDE_MAJORS)
-#define XLBD_MAJOR_VBD_START    (NUM_IDE_MAJORS + NUM_SCSI_MAJORS)
+#define XLBD_MAJOR_IDE_START   0
+#define XLBD_MAJOR_SCSI_START  (NUM_IDE_MAJORS)
+#define XLBD_MAJOR_VBD_START   (NUM_IDE_MAJORS + NUM_SCSI_MAJORS)
 
-#define XLBD_MAJOR_IDE_RANGE    XLBD_MAJOR_IDE_START ... XLBD_MAJOR_SCSI_START - 1
-#define XLBD_MAJOR_SCSI_RANGE   XLBD_MAJOR_SCSI_START ... XLBD_MAJOR_VBD_START - 1
-#define XLBD_MAJOR_VBD_RANGE    XLBD_MAJOR_VBD_START ... XLBD_MAJOR_VBD_START + NUM_VBD_MAJORS - 1
+#define XLBD_MAJOR_IDE_RANGE   XLBD_MAJOR_IDE_START ... XLBD_MAJOR_SCSI_START - 1
+#define XLBD_MAJOR_SCSI_RANGE  XLBD_MAJOR_SCSI_START ... XLBD_MAJOR_VBD_START - 1
+#define XLBD_MAJOR_VBD_RANGE   XLBD_MAJOR_VBD_START ... XLBD_MAJOR_VBD_START + NUM_VBD_MAJORS - 1
 
 /* Information about our VBDs. */
 #define MAX_VBDS 64
-struct list_head vbds_list;
+static LIST_HEAD(vbds_list);
 
-struct request_queue *xlbd_blk_queue = NULL;
-
-#define MAJOR_XEN(dev) ((dev)>>8)
-#define MINOR_XEN(dev) ((dev) & 0xff)
-
-static struct block_device_operations xlvbd_block_fops = 
+static struct block_device_operations xlvbd_block_fops =
 {
-    .owner  = THIS_MODULE,
-    .open  = blkif_open,
-    .release = blkif_release,
-    .ioctl  = blkif_ioctl,
+       .owner = THIS_MODULE,
+       .open = blkif_open,
+       .release = blkif_release,
+       .ioctl  = blkif_ioctl,
+       .getgeo = blkif_getgeo
 };
 
-spinlock_t blkif_io_lock = SPIN_LOCK_UNLOCKED;
+DEFINE_SPINLOCK(blkif_io_lock);
 
-static struct lvdisk * xlvbd_device_alloc(void)
+static struct xlbd_major_info *
+xlbd_alloc_major_info(int major, int minor, int index)
 {
-    struct lvdisk *ret;
-
-    ret = kmalloc(sizeof(struct lvdisk), GFP_KERNEL);
-    if ( ret ) {
-        memset(ret, '\0', sizeof(struct lvdisk));
-        INIT_LIST_HEAD(&ret->list);
-    }
-    return ret;
+       struct xlbd_major_info *ptr;
+
+       ptr = kzalloc(sizeof(struct xlbd_major_info), GFP_KERNEL);
+       if (ptr == NULL)
+               return NULL;
+
+       ptr->major = major;
+
+       switch (index) {
+       case XLBD_MAJOR_IDE_RANGE:
+               ptr->type = &xlbd_ide_type;
+               ptr->index = index - XLBD_MAJOR_IDE_START;
+               break;
+       case XLBD_MAJOR_SCSI_RANGE:
+               ptr->type = &xlbd_scsi_type;
+               ptr->index = index - XLBD_MAJOR_SCSI_START;
+               break;
+       case XLBD_MAJOR_VBD_RANGE:
+               ptr->type = &xlbd_vbd_type;
+               ptr->index = index - XLBD_MAJOR_VBD_START;
+               break;
+       }
+
+       printk("Registering block device major %i\n", ptr->major);
+       if (register_blkdev(ptr->major, ptr->type->devname)) {
+               WPRINTK("can't get major %d with name %s\n",
+                       ptr->major, ptr->type->devname);
+               kfree(ptr);
+               return NULL;
+       }
+
+       devfs_mk_dir(ptr->type->devname);
+       major_info[index] = ptr;
+       return ptr;
 }
 
-static void xlvbd_device_free(struct lvdisk *disk)
+static struct xlbd_major_info *
+xlbd_get_major_info(int vdevice)
 {
-    list_del(&disk->list);
-    kfree(disk);
+       struct xlbd_major_info *mi;
+       int major, minor, index;
+
+       major = BLKIF_MAJOR(vdevice);
+       minor = BLKIF_MINOR(vdevice);
+
+       switch (major) {
+       case IDE0_MAJOR: index = 0; break;
+       case IDE1_MAJOR: index = 1; break;
+       case IDE2_MAJOR: index = 2; break;
+       case IDE3_MAJOR: index = 3; break;
+       case IDE4_MAJOR: index = 4; break;
+       case IDE5_MAJOR: index = 5; break;
+       case IDE6_MAJOR: index = 6; break;
+       case IDE7_MAJOR: index = 7; break;
+       case IDE8_MAJOR: index = 8; break;
+       case IDE9_MAJOR: index = 9; break;
+       case SCSI_DISK0_MAJOR: index = 10; break;
+       case SCSI_DISK1_MAJOR ... SCSI_DISK7_MAJOR:
+               index = 11 + major - SCSI_DISK1_MAJOR;
+               break;
+       case SCSI_CDROM_MAJOR: index = 18; break;
+       default: index = 19; break;
+       }
+
+       mi = ((major_info[index] != NULL) ? major_info[index] :
+             xlbd_alloc_major_info(major, minor, index));
+       if (mi)
+               mi->usage++;
+       return mi;
 }
 
-static vdisk_t * xlvbd_probe(int *ret)
+static void
+xlbd_put_major_info(struct xlbd_major_info *mi)
 {
-    blkif_response_t rsp;
-    blkif_request_t req;
-    vdisk_t *disk_info = NULL;
-    unsigned long buf;
-    int nr;
-
-    buf = __get_free_page(GFP_KERNEL);
-    if ( !buf )
-        goto out;
-
-    memset(&req, 0, sizeof(req));
-    req.operation = BLKIF_OP_PROBE;
-    req.nr_segments = 1;
-#ifdef CONFIG_XEN_BLKDEV_GRANT
-    blkif_control_probe_send(&req, &rsp,
-                             (unsigned long)(virt_to_machine(buf)));
-#else
-    req.frame_and_sects[0] = virt_to_machine(buf) | 7;
-
-    blkif_control_send(&req, &rsp);
-#endif
-    if ( rsp.status <= 0 ) {
-        printk(KERN_ALERT "Could not probe disks (%d)\n", rsp.status);
-        goto out;
-    }
-    nr = rsp.status;
-    if ( nr > MAX_VBDS )
-        nr = MAX_VBDS;
-
-    disk_info = kmalloc(nr * sizeof(vdisk_t), GFP_KERNEL);
-    if ( disk_info )
-        memcpy(disk_info, (void *) buf, nr * sizeof(vdisk_t));
-    if ( ret )
-        *ret = nr;
-out:
-    free_page(buf);
-    return disk_info;
+       mi->usage--;
+       /* XXX: release major if 0 */
 }
 
-static struct xlbd_major_info *xlbd_alloc_major_info(int major, int minor, int index)
+static int
+xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size)
 {
-    struct xlbd_major_info *ptr;
-
-    ptr = kmalloc(sizeof(struct xlbd_major_info), GFP_KERNEL);
-    if ( !ptr )
-        return NULL;
-
-    memset(ptr, 0, sizeof(struct xlbd_major_info));
-
-    ptr->major = major;
-
-    switch (index) {
-    case XLBD_MAJOR_IDE_RANGE:
-        ptr->type = &xlbd_ide_type;
-        ptr->index = index - XLBD_MAJOR_IDE_START;
-        break;
-    case XLBD_MAJOR_SCSI_RANGE:
-        ptr->type = &xlbd_scsi_type;
-        ptr->index = index - XLBD_MAJOR_SCSI_START;
-        break;
-    case XLBD_MAJOR_VBD_RANGE:
-        ptr->type = &xlbd_vbd_type;
-        ptr->index = index - XLBD_MAJOR_VBD_START;
-        break;
-    }
-    
-    if ( register_blkdev(ptr->major, ptr->type->devname) ) {
-        printk(KERN_ALERT "XL VBD: can't get major %d with name %s\n",
-                    ptr->major, ptr->type->devname);
-        kfree(ptr);
-        return NULL;
-    }
-
-    devfs_mk_dir(ptr->type->devname);
-    major_info[index] = ptr;
-    return ptr;
-}
+       request_queue_t *rq;
 
-static struct xlbd_major_info *xlbd_get_major_info(int device)
-{
-    int major, minor, index;
-
-    major = MAJOR_XEN(device);
-    minor = MINOR_XEN(device);
-
-    switch (major) {
-    case IDE0_MAJOR: index = 0; break;
-    case IDE1_MAJOR: index = 1; break;
-    case IDE2_MAJOR: index = 2; break;
-    case IDE3_MAJOR: index = 3; break;
-    case IDE4_MAJOR: index = 4; break;
-    case IDE5_MAJOR: index = 5; break;
-    case IDE6_MAJOR: index = 6; break;
-    case IDE7_MAJOR: index = 7; break;
-    case IDE8_MAJOR: index = 8; break;
-    case IDE9_MAJOR: index = 9; break;
-    case SCSI_DISK0_MAJOR: index = 10; break;
-    case SCSI_DISK1_MAJOR ... SCSI_DISK7_MAJOR:
-        index = 11 + major - SCSI_DISK1_MAJOR;
-        break;
-    case SCSI_CDROM_MAJOR: index = 18; break;
-    default: index = 19; break;
-    }
-
-    return major_info[index]
-        ? major_info[index]
-        : xlbd_alloc_major_info(major, minor, index);
-}
+       rq = blk_init_queue(do_blkif_request, &blkif_io_lock);
+       if (rq == NULL)
+               return -1;
 
-static int xlvbd_blk_queue_alloc(struct xlbd_type_info *type)
-{
-    xlbd_blk_queue = blk_init_queue(do_blkif_request, &blkif_io_lock);
-    if ( !xlbd_blk_queue )
-        return -1;
-
-    elevator_init(xlbd_blk_queue, "noop");
-
-    /*
-    * Turn off barking 'headactive' mode. We dequeue
-    * buffer heads as soon as we pass them to back-end
-    * driver.
-    */
-    blk_queue_headactive(xlbd_blk_queue, 0);
-
-    /* Hard sector size and max sectors impersonate the equiv. hardware. */
-    blk_queue_hardsect_size(xlbd_blk_queue, 512);
-    blk_queue_max_sectors(xlbd_blk_queue, 512);
-
-    /* Each segment in a request is up to an aligned page in size. */
-    blk_queue_segment_boundary(xlbd_blk_queue, PAGE_SIZE - 1);
-    blk_queue_max_segment_size(xlbd_blk_queue, PAGE_SIZE);
-
-    /* Ensure a merged request will fit in a single I/O ring slot. */
-    blk_queue_max_phys_segments(xlbd_blk_queue, BLKIF_MAX_SEGMENTS_PER_REQUEST);
-    blk_queue_max_hw_segments(xlbd_blk_queue, BLKIF_MAX_SEGMENTS_PER_REQUEST);
-
-    /* Make sure buffer addresses are sector-aligned. */
-    blk_queue_dma_alignment(xlbd_blk_queue, 511);
-    return 0;
-}
+       elevator_init(rq, "noop");
 
-struct gendisk *xlvbd_alloc_gendisk(struct xlbd_major_info *mi, int minor,
-                    vdisk_t *disk)
-{
-    struct gendisk *gd;
-    struct xlbd_disk_info *di;
-    int nb_minors;
-
-    di = kmalloc(sizeof(struct xlbd_disk_info), GFP_KERNEL);
-    if ( !di )
-        goto out;
-    di->mi = mi;
-    di->xd_device = disk->device;
-
-    nb_minors = ((minor & ((1 << mi->type->partn_shift) - 1)) == 0)
-            ? mi->type->partn_per_major
-            : 1;
-
-    gd = alloc_disk(nb_minors);
-    if ( !gd )
-        goto out;
-
-    if ( nb_minors > 1 )
-        sprintf(gd->disk_name, "%s%c", mi->type->diskname,
-                'a' + mi->index * mi->type->partn_per_major +
-                    (minor >> mi->type->partn_shift));
-    else
-        sprintf(gd->disk_name, "%s%c%d", mi->type->diskname,
-                'a' + mi->index * mi->type->partn_per_major +
-                    (minor >> mi->type->partn_shift),
-                minor & ((1 << mi->type->partn_shift) - 1));
-
-    gd->major = mi->major;
-    gd->first_minor = minor;
-    gd->fops = &xlvbd_block_fops;
-    gd->private_data = di;
-    set_capacity(gd, disk->capacity);
-
-    if ( !xlbd_blk_queue )
-        if ( xlvbd_blk_queue_alloc(mi->type) )
-            goto out_gendisk;
-
-    gd->queue = xlbd_blk_queue;
-    add_disk(gd);
-    return gd;
-out_gendisk:
-    printk(KERN_ALERT "error gendisk\n");
-    del_gendisk(gd);
-out:
-    printk(KERN_ALERT "error out\n");
-    kfree(di);
-    return NULL;
-}
+       /* Hard sector size and max sectors impersonate the equiv. hardware. */
+       blk_queue_hardsect_size(rq, sector_size);
+       blk_queue_max_sectors(rq, 512);
 
-static int xlvbd_device_add(struct list_head *list, vdisk_t *disk)
-{
-    struct lvdisk *new;
-    int minor;
-    dev_t device;
-    struct block_device *bd;
-    struct gendisk *gd;
-    struct xlbd_major_info *mi;
-
-    mi = xlbd_get_major_info(disk->device);
-    if ( !mi )
-        return -EPERM;
-
-    new = xlvbd_device_alloc();
-    if ( !new )
-        return -1;
-    new->capacity = disk->capacity;
-    new->device = disk->device;
-    new->info = disk->info;
-    
-    minor = MINOR_XEN(disk->device);
-    device = MKDEV(mi->major, minor);
-    
-    bd = bdget(device);
-    if ( !bd )
-        goto out;
-    
-    gd = xlvbd_alloc_gendisk(mi, minor, disk);
-    if ( !gd )
-        goto out_bd;
-
-    if ( VDISK_READONLY(disk->info) )
-        set_disk_ro(gd, 1);
-
-    switch (VDISK_TYPE(disk->info)) {
-    case VDISK_TYPE_CDROM:
-        gd->flags |= GENHD_FL_REMOVABLE | GENHD_FL_CD;
-        break;
-    case VDISK_TYPE_FLOPPY: 
-    case VDISK_TYPE_TAPE:
-        gd->flags |= GENHD_FL_REMOVABLE;
-        break;
-    case VDISK_TYPE_DISK:
-        break;
-    default:
-        printk(KERN_ALERT "XenLinux: unknown device type %d\n",
-                        VDISK_TYPE(disk->info));
-        break;
-    }    
-
-    list_add(&new->list, list);
-out_bd:
-    bdput(bd);
-out:
-    return 0;
-}
+       /* Each segment in a request is up to an aligned page in size. */
+       blk_queue_segment_boundary(rq, PAGE_SIZE - 1);
+       blk_queue_max_segment_size(rq, PAGE_SIZE);
 
-static int xlvbd_device_del(struct lvdisk *disk)
-{
-    dev_t device;
-    struct block_device *bd;
-    struct gendisk *gd;
-    struct xlbd_disk_info *di;
-    int ret = 0, unused;
+       /* Ensure a merged request will fit in a single I/O ring slot. */
+       blk_queue_max_phys_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST);
+       blk_queue_max_hw_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST);
 
-    device = MKDEV(MAJOR_XEN(disk->device), MINOR_XEN(disk->device));
+       /* Make sure buffer addresses are sector-aligned. */
+       blk_queue_dma_alignment(rq, 511);
 
-    bd = bdget(device);
-    if ( !bd )
-        return -1;
+       gd->queue = rq;
 
-    gd = get_gendisk(device, &unused);
-    di = gd->private_data;
-
-    if ( di->mi->usage != 0 ) {
-        printk(KERN_ALERT "VBD removal failed: used [dev=%x]\n", device);
-        ret = -1;
-        goto out;
-    }
-
-    del_gendisk(gd);
-
-    xlvbd_device_free(disk);
-out:
-    bdput(bd);
-    return ret;
+       return 0;
 }
 
-static int xlvbd_device_update(struct lvdisk *ldisk, vdisk_t *disk)
+static int
+xlvbd_alloc_gendisk(int minor, blkif_sector_t capacity, int vdevice,
+                   u16 vdisk_info, u16 sector_size,
+                   struct blkfront_info *info)
 {
-    dev_t device;
-    struct block_device *bd;
-    struct gendisk *gd;
-    int unused;
-
-    if ( ldisk->capacity == disk->capacity && ldisk->info == disk->info )
-        return 0;    
+       struct gendisk *gd;
+       struct xlbd_major_info *mi;
+       int nr_minors = 1;
+       int err = -ENODEV;
+
+       BUG_ON(info->gd != NULL);
+       BUG_ON(info->mi != NULL);
+       BUG_ON(info->rq != NULL);
+
+       mi = xlbd_get_major_info(vdevice);
+       if (mi == NULL)
+               goto out;
+       info->mi = mi;
+
+       if ((minor & ((1 << mi->type->partn_shift) - 1)) == 0)
+               nr_minors = 1 << mi->type->partn_shift;
+
+       gd = alloc_disk(nr_minors);
+       if (gd == NULL)
+               goto out;
+
+       if (nr_minors > 1)
+               sprintf(gd->disk_name, "%s%c", mi->type->diskname,
+                       'a' + mi->index * mi->type->disks_per_major +
+                       (minor >> mi->type->partn_shift));
+       else
+               sprintf(gd->disk_name, "%s%c%d", mi->type->diskname,
+                       'a' + mi->index * mi->type->disks_per_major +
+                       (minor >> mi->type->partn_shift),
+                       minor & ((1 << mi->type->partn_shift) - 1));
+
+       gd->major = mi->major;
+       gd->first_minor = minor;
+       gd->fops = &xlvbd_block_fops;
+       gd->private_data = info;
+       gd->driverfs_dev = &(info->xbdev->dev);
+       set_capacity(gd, capacity);
+
+       if (xlvbd_init_blk_queue(gd, sector_size)) {
+               del_gendisk(gd);
+               goto out;
+       }
+
+       info->rq = gd->queue;
+
+       if (vdisk_info & VDISK_READONLY)
+               set_disk_ro(gd, 1);
+
+       if (vdisk_info & VDISK_REMOVABLE)
+               gd->flags |= GENHD_FL_REMOVABLE;
+
+       if (vdisk_info & VDISK_CDROM)
+               gd->flags |= GENHD_FL_CD;
+
+       info->gd = gd;
+
+       return 0;
+
+ out:
+       if (mi)
+               xlbd_put_major_info(mi);
+       info->mi = NULL;
+       return err;
+}
 
-    device = MKDEV(MAJOR_XEN(ldisk->device), MINOR_XEN(ldisk->device));
+int
+xlvbd_add(blkif_sector_t capacity, int vdevice, u16 vdisk_info,
+         u16 sector_size, struct blkfront_info *info)
+{
+       struct block_device *bd;
+       int err = 0;
 
-    bd = bdget(device);
-    if ( !bd )
-        return -1;
+       info->dev = MKDEV(BLKIF_MAJOR(vdevice), BLKIF_MINOR(vdevice));
 
-    gd = get_gendisk(device, &unused);
-    set_capacity(gd, disk->capacity);    
-    ldisk->capacity = disk->capacity;
+       bd = bdget(info->dev);
+       if (bd == NULL)
+               return -ENODEV;
 
-    bdput(bd);
+       err = xlvbd_alloc_gendisk(BLKIF_MINOR(vdevice), capacity, vdevice,
+                                 vdisk_info, sector_size, info);
 
-    return 0;
+       bdput(bd);
+       return err;
 }
 
-void xlvbd_refresh(void)
+void
+xlvbd_del(struct blkfront_info *info)
 {
-    vdisk_t *newdisks;
-    struct list_head *tmp, *tmp2;
-    struct lvdisk *disk;
-    int i, nr;
-
-    newdisks = xlvbd_probe(&nr);
-    if ( !newdisks ) {
-        printk(KERN_ALERT "failed to probe\n");
-        return;
-    }
-    
-    i = 0;
-    list_for_each_safe(tmp, tmp2, &vbds_list) {
-        disk = list_entry(tmp, struct lvdisk, list);
-        
-        for (i = 0; i < nr; i++) {
-            if ( !newdisks[i].device )
-                continue;
-            if ( disk->device == newdisks[i].device ) {
-                xlvbd_device_update(disk, &newdisks[i]);
-                newdisks[i].device = 0;
-                break;
-            }
-        }
-        if ( i == nr ) {
-            xlvbd_device_del(disk);
-            newdisks[i].device = 0;
-        }
-    }
-    for (i = 0; i < nr; i++)
-        if ( newdisks[i].device )
-            xlvbd_device_add(&vbds_list, &newdisks[i]);
-    kfree(newdisks);
-}
+       if (info->mi == NULL)
+               return;
 
-/*
- * xlvbd_update_vbds - reprobes the VBD status and performs updates driver
- * state. The VBDs need to be updated in this way when the domain is
- * initialised and also each time we receive an XLBLK_UPDATE event.
- */
-void xlvbd_update_vbds(void)
-{
-    xlvbd_refresh();
-}
+       BUG_ON(info->gd == NULL);
+       del_gendisk(info->gd);
+       put_disk(info->gd);
+       info->gd = NULL;
 
-/*
- * Set up all the linux device goop for the virtual block devices
- * (vbd's) that we know about. Note that although from the backend
- * driver's p.o.v. VBDs are addressed simply an opaque 16-bit device
- * number, the domain creation tools conventionally allocate these
- * numbers to correspond to those used by 'real' linux -- this is just
- * for convenience as it means e.g. that the same /etc/fstab can be
- * used when booting with or without Xen.
- */
-int xlvbd_init(void)
-{
-    int i, nr;
-    vdisk_t *disks;
-
-    INIT_LIST_HEAD(&vbds_list);
-
-    memset(major_info, 0, sizeof(major_info));
-    
-    disks = xlvbd_probe(&nr);
-    if ( !disks ) {
-        printk(KERN_ALERT "failed to probe\n");
-        return -1;
-    }
-
-    for (i = 0; i < nr; i++)
-        xlvbd_device_add(&vbds_list, &disks[i]);
-    kfree(disks);
-    return 0;
+       xlbd_put_major_info(info->mi);
+       info->mi = NULL;
+
+       BUG_ON(info->rq == NULL);
+       blk_cleanup_queue(info->rq);
+       info->rq = NULL;
 }