#include <linux/config.h>
#include <linux/version.h>
#include <linux/module.h>
-#include <linux/rbtree.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/blkdev.h>
#define DPRINTK(_f, _a...) ((void)0)
#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-typedef struct rb_root rb_root_t;
-typedef struct rb_node rb_node_t;
-#else
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
struct block_device;
#endif
+struct vbd {
+ blkif_vdev_t handle; /* what the domain refers to this vbd as */
+ unsigned char readonly; /* Non-zero -> read-only */
+ unsigned char type; /* VDISK_xxx */
+ blkif_pdev_t pdevice; /* phys device that this vbd maps to */
+ struct block_device *bdev;
+
+ int active;
+};
+
typedef struct blkif_st {
/* Unique identifier for this interface. */
domid_t domid;
/* Comms information. */
blkif_back_ring_t blk_ring;
/* VBDs attached to this interface. */
- struct vbd *vbd;
+ struct vbd vbd;
/* Private fields. */
enum { DISCONNECTED, CONNECTED } status;
/*
spinlock_t blk_ring_lock;
atomic_t refcnt;
- struct work_struct work;
+ struct work_struct free_work;
u16 shmem_handle;
unsigned long shmem_vaddr;
grant_ref_t shmem_ref;
int blkif_disconnect(blkif_be_disconnect_t *disconnect, u8 rsp_id);
void blkif_disconnect_complete(blkif_t *blkif);
blkif_t *alloc_blkif(domid_t domid);
-void free_blkif(blkif_t *blkif);
+void free_blkif_callback(blkif_t *blkif);
int blkif_map(blkif_t *blkif, unsigned long shared_page, unsigned int evtchn);
#define blkif_get(_b) (atomic_inc(&(_b)->refcnt))
#define blkif_put(_b) \
do { \
if ( atomic_dec_and_test(&(_b)->refcnt) ) \
- free_blkif(_b); \
+ free_blkif_callback(_b); \
} while (0)
-struct vbd;
-void vbd_free(blkif_t *blkif, struct vbd *vbd);
-
/* Creates inactive vbd. */
-struct vbd *vbd_create(blkif_t *blkif, blkif_vdev_t vdevice, blkif_pdev_t pdevice, int readonly);
+int vbd_create(blkif_t *blkif, blkif_vdev_t vdevice, blkif_pdev_t pdevice,
+ int readonly);
int vbd_is_active(struct vbd *vbd);
-void vbd_activate(blkif_t *blkif, struct vbd *vbd);
+void vbd_activate(struct vbd *vbd);
+void vbd_free(struct vbd *vbd);
unsigned long vbd_size(struct vbd *vbd);
unsigned int vbd_info(struct vbd *vbd);
return 0;
}
-void free_blkif(blkif_t *blkif)
+static void free_blkif(void *arg)
{
evtchn_op_t op = { .cmd = EVTCHNOP_close };
+ blkif_t *blkif = (blkif_t *)arg;
op.u.close.port = blkif->evtchn;
op.u.close.dom = DOMID_SELF;
op.u.close.dom = blkif->domid;
HYPERVISOR_event_channel_op(&op);
+ if (vbd_is_active(&blkif->vbd))
+ vbd_free(&blkif->vbd);
+
if (blkif->evtchn)
unbind_evtchn_from_irqhandler(blkif->evtchn, blkif);
kmem_cache_free(blkif_cachep, blkif);
}
+void free_blkif_callback(blkif_t *blkif)
+{
+ INIT_WORK(&blkif->free_work, free_blkif, (void *)blkif);
+ schedule_work(&blkif->free_work);
+}
+
void __init blkif_interface_init(void)
{
blkif_cachep = kmem_cache_create("blkif_cache", sizeof(blkif_t),
#include "common.h"
#include <asm-xen/xenbus.h>
-struct vbd {
- blkif_vdev_t handle; /* what the domain refers to this vbd as */
- unsigned char readonly; /* Non-zero -> read-only */
- unsigned char type; /* VDISK_xxx */
- blkif_pdev_t pdevice; /* phys device that this vbd maps to */
- struct block_device *bdev;
-
- int active;
-};
-
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
static inline dev_t vbd_map_devnum(blkif_pdev_t cookie)
{
return vbd->active;
}
-struct vbd *vbd_create(blkif_t *blkif, blkif_vdev_t handle,
- blkif_pdev_t pdevice, int readonly)
+int vbd_create(blkif_t *blkif, blkif_vdev_t handle,
+ blkif_pdev_t pdevice, int readonly)
{
- struct vbd *vbd, *err;
-
- if ( unlikely((vbd = kmalloc(sizeof(struct vbd), GFP_KERNEL)) == NULL) )
- {
- DPRINTK("vbd_create: out of memory\n");
- return ERR_PTR(-ENOMEM);
- }
+ struct vbd *vbd;
- blkif->vbd = vbd;
+ vbd = &blkif->vbd;
vbd->handle = handle;
vbd->readonly = readonly;
vbd->type = 0;
if ( IS_ERR(vbd->bdev) )
{
DPRINTK("vbd_creat: device %08x doesn't exist.\n", vbd->pdevice);
- err = ERR_PTR(-ENOENT);
- goto out;
+ return -ENOENT;
}
if ( (vbd->bdev->bd_disk == NULL) )
{
DPRINTK("vbd_creat: device %08x doesn't exist.\n", vbd->pdevice);
bdev_put(vbd->bdev);
- err = ERR_PTR(-ENOENT);
- goto out;
+ return -ENOENT;
}
if ( vbd->bdev->bd_disk->flags & GENHD_FL_CD )
if ( (blk_size[MAJOR(vbd->pdevice)] == NULL) || (vbd_sz(vbd) == 0) )
{
DPRINTK("vbd_creat: device %08x doesn't exist.\n", vbd->pdevice);
- err = ERR_PTR(-ENOENT);
- goto out;
+ return -ENOENT;
}
#endif
DPRINTK("Successful creation of handle=%04x (dom=%u)\n",
handle, blkif->domid);
- return vbd;
-
- out:
- kfree(vbd);
- return err;
+ return 0;
}
-void vbd_activate(blkif_t *blkif, struct vbd *vbd)
+void vbd_activate(struct vbd *vbd)
{
BUG_ON(vbd_is_active(vbd));
/* Now we're active. */
vbd->active = 1;
- blkif_get(blkif);
}
-void vbd_free(blkif_t *blkif, struct vbd *vbd)
+void vbd_free(struct vbd *vbd)
{
- if (vbd_is_active(vbd)) {
- blkif_put(blkif);
- }
+ if (vbd_is_active(vbd))
+ vbd->active = 0;
bdev_put(vbd->bdev);
- kfree(vbd);
}
int vbd_translate(struct phys_req *req, blkif_t *blkif, int operation)
{
- struct vbd *vbd = blkif->vbd;
+ struct vbd *vbd = &blkif->vbd;
int rc = -EACCES;
if ((operation == WRITE) && vbd->readonly)
/* our communications channel */
blkif_t *blkif;
- struct vbd *vbd;
long int frontend_id;
long int pdev;
if (be->watch.node)
unregister_xenbus_watch(&be->watch);
unregister_xenbus_watch(&be->backend_watch);
- if (be->vbd)
- vbd_free(be->blkif, be->vbd);
if (be->blkif)
blkif_put(be->blkif);
if (be->frontpath)
device_unregister(&be->dev->dev);
return;
}
- if (vbd_is_active(be->vbd))
+ if (vbd_is_active(&be->blkif->vbd))
return;
err = xenbus_gather(be->frontpath, "grant-id", "%lu", &sharedmfn,
}
err = xenbus_printf(be->dev->nodename, "sectors", "%lu",
- vbd_size(be->vbd));
+ vbd_size(&be->blkif->vbd));
if (err) {
xenbus_dev_error(be->dev, err, "writing %s/sectors",
be->dev->nodename);
/* FIXME: use a typename instead */
err = xenbus_printf(be->dev->nodename, "info", "%u",
- vbd_info(be->vbd));
+ vbd_info(&be->blkif->vbd));
if (err) {
xenbus_dev_error(be->dev, err, "writing %s/info",
be->dev->nodename);
goto abort;
}
err = xenbus_printf(be->dev->nodename, "sector-size", "%lu",
- vbd_secsize(be->vbd));
+ vbd_secsize(&be->blkif->vbd));
if (err) {
xenbus_dev_error(be->dev, err, "writing %s/sector-size",
be->dev->nodename);
}
/* We're ready, activate. */
- vbd_activate(be->blkif, be->vbd);
+ vbd_activate(&be->blkif->vbd);
xenbus_transaction_end(0);
xenbus_dev_ok(be->dev);
goto device_fail;
}
- be->vbd = vbd_create(be->blkif, handle, be->pdev,
- be->readonly);
- if (IS_ERR(be->vbd)) {
- err = PTR_ERR(be->vbd);
- be->vbd = NULL;
+ err = vbd_create(be->blkif, handle, be->pdev, be->readonly);
+ if (err)
goto device_fail;
- }
frontend_changed(&be->watch, be->frontpath);
}