#include <linux/delay.h>
#include <linux/freezer.h>
#include <linux/bitmap.h>
+#include <linux/rwsem.h>
#include <xen/events.h>
#include <xen/page.h>
goto out;
}
+ /*
+ * vbd_translate is always called with vbd_lock held so we can
+ * safely dereference it
+ */
req->dev = vbd->pdevice;
req->bdev = vbd->bdev;
rc = 0;
static void xen_vbd_resize(struct xen_blkif *blkif)
{
- struct xen_vbd *vbd = &blkif->vbd;
+ struct xen_vbd *vbd;
struct xenbus_transaction xbt;
int err;
struct xenbus_device *dev = xen_blkbk_xenbus(blkif->be);
- unsigned long long new_size = vbd_sz(vbd);
+ unsigned long long new_size;
+
+ down_read(&blkif->vbd_lock);
+ vbd = &blkif->vbd;
+ new_size = vbd_sz(vbd);
+ if (likely(vbd->size == new_size)) {
+ up_read(&blkif->vbd_lock);
+ return;
+ }
pr_info("VBD Resize: Domid: %d, Device: (%d, %d)\n",
blkif->domid, MAJOR(vbd->pdevice), MINOR(vbd->pdevice));
err = xenbus_transaction_start(&xbt);
if (err) {
pr_warn("Error starting transaction\n");
+ up_read(&blkif->vbd_lock);
return;
}
err = xenbus_printf(xbt, dev->nodename, "sectors", "%llu",
goto again;
if (err)
pr_warn("Error ending transaction\n");
+ up_read(&blkif->vbd_lock);
return;
abort:
xenbus_transaction_end(xbt, 1);
+ up_read(&blkif->vbd_lock);
}
/*
{
struct xen_blkif_ring *ring = arg;
struct xen_blkif *blkif = ring->blkif;
- struct xen_vbd *vbd = &blkif->vbd;
unsigned long timeout;
int ret;
while (!kthread_should_stop()) {
if (try_to_freeze())
continue;
- if (unlikely(vbd->size != vbd_sz(vbd)))
- xen_vbd_resize(blkif);
+ xen_vbd_resize(blkif);
timeout = msecs_to_jiffies(LRU_INTERVAL);
barrier();
+ /*
+ * To ensure that this vbd hangs around, we hold onto the lock
+ * until completion
+ */
+ down_read(&ring->blkif->vbd_lock);
+
if (likely(valid_req)) {
switch (req.operation) {
case BLKIF_OP_READ:
union blkif_back_rings *blk_rings;
int notify;
+ up_read(&ring->blkif->vbd_lock);
+
spin_lock_irqsave(&ring->blk_ring_lock, flags);
blk_rings = &ring->blk_rings;
/* Place on the response ring for the relevant domain. */
#include <stdarg.h>
#include <linux/module.h>
#include <linux/kthread.h>
+#include <linux/rwsem.h>
#include <xen/events.h>
#include <xen/grant_table.h>
#include "common.h"
/* On the XenBus the max length of 'ring-ref%u'. */
#define RINGREF_NAME_LEN (20)
-struct blkif_params {
- unsigned int major;
- unsigned int minor;
- unsigned int readonly;
- unsigned int cdrom;
-};
-
-struct backend_info {
- struct xenbus_device *dev;
- struct xen_blkif *blkif;
- struct xenbus_watch backend_watch;
- struct blkif_params params;
-};
-
static struct kmem_cache *xen_blkif_cachep;
static void connect(struct backend_info *);
static int connect_ring(struct backend_info *);
atomic_set(&blkif->refcnt, 1);
init_completion(&blkif->drain_complete);
INIT_WORK(&blkif->free_work, xen_blkif_deferred_free);
+ init_rwsem(&blkif->vbd_lock);
return blkif;
}
struct blkif_params oldp, newp;
struct xen_vbd vbd;
bool swap = false;
+ int locked = 0;
pr_debug("%s %p %d\n", __func__, dev, dev->otherend_id);
if (be->params.major | be->params.minor) {
err = validate_swap_params(be, &newp);
- if (err)
+
+ if (!err) {
+ locked = down_write_trylock(&be->blkif->vbd_lock);
+ if (locked)
+ swap = true;
+ else
+ err = -EAGAIN;
+ }
+
+ if (err) /* !valid || !locked */
goto out;
- swap = true;
}
err = xen_vbd_create(be->blkif, handle, &newp, &vbd);
be->params = newp;
if (swap) {
+ if (be->blkif->vbd.bdev == NULL) {
+ /* Should not happen; Bail out */
+ WARN(1, "xen-blkback: invalid blkif->vbd.bdev\n");
+ goto flush_sysfs_out;
+ }
+
/* Flush, invalidate extant mappings */
err = flush_bdev_mapping(dev, &be->blkif->vbd);
if (err) {
xenbus_dev_fatal(dev, err,
"Failed in writing oracle/active-physical-device");
}
+ if (locked)
+ up_write(&be->blkif->vbd_lock);
}
/*
pr_debug("%s %s\n", __func__, dev->otherend);
+ down_read(&be->blkif->vbd_lock);
+
/* Supply the information about the device the frontend needs */
again:
err = xenbus_transaction_start(&xbt);
if (err) {
xenbus_dev_fatal(dev, err, "starting transaction");
+ up_read(&be->blkif->vbd_lock);
return;
}
xenbus_dev_fatal(dev, err, "%s: switching to Connected state",
dev->nodename);
+ up_read(&be->blkif->vbd_lock);
return;
abort:
xenbus_transaction_end(xbt, 1);
+ up_read(&be->blkif->vbd_lock);
}
void xen_blkbk_free_req(struct pending_req *req)