* debian/changelog: Update.

* debian/patches/features/all/xen/pvops.patch: Update patch to f6fe6583b77a.

svn path=/dists/sid/linux-2.6/; revision=15763
This commit is contained in:
Bastian Blank 2010-05-24 15:38:15 +00:00
parent 2dc1864b91
commit 1d53ee02e6
2 changed files with 445 additions and 88 deletions

3
debian/changelog vendored
View File

@ -17,6 +17,9 @@ linux-2.6 (2.6.32-14) UNRELEASED; urgency=low
been blacklisted by cpufrequtils. The acpi-cpufreq driver can be used
instead on some VIA C7 systems. (Closes: #566208)
[ Bastian Blank ]
* Update Xen patch.
-- Ben Hutchings <ben@decadent.org.uk> Tue, 18 May 2010 02:13:44 +0100
linux-2.6 (2.6.32-13) unstable; urgency=low

View File

@ -1,4 +1,4 @@
Patch based on commit ba739f9abd3f659b907a824af1161926b420a2ce of
Patch based on commit f6fe6583b77a49b569eef1b66c3d761eec2e561b of
git://git.kernel.org/pub/scm/linux/kernel/git/jeremy/xen.git.
diff --git a/Documentation/x86/x86_64/boot-options.txt b/Documentation/x86/x86_64/boot-options.txt
@ -3380,7 +3380,7 @@ index 0000000..21a3089
+#endif
+}
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index 3578688..e6a9f9f 100644
index 3578688..7638cd6 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -28,12 +28,19 @@
@ -3675,7 +3675,7 @@ index 3578688..e6a9f9f 100644
}
xen_raw_console_write("about to get started...\n");
@@ -1197,3 +1279,142 @@ asmlinkage void __init xen_start_kernel(void)
@@ -1197,3 +1279,141 @@ asmlinkage void __init xen_start_kernel(void)
x86_64_start_reservations((char *)__pa_symbol(&boot_params));
#endif
}
@ -3792,7 +3792,6 @@ index 3578688..e6a9f9f 100644
+ }
+ have_vcpu_info_placement = 0;
+ x86_init.irqs.intr_init = xen_init_IRQ;
+ machine_ops = xen_machine_ops;
+}
+
+static int __init parse_unplug(char *arg)
@ -6236,7 +6235,7 @@ index 1d886e0..f4a2b10 100644
This driver implements the front-end of the Xen virtual
block device driver. It communicates with a back-end driver
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index b8578bb..a8d30d7 100644
index b8578bb..75f730b 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -42,6 +42,7 @@
@ -6247,7 +6246,25 @@ index b8578bb..a8d30d7 100644
#include <xen/xenbus.h>
#include <xen/grant_table.h>
#include <xen/events.h>
@@ -102,6 +103,10 @@ struct blkfront_info
@@ -76,6 +77,7 @@ static const struct block_device_operations xlvbd_block_fops;
*/
struct blkfront_info
{
+ struct mutex mutex;
struct xenbus_device *xbdev;
struct gendisk *gd;
int vdevice;
@@ -92,16 +94,14 @@ struct blkfront_info
unsigned long shadow_free;
int feature_barrier;
int is_ready;
-
- /**
- * The number of people holding this device open. We won't allow a
- * hot-unplug unless this is 0.
- */
- int users;
};
static DEFINE_SPINLOCK(blkif_io_lock);
@ -6258,7 +6275,7 @@ index b8578bb..a8d30d7 100644
#define MAXIMUM_OUTSTANDING_BLOCK_REQS \
(BLKIF_MAX_SEGMENTS_PER_REQUEST * BLK_RING_SIZE)
#define GRANT_INVALID_REF 0
@@ -136,6 +141,55 @@ static void add_id_to_freelist(struct blkfront_info *info,
@@ -136,6 +136,55 @@ static void add_id_to_freelist(struct blkfront_info *info,
info->shadow_free = id;
}
@ -6314,7 +6331,7 @@ index b8578bb..a8d30d7 100644
static void blkif_restart_queue_callback(void *arg)
{
struct blkfront_info *info = (struct blkfront_info *)arg;
@@ -416,9 +470,14 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity,
@@ -416,9 +465,14 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity,
if ((minor % nr_parts) == 0)
nr_minors = nr_parts;
@ -6330,7 +6347,7 @@ index b8578bb..a8d30d7 100644
offset = minor / nr_parts;
@@ -449,7 +508,7 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity,
@@ -449,7 +503,7 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity,
if (xlvbd_init_blk_queue(gd, sector_size)) {
del_gendisk(gd);
@ -6339,7 +6356,7 @@ index b8578bb..a8d30d7 100644
}
info->rq = gd->queue;
@@ -469,6 +528,8 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity,
@@ -469,10 +523,45 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity,
return 0;
@ -6348,7 +6365,44 @@ index b8578bb..a8d30d7 100644
out:
return err;
}
@@ -650,7 +711,7 @@ fail:
+static void xlvbd_release_gendisk(struct blkfront_info *info)
+{
+ unsigned int minor, nr_minors;
+ unsigned long flags;
+
+ if (info->rq == NULL)
+ return;
+
+ spin_lock_irqsave(&blkif_io_lock, flags);
+
+ /* No more blkif_request(). */
+ blk_stop_queue(info->rq);
+
+ /* No more gnttab callback work. */
+ gnttab_cancel_free_callback(&info->callback);
+ spin_unlock_irqrestore(&blkif_io_lock, flags);
+
+ /* Flush gnttab callback work. Must be done with no locks held. */
+ flush_scheduled_work();
+
+ del_gendisk(info->gd);
+
+ minor = info->gd->first_minor;
+ nr_minors = info->gd->minors;
+ xlbd_release_minors(minor, nr_minors);
+
+ blk_cleanup_queue(info->rq);
+ info->rq = NULL;
+
+ put_disk(info->gd);
+ info->gd = NULL;
+}
+
static void kick_pending_request_queues(struct blkfront_info *info)
{
if (!RING_FULL(&info->ring)) {
@@ -650,7 +739,7 @@ fail:
/* Common code used when first setting up, and when resuming. */
@ -6357,7 +6411,23 @@ index b8578bb..a8d30d7 100644
struct blkfront_info *info)
{
const char *message = NULL;
@@ -755,7 +816,7 @@ static int blkfront_probe(struct xenbus_device *dev,
@@ -710,7 +799,6 @@ again:
return err;
}
-
/**
* Entry point to this code when a new device is created. Allocate the basic
* structures and the ring buffer for communication with the backend, and
@@ -742,6 +830,7 @@ static int blkfront_probe(struct xenbus_device *dev,
return -ENOMEM;
}
+ mutex_init(&info->mutex);
info->xbdev = dev;
info->vdevice = vdevice;
info->connected = BLKIF_STATE_DISCONNECTED;
@@ -755,7 +844,7 @@ static int blkfront_probe(struct xenbus_device *dev,
info->handle = simple_strtoul(strrchr(dev->nodename, '/')+1, NULL, 0);
dev_set_drvdata(&dev->dev, info);
@ -6366,7 +6436,7 @@ index b8578bb..a8d30d7 100644
if (err) {
kfree(info);
dev_set_drvdata(&dev->dev, NULL);
@@ -850,7 +911,7 @@ static int blkfront_resume(struct xenbus_device *dev)
@@ -850,13 +939,50 @@ static int blkfront_resume(struct xenbus_device *dev)
blkif_free(info, info->connected == BLKIF_STATE_CONNECTED);
@ -6375,7 +6445,50 @@ index b8578bb..a8d30d7 100644
if (info->connected == BLKIF_STATE_SUSPENDED && !err)
err = blkif_recover(info);
@@ -869,10 +930,29 @@ static void blkfront_connect(struct blkfront_info *info)
return err;
}
+static void
+blkfront_closing(struct blkfront_info *info)
+{
+ struct xenbus_device *xbdev = info->xbdev;
+ struct block_device *bdev = NULL;
+
+ mutex_lock(&info->mutex);
+
+ if (xbdev->state == XenbusStateClosing) {
+ mutex_unlock(&info->mutex);
+ return;
+ }
+
+ if (info->gd)
+ bdev = bdget_disk(info->gd, 0);
+
+ mutex_unlock(&info->mutex);
+
+ if (!bdev) {
+ xenbus_frontend_closed(xbdev);
+ return;
+ }
+
+ mutex_lock(&bdev->bd_mutex);
+
+ if (bdev->bd_openers) {
+ xenbus_dev_error(xbdev, -EBUSY,
+ "Device in use; refusing to close");
+ xenbus_switch_state(xbdev, XenbusStateClosing);
+ } else {
+ xlvbd_release_gendisk(info);
+ xenbus_frontend_closed(xbdev);
+ }
+
+ mutex_unlock(&bdev->bd_mutex);
+ bdput(bdev);
+}
/*
* Invoked when the backend is finally 'ready' (and has told produced
@@ -869,10 +995,29 @@ static void blkfront_connect(struct blkfront_info *info)
unsigned int binfo;
int err;
@ -6407,37 +6520,47 @@ index b8578bb..a8d30d7 100644
dev_dbg(&info->xbdev->dev, "%s:%s.\n",
__func__, info->xbdev->otherend);
@@ -920,12 +1000,11 @@ static void blkfront_connect(struct blkfront_info *info)
* the backend. Once is this done, we can switch to Closed in
* acknowledgement.
*/
-static void blkfront_closing(struct xenbus_device *dev)
+static void blkfront_closing(struct blkfront_info *info)
{
- struct blkfront_info *info = dev_get_drvdata(&dev->dev);
+ unsigned int minor, nr_minors;
unsigned long flags;
- dev_dbg(&dev->dev, "blkfront_closing: %s removed\n", dev->nodename);
if (info->rq == NULL)
goto out;
@@ -945,27 +1024,33 @@ static void blkfront_closing(struct xenbus_device *dev)
blk_cleanup_queue(info->rq);
info->rq = NULL;
+ minor = info->gd->first_minor;
+ nr_minors = info->gd->minors;
del_gendisk(info->gd);
+ xlbd_release_minors(minor, nr_minors);
out:
- xenbus_frontend_closed(dev);
+ if (info->xbdev)
+ xenbus_frontend_closed(info->xbdev);
@@ -915,57 +1060,21 @@ static void blkfront_connect(struct blkfront_info *info)
}
/**
- * Handle the change of state of the backend to Closing. We must delete our
- * device-layer structures now, to ensure that writes are flushed through to
- * the backend. Once is this done, we can switch to Closed in
- * acknowledgement.
- */
-static void blkfront_closing(struct xenbus_device *dev)
-{
- struct blkfront_info *info = dev_get_drvdata(&dev->dev);
- unsigned long flags;
-
- dev_dbg(&dev->dev, "blkfront_closing: %s removed\n", dev->nodename);
-
- if (info->rq == NULL)
- goto out;
-
- spin_lock_irqsave(&blkif_io_lock, flags);
-
- /* No more blkif_request(). */
- blk_stop_queue(info->rq);
-
- /* No more gnttab callback work. */
- gnttab_cancel_free_callback(&info->callback);
- spin_unlock_irqrestore(&blkif_io_lock, flags);
-
- /* Flush gnttab callback work. Must be done with no locks held. */
- flush_scheduled_work();
-
- blk_cleanup_queue(info->rq);
- info->rq = NULL;
-
- del_gendisk(info->gd);
-
- out:
- xenbus_frontend_closed(dev);
-}
-
-/**
* Callback received when the backend's state changes.
*/
-static void backend_changed(struct xenbus_device *dev,
@ -6445,7 +6568,7 @@ index b8578bb..a8d30d7 100644
enum xenbus_state backend_state)
{
struct blkfront_info *info = dev_get_drvdata(&dev->dev);
struct block_device *bd;
- struct block_device *bd;
- dev_dbg(&dev->dev, "blkfront:backend_changed.\n");
+ dev_dbg(&dev->dev, "blkfront:blkback_changed to state %d.\n", backend_state);
@ -6459,28 +6582,84 @@ index b8578bb..a8d30d7 100644
case XenbusStateUnknown:
case XenbusStateClosed:
break;
@@ -988,7 +1073,7 @@ static void backend_changed(struct xenbus_device *dev,
xenbus_dev_error(dev, -EBUSY,
"Device in use; refusing to close");
else
- blkfront_closing(dev);
+ blkfront_closing(info);
mutex_unlock(&bd->bd_mutex);
bdput(bd);
@@ -975,35 +1084,56 @@ static void backend_changed(struct xenbus_device *dev,
break;
@@ -1003,7 +1088,10 @@ static int blkfront_remove(struct xenbus_device *dev)
case XenbusStateClosing:
- if (info->gd == NULL) {
- xenbus_frontend_closed(dev);
- break;
- }
- bd = bdget_disk(info->gd, 0);
- if (bd == NULL)
- xenbus_dev_fatal(dev, -ENODEV, "bdget failed");
-
- mutex_lock(&bd->bd_mutex);
- if (info->users > 0)
- xenbus_dev_error(dev, -EBUSY,
- "Device in use; refusing to close");
- else
- blkfront_closing(dev);
- mutex_unlock(&bd->bd_mutex);
- bdput(bd);
+ blkfront_closing(info);
break;
}
}
-static int blkfront_remove(struct xenbus_device *dev)
+static int blkfront_remove(struct xenbus_device *xbdev)
{
- struct blkfront_info *info = dev_get_drvdata(&dev->dev);
+ struct blkfront_info *info = dev_get_drvdata(&xbdev->dev);
+ struct block_device *bdev = NULL;
+ struct gendisk *disk;
- dev_dbg(&dev->dev, "blkfront_remove: %s removed\n", dev->nodename);
+ dev_dbg(&xbdev->dev, "%s removed", xbdev->nodename);
blkif_free(info, 0);
- kfree(info);
+ if(info->users == 0)
+ mutex_lock(&info->mutex);
+
+ disk = info->gd;
+ if (disk)
+ bdev = bdget_disk(disk, 0);
+
+ info->xbdev = NULL;
+ mutex_unlock(&info->mutex);
+
+ if (!bdev) {
+ kfree(info);
+ else
+ info->xbdev = NULL;
+ return 0;
+ }
+
+ /*
+ * The xbdev was removed before we reached the Closed
+ * state. See if it's safe to remove the disk. If the bdev
+ * isn't closed yet, we let release take care of it.
+ */
+
+ mutex_lock(&bdev->bd_mutex);
+ info = disk->private_data;
+
+ dev_warn(disk_to_dev(disk),
+ "%s was hot-unplugged, %d stale handles\n",
+ xbdev->nodename, bdev->bd_openers);
+
+ if (info && !bdev->bd_openers) {
+ xlvbd_release_gendisk(info);
+ disk->private_data = NULL;
+ kfree(info);
+ }
+
+ mutex_unlock(&bdev->bd_mutex);
+ bdput(bdev);
return 0;
}
@@ -1012,12 +1100,15 @@ static int blkfront_is_ready(struct xenbus_device *dev)
@@ -1012,30 +1142,68 @@ static int blkfront_is_ready(struct xenbus_device *dev)
{
struct blkfront_info *info = dev_get_drvdata(&dev->dev);
@ -6490,31 +6669,80 @@ index b8578bb..a8d30d7 100644
static int blkif_open(struct block_device *bdev, fmode_t mode)
{
struct blkfront_info *info = bdev->bd_disk->private_data;
- struct blkfront_info *info = bdev->bd_disk->private_data;
- info->users++;
- return 0;
+ struct gendisk *disk = bdev->bd_disk;
+ struct blkfront_info *info;
+ int err = 0;
+
+ if (!info->xbdev)
+ return -ENODEV;
info->users++;
return 0;
+ info = disk->private_data;
+ if (!info)
+ /* xbdev gone */
+ return -ERESTARTSYS;
+
+ mutex_lock(&info->mutex);
+
+ if (!info->gd)
+ /* xbdev is closed */
+ err = -ERESTARTSYS;
+
+ mutex_unlock(&info->mutex);
+
+ return err;
}
@@ -1031,10 +1122,13 @@ static int blkif_release(struct gendisk *disk, fmode_t mode)
have ignored this request initially, as the device was
still mounted. */
struct xenbus_device *dev = info->xbdev;
- enum xenbus_state state = xenbus_read_driver_state(dev->otherend);
static int blkif_release(struct gendisk *disk, fmode_t mode)
{
struct blkfront_info *info = disk->private_data;
- info->users--;
- if (info->users == 0) {
- /* Check whether we have been instructed to close. We will
- have ignored this request initially, as the device was
- still mounted. */
- struct xenbus_device *dev = info->xbdev;
- enum xenbus_state state = xenbus_read_driver_state(dev->otherend);
-
- if (state == XenbusStateClosing && info->is_ready)
- blkfront_closing(dev);
+ if (!dev) {
+ blkfront_closing(info);
+ kfree(info);
+ } else if (xenbus_read_driver_state(dev->otherend)
+ == XenbusStateClosing && info->is_ready)
+ blkfront_closing(info);
+ struct block_device *bdev;
+ struct xenbus_device *xbdev;
+
+ bdev = bdget_disk(disk, 0);
+ bdput(bdev);
+
+ if (bdev->bd_openers)
+ return 0;
+
+ /*
+ * Check if we have been instructed to close. We will have
+ * deferred this request, because the bdev was still open.
+ */
+
+ mutex_lock(&info->mutex);
+ xbdev = info->xbdev;
+
+ if (xbdev && xbdev->state == XenbusStateClosing) {
+ /* pending switch to state closed */
+ dev_info(disk_to_dev(bdev->bd_disk), "releasing disk\n");
+ xlvbd_release_gendisk(info);
+ xenbus_frontend_closed(info->xbdev);
+ }
+
+ mutex_unlock(&info->mutex);
+
+ if (!xbdev) {
+ /* sudden device removal */
+ dev_info(disk_to_dev(bdev->bd_disk), "releasing disk\n");
+ xlvbd_release_gendisk(info);
+ disk->private_data = NULL;
+ kfree(info);
}
+
return 0;
}
@@ -1061,7 +1155,7 @@ static struct xenbus_driver blkfront = {
@@ -1061,7 +1229,7 @@ static struct xenbus_driver blkfront = {
.probe = blkfront_probe,
.remove = blkfront_remove,
.resume = blkfront_resume,
@ -16661,7 +16889,7 @@ index 7d8f531..8df6ae0 100644
+
+core_initcall(__gnttab_init);
diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c
index 5d42d55..004b1dd 100644
index 5d42d55..3924018 100644
--- a/drivers/xen/manage.c
+++ b/drivers/xen/manage.c
@@ -7,15 +7,19 @@
@ -16716,7 +16944,7 @@ index 5d42d55..004b1dd 100644
BUG_ON(!irqs_disabled());
@@ -72,6 +96,59 @@ static int xen_suspend(void *data)
@@ -72,6 +96,62 @@ static int xen_suspend(void *data)
return 0;
}
@ -16770,13 +16998,16 @@ index 5d42d55..004b1dd 100644
+ stop_machine_destroy();
+
+out:
+#ifdef CONFIG_PREEMPT
+ thaw_processes();
+#endif
+ shutting_down = SHUTDOWN_INVALID;
+}
+
static void do_suspend(void)
{
int err;
@@ -184,7 +261,10 @@ static void shutdown_handler(struct xenbus_watch *watch,
@@ -184,7 +264,10 @@ static void shutdown_handler(struct xenbus_watch *watch,
ctrl_alt_del();
#ifdef CONFIG_PM_SLEEP
} else if (strcmp(str, "suspend") == 0) {
@ -16788,7 +17019,7 @@ index 5d42d55..004b1dd 100644
#endif
} else {
printk(KERN_INFO "Ignoring shutdown request: %s\n", str);
@@ -260,7 +340,19 @@ static int shutdown_event(struct notifier_block *notifier,
@@ -260,7 +343,19 @@ static int shutdown_event(struct notifier_block *notifier,
return NOTIFY_DONE;
}
@ -16809,7 +17040,7 @@ index 5d42d55..004b1dd 100644
{
static struct notifier_block xenstore_notifier = {
.notifier_call = shutdown_event
@@ -270,4 +362,4 @@ static int __init setup_shutdown_event(void)
@@ -270,4 +365,4 @@ static int __init setup_shutdown_event(void)
return 0;
}
@ -17697,10 +17928,10 @@ index 0000000..086d939
+}
diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
new file mode 100644
index 0000000..0bc6398
index 0000000..5dc4f98
--- /dev/null
+++ b/drivers/xen/netback/netback.c
@@ -0,0 +1,1613 @@
@@ -0,0 +1,1609 @@
+/******************************************************************************
+ * drivers/xen/netback/netback.c
+ *
@ -19035,14 +19266,10 @@ index 0000000..0bc6398
+ netif_idx_release(pending_idx);
+ }
+
+ /*
+ * Old frontends do not assert data_validated but we
+ * can infer it from csum_blank so test both flags.
+ */
+ if (txp->flags & (NETTXF_data_validated|NETTXF_csum_blank))
+ if (txp->flags & NETTXF_csum_blank)
+ skb->ip_summed = CHECKSUM_PARTIAL;
+ else
+ skb->ip_summed = CHECKSUM_NONE;
+ else if (txp->flags & NETTXF_data_validated)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ netbk_fill_frags(skb);
+
@ -26043,7 +26270,7 @@ index 5571f5b..8dca685 100644
+
+obj-$(CONFIG_XEN_XENBUS_FRONTEND) += xenbus_probe_frontend.o
diff --git a/drivers/xen/xenbus/xenbus_client.c b/drivers/xen/xenbus/xenbus_client.c
index 92a1ef8..da3ca9e 100644
index 92a1ef8..89f2e42 100644
--- a/drivers/xen/xenbus/xenbus_client.c
+++ b/drivers/xen/xenbus/xenbus_client.c
@@ -49,6 +49,8 @@ const char *xenbus_strstate(enum xenbus_state state)
@ -26055,6 +26282,133 @@ index 92a1ef8..da3ca9e 100644
};
return (state < ARRAY_SIZE(name)) ? name[state] : "INVALID";
}
@@ -132,17 +134,12 @@ int xenbus_watch_pathfmt(struct xenbus_device *dev,
}
EXPORT_SYMBOL_GPL(xenbus_watch_pathfmt);
+static void xenbus_switch_fatal(struct xenbus_device *, int, int,
+ const char *, ...);
-/**
- * xenbus_switch_state
- * @dev: xenbus device
- * @state: new state
- *
- * Advertise in the store a change of the given driver to the given new_state.
- * Return 0 on success, or -errno on error. On error, the device will switch
- * to XenbusStateClosing, and the error will be saved in the store.
- */
-int xenbus_switch_state(struct xenbus_device *dev, enum xenbus_state state)
+static int
+__xenbus_switch_state(struct xenbus_device *dev,
+ enum xenbus_state state, int depth)
{
/* We check whether the state is currently set to the given value, and
if not, then the state is set. We don't want to unconditionally
@@ -151,35 +148,65 @@ int xenbus_switch_state(struct xenbus_device *dev, enum xenbus_state state)
to it, as the device will be tearing down, and we don't want to
resurrect that directory.
- Note that, because of this cached value of our state, this function
- will not work inside a Xenstore transaction (something it was
- trying to in the past) because dev->state would not get reset if
- the transaction was aborted.
-
+ Note that, because of this cached value of our state, this
+ function will not take a caller's Xenstore transaction
+ (something it was trying to in the past) because dev->state
+ would not get reset if the transaction was aborted.
*/
+ struct xenbus_transaction xbt;
int current_state;
- int err;
+ int err, abort;
if (state == dev->state)
return 0;
- err = xenbus_scanf(XBT_NIL, dev->nodename, "state", "%d",
- &current_state);
- if (err != 1)
+again:
+ abort = 1;
+
+ err = xenbus_transaction_start(&xbt);
+ if (err) {
+ xenbus_switch_fatal(dev, depth, err, "starting transaction");
return 0;
+ }
+
+ err = xenbus_scanf(xbt, dev->nodename, "state", "%d", &current_state);
+ if (err != 1)
+ goto abort;
- err = xenbus_printf(XBT_NIL, dev->nodename, "state", "%d", state);
+ err = xenbus_printf(xbt, dev->nodename, "state", "%d", state);
if (err) {
- if (state != XenbusStateClosing) /* Avoid looping */
- xenbus_dev_fatal(dev, err, "writing new state");
- return err;
+ xenbus_switch_fatal(dev, depth, err, "writing new state");
+ goto abort;
}
- dev->state = state;
+ abort = 0;
+abort:
+ err = xenbus_transaction_end(xbt, abort);
+ if (err) {
+ if (err == -EAGAIN && !abort)
+ goto again;
+ xenbus_switch_fatal(dev, depth, err, "ending transaction");
+ } else
+ dev->state = state;
return 0;
}
+
+/**
+ * xenbus_switch_state
+ * @dev: xenbus device
+ * @state: new state
+ *
+ * Advertise in the store a change of the given driver to the given new_state.
+ * Return 0 on success, or -errno on error. On error, the device will switch
+ * to XenbusStateClosing, and the error will be saved in the store.
+ */
+int xenbus_switch_state(struct xenbus_device *dev, enum xenbus_state state)
+{
+ return __xenbus_switch_state(dev, state, 0);
+}
+
EXPORT_SYMBOL_GPL(xenbus_switch_state);
int xenbus_frontend_closed(struct xenbus_device *dev)
@@ -283,6 +310,23 @@ void xenbus_dev_fatal(struct xenbus_device *dev, int err, const char *fmt, ...)
EXPORT_SYMBOL_GPL(xenbus_dev_fatal);
/**
+ * Equivalent to xenbus_dev_fatal(dev, err, fmt, args), but helps
+ * avoiding recursion within xenbus_switch_state.
+ */
+static void xenbus_switch_fatal(struct xenbus_device *dev, int depth, int err,
+ const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ xenbus_va_dev_error(dev, err, fmt, ap);
+ va_end(ap);
+
+ if (!depth)
+ __xenbus_switch_state(dev, XenbusStateClosing, 1);
+}
+
+/**
* xenbus_grant_ring
* @dev: xenbus device
* @ring_mfn: mfn of ring to grant
diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c
index 649fcdf..57fb749 100644
--- a/drivers/xen/xenbus/xenbus_probe.c