--- /dev/null
+From 6076905b5ef39e0ea58db32583c9e0036c05e47b Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+Date: Thu, 10 Dec 2009 23:51:52 +0000
+Subject: dm: avoid _hash_lock deadlock
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+commit 6076905b5ef39e0ea58db32583c9e0036c05e47b upstream.
+
+Fix a reported deadlock if there are still unprocessed multipath events
+on a device that is being removed.
+
+_hash_lock is held during dev_remove while trying to send the
+outstanding events. Sending the events requests the _hash_lock
+again in dm_copy_name_and_uuid.
+
+This patch introduces a separate lock around regions that modify the
+link to the hash table (dm_set_mdptr) or the name or uuid so that
+dm_copy_name_and_uuid no longer needs _hash_lock.
+
+Additionally, dm_copy_name_and_uuid can only be called if md exists
+so we can drop the dm_get() and dm_put() which can lead to a BUG()
+while md is being freed.
+
+The deadlock:
+ #0 [ffff8106298dfb48] schedule at ffffffff80063035
+ #1 [ffff8106298dfc20] __down_read at ffffffff8006475d
+ #2 [ffff8106298dfc60] dm_copy_name_and_uuid at ffffffff8824f740
+ #3 [ffff8106298dfc90] dm_send_uevents at ffffffff88252685
+ #4 [ffff8106298dfcd0] event_callback at ffffffff8824c678
+ #5 [ffff8106298dfd00] dm_table_event at ffffffff8824dd01
+ #6 [ffff8106298dfd10] __hash_remove at ffffffff882507ad
+ #7 [ffff8106298dfd30] dev_remove at ffffffff88250865
+ #8 [ffff8106298dfd60] ctl_ioctl at ffffffff88250d80
+ #9 [ffff8106298dfee0] do_ioctl at ffffffff800418c4
+#10 [ffff8106298dff00] vfs_ioctl at ffffffff8002fab9
+#11 [ffff8106298dff40] sys_ioctl at ffffffff8004bdaf
+#12 [ffff8106298dff80] tracesys at ffffffff8005d28d (via system_call)
+
+Reported-by: guy keren <choo@actcom.co.il>
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Signed-off-by: Alasdair G Kergon <agk@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/md/dm-ioctl.c | 17 +++++++++++++----
+ drivers/md/dm-uevent.c | 9 ++++-----
+ 2 files changed, 17 insertions(+), 9 deletions(-)
+
+--- a/drivers/md/dm-ioctl.c
++++ b/drivers/md/dm-ioctl.c
+@@ -56,6 +56,11 @@ static void dm_hash_remove_all(int keep_
+ */
+ static DECLARE_RWSEM(_hash_lock);
+
++/*
++ * Protects use of mdptr to obtain hash cell name and uuid from mapped device.
++ */
++static DEFINE_MUTEX(dm_hash_cells_mutex);
++
+ static void init_buckets(struct list_head *buckets)
+ {
+ unsigned int i;
+@@ -206,7 +211,9 @@ static int dm_hash_insert(const char *na
+ list_add(&cell->uuid_list, _uuid_buckets + hash_str(uuid));
+ }
+ dm_get(md);
++ mutex_lock(&dm_hash_cells_mutex);
+ dm_set_mdptr(md, cell);
++ mutex_unlock(&dm_hash_cells_mutex);
+ up_write(&_hash_lock);
+
+ return 0;
+@@ -224,7 +231,9 @@ static void __hash_remove(struct hash_ce
+ /* remove from the dev hash */
+ list_del(&hc->uuid_list);
+ list_del(&hc->name_list);
++ mutex_lock(&dm_hash_cells_mutex);
+ dm_set_mdptr(hc->md, NULL);
++ mutex_unlock(&dm_hash_cells_mutex);
+
+ table = dm_get_table(hc->md);
+ if (table) {
+@@ -321,7 +330,9 @@ static int dm_hash_rename(uint32_t cooki
+ */
+ list_del(&hc->name_list);
+ old_name = hc->name;
++ mutex_lock(&dm_hash_cells_mutex);
+ hc->name = new_name;
++ mutex_unlock(&dm_hash_cells_mutex);
+ list_add(&hc->name_list, _name_buckets + hash_str(new_name));
+
+ /*
+@@ -1582,8 +1593,7 @@ int dm_copy_name_and_uuid(struct mapped_
+ if (!md)
+ return -ENXIO;
+
+- dm_get(md);
+- down_read(&_hash_lock);
++ mutex_lock(&dm_hash_cells_mutex);
+ hc = dm_get_mdptr(md);
+ if (!hc || hc->md != md) {
+ r = -ENXIO;
+@@ -1596,8 +1606,7 @@ int dm_copy_name_and_uuid(struct mapped_
+ strcpy(uuid, hc->uuid ? : "");
+
+ out:
+- up_read(&_hash_lock);
+- dm_put(md);
++ mutex_unlock(&dm_hash_cells_mutex);
+
+ return r;
+ }
+--- a/drivers/md/dm-uevent.c
++++ b/drivers/md/dm-uevent.c
+@@ -139,14 +139,13 @@ void dm_send_uevents(struct list_head *e
+ list_del_init(&event->elist);
+
+ /*
+- * Need to call dm_copy_name_and_uuid from here for now.
+- * Context of previous var adds and locking used for
+- * hash_cell not compatable.
++ * When a device is being removed this copy fails and we
++ * discard these unsent events.
+ */
+ if (dm_copy_name_and_uuid(event->md, event->name,
+ event->uuid)) {
+- DMERR("%s: dm_copy_name_and_uuid() failed",
+- __func__);
++ DMINFO("%s: skipping sending uevent for lost device",
++ __func__);
+ goto uevent_free;
+ }
+
--- /dev/null
+From 542da317668c35036e8471822a564b609d05af66 Mon Sep 17 00:00:00 2001
+From: Milan Broz <mbroz@redhat.com>
+Date: Thu, 10 Dec 2009 23:51:57 +0000
+Subject: dm crypt: make wipe message also wipe essiv key
+
+From: Milan Broz <mbroz@redhat.com>
+
+commit 542da317668c35036e8471822a564b609d05af66 upstream.
+
+The "wipe key" message is used to wipe the volume key from memory
+temporarily, for example when suspending to RAM.
+
+But the initialisation vector in ESSIV mode is calculated from the
+hashed volume key, so the wipe message should wipe this IV key too and
+reinitialise it when the volume key is reinstated.
+
+This patch adds an IV wipe method called from a wipe message callback.
+ESSIV is then reinitialised using the init function added by the
+last patch.
+
+Signed-off-by: Milan Broz <mbroz@redhat.com>
+Signed-off-by: Alasdair G Kergon <agk@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/md/dm-crypt.c | 34 ++++++++++++++++++++++++++++++----
+ 1 file changed, 30 insertions(+), 4 deletions(-)
+
+--- a/drivers/md/dm-crypt.c
++++ b/drivers/md/dm-crypt.c
+@@ -1,7 +1,7 @@
+ /*
+ * Copyright (C) 2003 Christophe Saout <christophe@saout.de>
+ * Copyright (C) 2004 Clemens Fruhwirth <clemens@endorphin.org>
+- * Copyright (C) 2006-2008 Red Hat, Inc. All rights reserved.
++ * Copyright (C) 2006-2009 Red Hat, Inc. All rights reserved.
+ *
+ * This file is released under the GPL.
+ */
+@@ -72,6 +72,7 @@ struct crypt_iv_operations {
+ const char *opts);
+ void (*dtr)(struct crypt_config *cc);
+ int (*init)(struct crypt_config *cc);
++ int (*wipe)(struct crypt_config *cc);
+ int (*generator)(struct crypt_config *cc, u8 *iv, sector_t sector);
+ };
+
+@@ -199,6 +200,17 @@ static int crypt_iv_essiv_init(struct cr
+ crypto_hash_digestsize(essiv->hash_tfm));
+ }
+
++/* Wipe salt and reset key derived from volume key */
++static int crypt_iv_essiv_wipe(struct crypt_config *cc)
++{
++ struct iv_essiv_private *essiv = &cc->iv_gen_private.essiv;
++ unsigned salt_size = crypto_hash_digestsize(essiv->hash_tfm);
++
++ memset(essiv->salt, 0, salt_size);
++
++ return crypto_cipher_setkey(essiv->tfm, essiv->salt, salt_size);
++}
++
+ static void crypt_iv_essiv_dtr(struct crypt_config *cc)
+ {
+ struct iv_essiv_private *essiv = &cc->iv_gen_private.essiv;
+@@ -334,6 +346,7 @@ static struct crypt_iv_operations crypt_
+ .ctr = crypt_iv_essiv_ctr,
+ .dtr = crypt_iv_essiv_dtr,
+ .init = crypt_iv_essiv_init,
++ .wipe = crypt_iv_essiv_wipe,
+ .generator = crypt_iv_essiv_gen
+ };
+
+@@ -1310,6 +1323,7 @@ static void crypt_resume(struct dm_targe
+ static int crypt_message(struct dm_target *ti, unsigned argc, char **argv)
+ {
+ struct crypt_config *cc = ti->private;
++ int ret = -EINVAL;
+
+ if (argc < 2)
+ goto error;
+@@ -1319,10 +1333,22 @@ static int crypt_message(struct dm_targe
+ DMWARN("not suspended during key manipulation.");
+ return -EINVAL;
+ }
+- if (argc == 3 && !strnicmp(argv[1], MESG_STR("set")))
+- return crypt_set_key(cc, argv[2]);
+- if (argc == 2 && !strnicmp(argv[1], MESG_STR("wipe")))
++ if (argc == 3 && !strnicmp(argv[1], MESG_STR("set"))) {
++ ret = crypt_set_key(cc, argv[2]);
++ if (ret)
++ return ret;
++ if (cc->iv_gen_ops && cc->iv_gen_ops->init)
++ ret = cc->iv_gen_ops->init(cc);
++ return ret;
++ }
++ if (argc == 2 && !strnicmp(argv[1], MESG_STR("wipe"))) {
++ if (cc->iv_gen_ops && cc->iv_gen_ops->wipe) {
++ ret = cc->iv_gen_ops->wipe(cc);
++ if (ret)
++ return ret;
++ }
+ return crypt_wipe_key(cc);
++ }
+ }
+
+ error:
--- /dev/null
+From 6047359277517c4e56d8bfd6ea4966d7a3924151 Mon Sep 17 00:00:00 2001
+From: Milan Broz <mbroz@redhat.com>
+Date: Thu, 10 Dec 2009 23:51:55 +0000
+Subject: dm crypt: move private iv fields to structs
+
+From: Milan Broz <mbroz@redhat.com>
+
+commit 6047359277517c4e56d8bfd6ea4966d7a3924151 upstream.
+
+Define private structures for IV so it's easy to add further attributes
+in a following patch which fixes the way key material is wiped from
+memory. Also move ESSIV destructor and remove unnecessary 'status'
+operation.
+
+There are no functional changes in this patch.
+
+Signed-off-by: Milan Broz <mbroz@redhat.com>
+Signed-off-by: Alasdair G Kergon <agk@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/md/dm-crypt.c | 35 ++++++++++++++++++++++-------------
+ 1 file changed, 22 insertions(+), 13 deletions(-)
+
+--- a/drivers/md/dm-crypt.c
++++ b/drivers/md/dm-crypt.c
+@@ -71,10 +71,17 @@ struct crypt_iv_operations {
+ int (*ctr)(struct crypt_config *cc, struct dm_target *ti,
+ const char *opts);
+ void (*dtr)(struct crypt_config *cc);
+- const char *(*status)(struct crypt_config *cc);
+ int (*generator)(struct crypt_config *cc, u8 *iv, sector_t sector);
+ };
+
++struct iv_essiv_private {
++ struct crypto_cipher *tfm;
++};
++
++struct iv_benbi_private {
++ int shift;
++};
++
+ /*
+ * Crypt: maps a linear range of a block device
+ * and encrypts / decrypts at the same time.
+@@ -102,8 +109,8 @@ struct crypt_config {
+ struct crypt_iv_operations *iv_gen_ops;
+ char *iv_mode;
+ union {
+- struct crypto_cipher *essiv_tfm;
+- int benbi_shift;
++ struct iv_essiv_private essiv;
++ struct iv_benbi_private benbi;
+ } iv_gen_private;
+ sector_t iv_offset;
+ unsigned int iv_size;
+@@ -169,6 +176,14 @@ static int crypt_iv_plain_gen(struct cry
+ return 0;
+ }
+
++static void crypt_iv_essiv_dtr(struct crypt_config *cc)
++{
++ struct iv_essiv_private *essiv = &cc->iv_gen_private.essiv;
++
++ crypto_free_cipher(essiv->tfm);
++ essiv->tfm = NULL;
++}
++
+ static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti,
+ const char *opts)
+ {
+@@ -236,21 +251,15 @@ static int crypt_iv_essiv_ctr(struct cry
+ }
+ kfree(salt);
+
+- cc->iv_gen_private.essiv_tfm = essiv_tfm;
++ cc->iv_gen_private.essiv.tfm = essiv_tfm;
+ return 0;
+ }
+
+-static void crypt_iv_essiv_dtr(struct crypt_config *cc)
+-{
+- crypto_free_cipher(cc->iv_gen_private.essiv_tfm);
+- cc->iv_gen_private.essiv_tfm = NULL;
+-}
+-
+ static int crypt_iv_essiv_gen(struct crypt_config *cc, u8 *iv, sector_t sector)
+ {
+ memset(iv, 0, cc->iv_size);
+ *(u64 *)iv = cpu_to_le64(sector);
+- crypto_cipher_encrypt_one(cc->iv_gen_private.essiv_tfm, iv, iv);
++ crypto_cipher_encrypt_one(cc->iv_gen_private.essiv.tfm, iv, iv);
+ return 0;
+ }
+
+@@ -273,7 +282,7 @@ static int crypt_iv_benbi_ctr(struct cry
+ return -EINVAL;
+ }
+
+- cc->iv_gen_private.benbi_shift = 9 - log;
++ cc->iv_gen_private.benbi.shift = 9 - log;
+
+ return 0;
+ }
+@@ -288,7 +297,7 @@ static int crypt_iv_benbi_gen(struct cry
+
+ memset(iv, 0, cc->iv_size - sizeof(u64)); /* rest is cleared below */
+
+- val = cpu_to_be64(((u64)sector << cc->iv_gen_private.benbi_shift) + 1);
++ val = cpu_to_be64(((u64)sector << cc->iv_gen_private.benbi.shift) + 1);
+ put_unaligned(val, (__be64 *)(iv + cc->iv_size - sizeof(u64)));
+
+ return 0;
--- /dev/null
+From 5861f1be00b3b70f8ab5e5a81392a6cf69666cd2 Mon Sep 17 00:00:00 2001
+From: Milan Broz <mbroz@redhat.com>
+Date: Thu, 10 Dec 2009 23:51:56 +0000
+Subject: dm crypt: restructure essiv error path
+
+From: Milan Broz <mbroz@redhat.com>
+
+commit 5861f1be00b3b70f8ab5e5a81392a6cf69666cd2 upstream.
+
+Use kzfree for salt deallocation because it is derived from the volume
+key. Use a common error path in ESSIV constructor.
+
+Required by a later patch which fixes the way key material is wiped
+from memory.
+
+Signed-off-by: Milan Broz <mbroz@redhat.com>
+Signed-off-by: Alasdair G Kergon <agk@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/md/dm-crypt.c | 46 ++++++++++++++++++++++++++--------------------
+ 1 file changed, 26 insertions(+), 20 deletions(-)
+
+--- a/drivers/md/dm-crypt.c
++++ b/drivers/md/dm-crypt.c
+@@ -187,15 +187,15 @@ static void crypt_iv_essiv_dtr(struct cr
+ static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti,
+ const char *opts)
+ {
+- struct crypto_cipher *essiv_tfm;
+- struct crypto_hash *hash_tfm;
++ struct crypto_cipher *essiv_tfm = NULL;
++ struct crypto_hash *hash_tfm = NULL;
+ struct hash_desc desc;
+ struct scatterlist sg;
+ unsigned int saltsize;
+- u8 *salt;
++ u8 *salt = NULL;
+ int err;
+
+- if (opts == NULL) {
++ if (!opts) {
+ ti->error = "Digest algorithm missing for ESSIV mode";
+ return -EINVAL;
+ }
+@@ -204,15 +204,16 @@ static int crypt_iv_essiv_ctr(struct cry
+ hash_tfm = crypto_alloc_hash(opts, 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(hash_tfm)) {
+ ti->error = "Error initializing ESSIV hash";
+- return PTR_ERR(hash_tfm);
++ err = PTR_ERR(hash_tfm);
++ goto bad;
+ }
+
+ saltsize = crypto_hash_digestsize(hash_tfm);
+- salt = kmalloc(saltsize, GFP_KERNEL);
+- if (salt == NULL) {
++ salt = kzalloc(saltsize, GFP_KERNEL);
++ if (!salt) {
+ ti->error = "Error kmallocing salt storage in ESSIV";
+- crypto_free_hash(hash_tfm);
+- return -ENOMEM;
++ err = -ENOMEM;
++ goto bad;
+ }
+
+ sg_init_one(&sg, cc->key, cc->key_size);
+@@ -220,39 +221,44 @@ static int crypt_iv_essiv_ctr(struct cry
+ desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+ err = crypto_hash_digest(&desc, &sg, cc->key_size, salt);
+ crypto_free_hash(hash_tfm);
++ hash_tfm = NULL;
+
+ if (err) {
+ ti->error = "Error calculating hash in ESSIV";
+- kfree(salt);
+- return err;
++ goto bad;
+ }
+
+ /* Setup the essiv_tfm with the given salt */
+ essiv_tfm = crypto_alloc_cipher(cc->cipher, 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(essiv_tfm)) {
+ ti->error = "Error allocating crypto tfm for ESSIV";
+- kfree(salt);
+- return PTR_ERR(essiv_tfm);
++ err = PTR_ERR(essiv_tfm);
++ goto bad;
+ }
+ if (crypto_cipher_blocksize(essiv_tfm) !=
+ crypto_ablkcipher_ivsize(cc->tfm)) {
+ ti->error = "Block size of ESSIV cipher does "
+ "not match IV size of block cipher";
+- crypto_free_cipher(essiv_tfm);
+- kfree(salt);
+- return -EINVAL;
++ err = -EINVAL;
++ goto bad;
+ }
+ err = crypto_cipher_setkey(essiv_tfm, salt, saltsize);
+ if (err) {
+ ti->error = "Failed to set key for ESSIV cipher";
+- crypto_free_cipher(essiv_tfm);
+- kfree(salt);
+- return err;
++ goto bad;
+ }
+- kfree(salt);
++ kzfree(salt);
+
+ cc->iv_gen_private.essiv.tfm = essiv_tfm;
+ return 0;
++
++bad:
++ if (essiv_tfm && !IS_ERR(essiv_tfm))
++ crypto_free_cipher(essiv_tfm);
++ if (hash_tfm && !IS_ERR(hash_tfm))
++ crypto_free_hash(hash_tfm);
++ kzfree(salt);
++ return err;
+ }
+
+ static int crypt_iv_essiv_gen(struct crypt_config *cc, u8 *iv, sector_t sector)
--- /dev/null
+From b95bf2d3d5a48b095bffe2a0cd8c40453cf59557 Mon Sep 17 00:00:00 2001
+From: Milan Broz <mbroz@redhat.com>
+Date: Thu, 10 Dec 2009 23:51:56 +0000
+Subject: dm crypt: separate essiv allocation from initialisation
+
+From: Milan Broz <mbroz@redhat.com>
+
+commit b95bf2d3d5a48b095bffe2a0cd8c40453cf59557 upstream.
+
+This patch separates the construction of IV from its initialisation.
+(For ESSIV it is a hash calculation based on volume key.)
+
+Constructor code now preallocates hash tfm and salt array
+and saves it in a private IV structure.
+
+The next patch requires this to reinitialise the wiped IV
+without reallocating memory when resuming a suspended device.
+
+Signed-off-by: Milan Broz <mbroz@redhat.com>
+Signed-off-by: Alasdair G Kergon <agk@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/md/dm-crypt.c | 69 +++++++++++++++++++++++++++++++-------------------
+ 1 file changed, 43 insertions(+), 26 deletions(-)
+
+--- a/drivers/md/dm-crypt.c
++++ b/drivers/md/dm-crypt.c
+@@ -71,11 +71,14 @@ struct crypt_iv_operations {
+ int (*ctr)(struct crypt_config *cc, struct dm_target *ti,
+ const char *opts);
+ void (*dtr)(struct crypt_config *cc);
++ int (*init)(struct crypt_config *cc);
+ int (*generator)(struct crypt_config *cc, u8 *iv, sector_t sector);
+ };
+
+ struct iv_essiv_private {
+ struct crypto_cipher *tfm;
++ struct crypto_hash *hash_tfm;
++ u8 *salt;
+ };
+
+ struct iv_benbi_private {
+@@ -176,12 +179,38 @@ static int crypt_iv_plain_gen(struct cry
+ return 0;
+ }
+
++/* Initialise ESSIV - compute salt but no local memory allocations */
++static int crypt_iv_essiv_init(struct crypt_config *cc)
++{
++ struct iv_essiv_private *essiv = &cc->iv_gen_private.essiv;
++ struct hash_desc desc;
++ struct scatterlist sg;
++ int err;
++
++ sg_init_one(&sg, cc->key, cc->key_size);
++ desc.tfm = essiv->hash_tfm;
++ desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
++
++ err = crypto_hash_digest(&desc, &sg, cc->key_size, essiv->salt);
++ if (err)
++ return err;
++
++ return crypto_cipher_setkey(essiv->tfm, essiv->salt,
++ crypto_hash_digestsize(essiv->hash_tfm));
++}
++
+ static void crypt_iv_essiv_dtr(struct crypt_config *cc)
+ {
+ struct iv_essiv_private *essiv = &cc->iv_gen_private.essiv;
+
+ crypto_free_cipher(essiv->tfm);
+ essiv->tfm = NULL;
++
++ crypto_free_hash(essiv->hash_tfm);
++ essiv->hash_tfm = NULL;
++
++ kzfree(essiv->salt);
++ essiv->salt = NULL;
+ }
+
+ static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti,
+@@ -189,9 +218,6 @@ static int crypt_iv_essiv_ctr(struct cry
+ {
+ struct crypto_cipher *essiv_tfm = NULL;
+ struct crypto_hash *hash_tfm = NULL;
+- struct hash_desc desc;
+- struct scatterlist sg;
+- unsigned int saltsize;
+ u8 *salt = NULL;
+ int err;
+
+@@ -200,7 +226,7 @@ static int crypt_iv_essiv_ctr(struct cry
+ return -EINVAL;
+ }
+
+- /* Hash the cipher key with the given hash algorithm */
++ /* Allocate hash algorithm */
+ hash_tfm = crypto_alloc_hash(opts, 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(hash_tfm)) {
+ ti->error = "Error initializing ESSIV hash";
+@@ -208,27 +234,14 @@ static int crypt_iv_essiv_ctr(struct cry
+ goto bad;
+ }
+
+- saltsize = crypto_hash_digestsize(hash_tfm);
+- salt = kzalloc(saltsize, GFP_KERNEL);
++ salt = kzalloc(crypto_hash_digestsize(hash_tfm), GFP_KERNEL);
+ if (!salt) {
+ ti->error = "Error kmallocing salt storage in ESSIV";
+ err = -ENOMEM;
+ goto bad;
+ }
+
+- sg_init_one(&sg, cc->key, cc->key_size);
+- desc.tfm = hash_tfm;
+- desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+- err = crypto_hash_digest(&desc, &sg, cc->key_size, salt);
+- crypto_free_hash(hash_tfm);
+- hash_tfm = NULL;
+-
+- if (err) {
+- ti->error = "Error calculating hash in ESSIV";
+- goto bad;
+- }
+-
+- /* Setup the essiv_tfm with the given salt */
++ /* Allocate essiv_tfm */
+ essiv_tfm = crypto_alloc_cipher(cc->cipher, 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(essiv_tfm)) {
+ ti->error = "Error allocating crypto tfm for ESSIV";
+@@ -242,14 +255,11 @@ static int crypt_iv_essiv_ctr(struct cry
+ err = -EINVAL;
+ goto bad;
+ }
+- err = crypto_cipher_setkey(essiv_tfm, salt, saltsize);
+- if (err) {
+- ti->error = "Failed to set key for ESSIV cipher";
+- goto bad;
+- }
+- kzfree(salt);
+
++ cc->iv_gen_private.essiv.salt = salt;
+ cc->iv_gen_private.essiv.tfm = essiv_tfm;
++ cc->iv_gen_private.essiv.hash_tfm = hash_tfm;
++
+ return 0;
+
+ bad:
+@@ -257,7 +267,7 @@ bad:
+ crypto_free_cipher(essiv_tfm);
+ if (hash_tfm && !IS_ERR(hash_tfm))
+ crypto_free_hash(hash_tfm);
+- kzfree(salt);
++ kfree(salt);
+ return err;
+ }
+
+@@ -323,6 +333,7 @@ static struct crypt_iv_operations crypt_
+ static struct crypt_iv_operations crypt_iv_essiv_ops = {
+ .ctr = crypt_iv_essiv_ctr,
+ .dtr = crypt_iv_essiv_dtr,
++ .init = crypt_iv_essiv_init,
+ .generator = crypt_iv_essiv_gen
+ };
+
+@@ -1054,6 +1065,12 @@ static int crypt_ctr(struct dm_target *t
+ cc->iv_gen_ops->ctr(cc, ti, ivopts) < 0)
+ goto bad_ivmode;
+
++ if (cc->iv_gen_ops && cc->iv_gen_ops->init &&
++ cc->iv_gen_ops->init(cc) < 0) {
++ ti->error = "Error initialising IV";
++ goto bad_slab_pool;
++ }
++
+ cc->iv_size = crypto_ablkcipher_ivsize(tfm);
+ if (cc->iv_size)
+ /* at least a 64 bit sector number should fit in our buffer */
--- /dev/null
+From 613978f8711c7fd4d0aa856872375d2abd7c92ff Mon Sep 17 00:00:00 2001
+From: Julia Lawall <julia@diku.dk>
+Date: Thu, 10 Dec 2009 23:51:52 +0000
+Subject: dm exception store: free tmp_store on persistent flag error
+
+From: Julia Lawall <julia@diku.dk>
+
+commit 613978f8711c7fd4d0aa856872375d2abd7c92ff upstream.
+
+Error handling code following a kmalloc should free the allocated data.
+
+Signed-off-by: Julia Lawall <julia@diku.dk>
+Signed-off-by: Alasdair G Kergon <agk@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/md/dm-exception-store.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/md/dm-exception-store.c
++++ b/drivers/md/dm-exception-store.c
+@@ -216,7 +216,8 @@ int dm_exception_store_create(struct dm_
+ type = get_type("N");
+ else {
+ ti->error = "Persistent flag is not P or N";
+- return -EINVAL;
++ r = -EINVAL;
++ goto bad_type;
+ }
+
+ if (!type) {
--- /dev/null
+From 8e87b9b81b3c370f7e53c1ab6e1c3519ef37a644 Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+Date: Thu, 10 Dec 2009 23:51:54 +0000
+Subject: dm snapshot: cope with chunk size larger than origin
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+commit 8e87b9b81b3c370f7e53c1ab6e1c3519ef37a644 upstream.
+
+Under some special conditions the snapshot hash_size is calculated as zero.
+This patch instead sets a minimum value of 64, the same as for the
+pending exception table.
+
+rounddown_pow_of_two(0) is an undefined operation (it expands to shift
+by -1). init_exception_table with an argument of 0 would fail with -ENOMEM.
+
+The way to trigger the problem is to create a snapshot with a chunk size
+that is larger than the origin device.
+
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Signed-off-by: Alasdair G Kergon <agk@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/md/dm-snap.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/md/dm-snap.c
++++ b/drivers/md/dm-snap.c
+@@ -553,6 +553,8 @@ static int init_hash_tables(struct dm_sn
+ hash_size = min(origin_dev_size, cow_dev_size) >> s->store->chunk_shift;
+ hash_size = min(hash_size, max_buckets);
+
++ if (hash_size < 64)
++ hash_size = 64;
+ hash_size = rounddown_pow_of_two(hash_size);
+ if (init_exception_table(&s->complete, hash_size,
+ DM_CHUNK_CONSECUTIVE_BITS))
--- /dev/null
+From 94e76572b5dd37b1f0f4b3742ee8a565daead932 Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+Date: Thu, 10 Dec 2009 23:51:53 +0000
+Subject: dm snapshot: only take lock for statustype info not table
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+commit 94e76572b5dd37b1f0f4b3742ee8a565daead932 upstream.
+
+Take snapshot lock only for STATUSTYPE_INFO, not STATUSTYPE_TABLE.
+
+Commit 4c6fff445d7aa753957856278d4d93bcad6e2c14
+(dm-snapshot-lock-snapshot-while-supplying-status.patch)
+introduced this use of the lock, but userspace applications using
+libdevmapper have been found to request STATUSTYPE_TABLE while the device
+is suspended and the lock is already held, leading to deadlock. Since
+the lock is not necessary in this case, don't try to take it.
+
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Signed-off-by: Alasdair G Kergon <agk@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/md/dm-snap.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+--- a/drivers/md/dm-snap.c
++++ b/drivers/md/dm-snap.c
+@@ -1152,10 +1152,11 @@ static int snapshot_status(struct dm_tar
+ unsigned sz = 0;
+ struct dm_snapshot *snap = ti->private;
+
+- down_write(&snap->lock);
+-
+ switch (type) {
+ case STATUSTYPE_INFO:
++
++ down_write(&snap->lock);
++
+ if (!snap->valid)
+ DMEMIT("Invalid");
+ else {
+@@ -1171,6 +1172,9 @@ static int snapshot_status(struct dm_tar
+ else
+ DMEMIT("Unknown");
+ }
++
++ up_write(&snap->lock);
++
+ break;
+
+ case STATUSTYPE_TABLE:
+@@ -1185,8 +1189,6 @@ static int snapshot_status(struct dm_tar
+ break;
+ }
+
+- up_write(&snap->lock);
+-
+ return 0;
+ }
+
--- /dev/null
+From 3589972e51fac1e02d0aaa576fa47f568cb94d40 Mon Sep 17 00:00:00 2001
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Fri, 4 Dec 2009 11:06:57 -0500
+Subject: Driver core: fix race in dev_driver_string
+
+From: Alan Stern <stern@rowland.harvard.edu>
+
+commit 3589972e51fac1e02d0aaa576fa47f568cb94d40 upstream.
+
+This patch (as1310) works around a race in dev_driver_string(). If
+the device is unbound while the function is running, dev->driver might
+become NULL after we test it and before we dereference it.
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Cc: Oliver Neukum <oliver@neukum.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/base/core.c | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+--- a/drivers/base/core.c
++++ b/drivers/base/core.c
+@@ -56,7 +56,14 @@ static inline int device_is_not_partitio
+ */
+ const char *dev_driver_string(const struct device *dev)
+ {
+- return dev->driver ? dev->driver->name :
++ struct device_driver *drv;
++
++ /* dev->driver can change to NULL underneath us because of unbinding,
++ * so be careful about accessing it. dev->bus and dev->class should
++ * never change once they are set, so they don't need special care.
++ */
++ drv = ACCESS_ONCE(dev->driver);
++ return drv ? drv->name :
+ (dev->bus ? dev->bus->name :
+ (dev->class ? dev->class->name : ""));
+ }
--- /dev/null
+From 652af9d74e1a3a10bb10f0d8e8f42ddac26bbc1a Mon Sep 17 00:00:00 2001
+From: Zhao Yakui <yakui.zhao@intel.com>
+Date: Wed, 2 Dec 2009 10:03:33 +0800
+Subject: drm/i915: Add the missing clonemask for display port on Ironlake
+
+From: Zhao Yakui <yakui.zhao@intel.com>
+
+commit 652af9d74e1a3a10bb10f0d8e8f42ddac26bbc1a upstream.
+
+Add the missing clonemask for display port on Ironlake.
+
+Signed-off-by: Zhao Yakui <yakui.zhao@intel.com>
+Reviewed-by: Zhenyu Wang <zhenyuw@linux.intel.com>
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/gpu/drm/i915/intel_dp.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/gpu/drm/i915/intel_dp.c
++++ b/drivers/gpu/drm/i915/intel_dp.c
+@@ -1254,11 +1254,11 @@ intel_dp_init(struct drm_device *dev, in
+ else
+ intel_output->type = INTEL_OUTPUT_DISPLAYPORT;
+
+- if (output_reg == DP_B)
++ if (output_reg == DP_B || output_reg == PCH_DP_B)
+ intel_output->clone_mask = (1 << INTEL_DP_B_CLONE_BIT);
+- else if (output_reg == DP_C)
++ else if (output_reg == DP_C || output_reg == PCH_DP_C)
+ intel_output->clone_mask = (1 << INTEL_DP_C_CLONE_BIT);
+- else if (output_reg == DP_D)
++ else if (output_reg == DP_D || output_reg == PCH_DP_D)
+ intel_output->clone_mask = (1 << INTEL_DP_D_CLONE_BIT);
+
+ if (IS_eDP(intel_output)) {
--- /dev/null
+From 5618ca6abc2d6f475b258badc017a5254cf43d1b Mon Sep 17 00:00:00 2001
+From: Chris Wilson <chris@chris-wilson.co.uk>
+Date: Wed, 2 Dec 2009 15:15:30 +0000
+Subject: drm/i915: Set the error code after failing to insert new offset into mm ht.
+
+From: Chris Wilson <chris@chris-wilson.co.uk>
+
+commit 5618ca6abc2d6f475b258badc017a5254cf43d1b upstream.
+
+Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/gpu/drm/i915/i915_gem.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/gpu/drm/i915/i915_gem.c
++++ b/drivers/gpu/drm/i915/i915_gem.c
+@@ -1288,6 +1288,7 @@ i915_gem_create_mmap_offset(struct drm_g
+ list->hash.key = list->file_offset_node->start;
+ if (drm_ht_insert_item(&mm->offset_hash, &list->hash)) {
+ DRM_ERROR("failed to add to map hash\n");
++ ret = -ENOMEM;
+ goto out_free_mm;
+ }
+
--- /dev/null
+From 4e3f9b78ff917cc5c833858fdb5d96bc262e0bf3 Mon Sep 17 00:00:00 2001
+From: Alex Deucher <alexdeucher@gmail.com>
+Date: Tue, 1 Dec 2009 14:49:50 -0500
+Subject: drm/radeon/kms: Add quirk for HIS X1300 board
+
+From: Alex Deucher <alexdeucher@gmail.com>
+
+commit 4e3f9b78ff917cc5c833858fdb5d96bc262e0bf3 upstream.
+
+Board is DVI+VGA, not DVI+DVI
+
+Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
+Signed-off-by: Dave Airlie <airlied@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/gpu/drm/radeon/radeon_atombios.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/drivers/gpu/drm/radeon/radeon_atombios.c
++++ b/drivers/gpu/drm/radeon/radeon_atombios.c
+@@ -135,6 +135,14 @@ static bool radeon_atom_apply_quirks(str
+ }
+ }
+
++ /* HIS X1300 is DVI+VGA, not DVI+DVI */
++ if ((dev->pdev->device == 0x7146) &&
++ (dev->pdev->subsystem_vendor == 0x17af) &&
++ (dev->pdev->subsystem_device == 0x2058)) {
++ if (supported_device == ATOM_DEVICE_DFP1_SUPPORT)
++ return false;
++ }
++
+ /* Funky macbooks */
+ if ((dev->pdev->device == 0x71C5) &&
+ (dev->pdev->subsystem_vendor == 0x106b) &&
--- /dev/null
+From 8de21525439e6b5bb8d8c81e49094d867bf82f6d Mon Sep 17 00:00:00 2001
+From: Alex Deucher <alexdeucher@gmail.com>
+Date: Thu, 3 Dec 2009 12:15:54 -0500
+Subject: drm/radeon/kms: fix legacy crtc2 dpms
+
+From: Alex Deucher <alexdeucher@gmail.com>
+
+commit 8de21525439e6b5bb8d8c81e49094d867bf82f6d upstream.
+
+noticed by Matthijs Kooijman on fdo bug 22140
+
+Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
+Signed-off-by: Dave Airlie <airlied@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/gpu/drm/radeon/radeon_legacy_crtc.c | 7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+--- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
++++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
+@@ -292,8 +292,7 @@ void radeon_crtc_dpms(struct drm_crtc *c
+ uint32_t mask;
+
+ if (radeon_crtc->crtc_id)
+- mask = (RADEON_CRTC2_EN |
+- RADEON_CRTC2_DISP_DIS |
++ mask = (RADEON_CRTC2_DISP_DIS |
+ RADEON_CRTC2_VSYNC_DIS |
+ RADEON_CRTC2_HSYNC_DIS |
+ RADEON_CRTC2_DISP_REQ_EN_B);
+@@ -305,7 +304,7 @@ void radeon_crtc_dpms(struct drm_crtc *c
+ switch (mode) {
+ case DRM_MODE_DPMS_ON:
+ if (radeon_crtc->crtc_id)
+- WREG32_P(RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_EN, ~mask);
++ WREG32_P(RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_EN, ~(RADEON_CRTC2_EN | mask));
+ else {
+ WREG32_P(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_EN, ~(RADEON_CRTC_EN |
+ RADEON_CRTC_DISP_REQ_EN_B));
+@@ -319,7 +318,7 @@ void radeon_crtc_dpms(struct drm_crtc *c
+ case DRM_MODE_DPMS_OFF:
+ drm_vblank_pre_modeset(dev, radeon_crtc->crtc_id);
+ if (radeon_crtc->crtc_id)
+- WREG32_P(RADEON_CRTC2_GEN_CNTL, mask, ~mask);
++ WREG32_P(RADEON_CRTC2_GEN_CNTL, mask, ~(RADEON_CRTC2_EN | mask));
+ else {
+ WREG32_P(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_DISP_REQ_EN_B, ~(RADEON_CRTC_EN |
+ RADEON_CRTC_DISP_REQ_EN_B));
--- /dev/null
+From 722f29434e72188b2d20f9b41f4b5952073ed568 Mon Sep 17 00:00:00 2001
+From: Alex Deucher <alexdeucher@gmail.com>
+Date: Thu, 3 Dec 2009 16:18:19 -0500
+Subject: drm/radeon/kms: fix vram setup on rs600
+
+From: Alex Deucher <alexdeucher@gmail.com>
+
+commit 722f29434e72188b2d20f9b41f4b5952073ed568 upstream.
+
+also fix up rs690 mem width.
+
+should fix fdo bug 25408
+
+Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
+Signed-off-by: Dave Airlie <airlied@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/gpu/drm/radeon/rs600.c | 6 ++++++
+ drivers/gpu/drm/radeon/rs690.c | 10 ++--------
+ 2 files changed, 8 insertions(+), 8 deletions(-)
+
+--- a/drivers/gpu/drm/radeon/rs600.c
++++ b/drivers/gpu/drm/radeon/rs600.c
+@@ -315,6 +315,12 @@ void rs600_vram_info(struct radeon_devic
+ /* FIXME: to do or is these values sane ? */
+ rdev->mc.vram_is_ddr = true;
+ rdev->mc.vram_width = 128;
++
++ rdev->mc.real_vram_size = RREG32(RADEON_CONFIG_MEMSIZE);
++ rdev->mc.mc_vram_size = rdev->mc.real_vram_size;
++
++ rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);
++ rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0);
+ }
+
+ void rs600_bandwidth_update(struct radeon_device *rdev)
+--- a/drivers/gpu/drm/radeon/rs690.c
++++ b/drivers/gpu/drm/radeon/rs690.c
+@@ -131,19 +131,13 @@ void rs690_pm_info(struct radeon_device
+
+ void rs690_vram_info(struct radeon_device *rdev)
+ {
+- uint32_t tmp;
+ fixed20_12 a;
+
+ rs400_gart_adjust_size(rdev);
+ /* DDR for all card after R300 & IGP */
+ rdev->mc.vram_is_ddr = true;
+- /* FIXME: is this correct for RS690/RS740 ? */
+- tmp = RREG32(RADEON_MEM_CNTL);
+- if (tmp & R300_MEM_NUM_CHANNELS_MASK) {
+- rdev->mc.vram_width = 128;
+- } else {
+- rdev->mc.vram_width = 64;
+- }
++ rdev->mc.vram_width = 128;
++
+ rdev->mc.real_vram_size = RREG32(RADEON_CONFIG_MEMSIZE);
+ rdev->mc.mc_vram_size = rdev->mc.real_vram_size;
+
--- /dev/null
+From 500b758725314ab1b5316eb0caa5b0fa26740e6b Mon Sep 17 00:00:00 2001
+From: Alex Deucher <alexdeucher@gmail.com>
+Date: Wed, 2 Dec 2009 11:46:52 -0500
+Subject: drm/radeon/kms: handle vblanks properly with dpms on
+
+From: Alex Deucher <alexdeucher@gmail.com>
+
+commit 500b758725314ab1b5316eb0caa5b0fa26740e6b upstream.
+
+avivo chips
+
+Copied from pre-avivo code.
+
+Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
+Signed-off-by: Dave Airlie <airlied@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/gpu/drm/radeon/atombios_crtc.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/drivers/gpu/drm/radeon/atombios_crtc.c
++++ b/drivers/gpu/drm/radeon/atombios_crtc.c
+@@ -241,6 +241,7 @@ void atombios_crtc_dpms(struct drm_crtc
+ {
+ struct drm_device *dev = crtc->dev;
+ struct radeon_device *rdev = dev->dev_private;
++ struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+
+ switch (mode) {
+ case DRM_MODE_DPMS_ON:
+@@ -248,20 +249,19 @@ void atombios_crtc_dpms(struct drm_crtc
+ if (ASIC_IS_DCE3(rdev))
+ atombios_enable_crtc_memreq(crtc, 1);
+ atombios_blank_crtc(crtc, 0);
++ drm_vblank_post_modeset(dev, radeon_crtc->crtc_id);
++ radeon_crtc_load_lut(crtc);
+ break;
+ case DRM_MODE_DPMS_STANDBY:
+ case DRM_MODE_DPMS_SUSPEND:
+ case DRM_MODE_DPMS_OFF:
++ drm_vblank_pre_modeset(dev, radeon_crtc->crtc_id);
+ atombios_blank_crtc(crtc, 1);
+ if (ASIC_IS_DCE3(rdev))
+ atombios_enable_crtc_memreq(crtc, 0);
+ atombios_enable_crtc(crtc, 0);
+ break;
+ }
+-
+- if (mode != DRM_MODE_DPMS_OFF) {
+- radeon_crtc_load_lut(crtc);
+- }
+ }
+
+ static void
--- /dev/null
+From 0088dbdb809e8799cb8f26da5ac64b15201fa99d Mon Sep 17 00:00:00 2001
+From: Alex Deucher <alexdeucher@gmail.com>
+Date: Thu, 3 Dec 2009 16:28:02 -0500
+Subject: drm/radeon/kms: rs6xx/rs740: clamp vram to aperture size
+
+From: Alex Deucher <alexdeucher@gmail.com>
+
+commit 0088dbdb809e8799cb8f26da5ac64b15201fa99d upstream.
+
+Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
+Signed-off-by: Dave Airlie <airlied@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/gpu/drm/radeon/rs600.c | 9 ++++++---
+ drivers/gpu/drm/radeon/rs690.c | 9 ++++++++-
+ 2 files changed, 14 insertions(+), 4 deletions(-)
+
+--- a/drivers/gpu/drm/radeon/rs600.c
++++ b/drivers/gpu/drm/radeon/rs600.c
+@@ -301,9 +301,7 @@ int rs600_mc_wait_for_idle(struct radeon
+
+ void rs600_gpu_init(struct radeon_device *rdev)
+ {
+- /* FIXME: HDP same place on rs600 ? */
+ r100_hdp_reset(rdev);
+- /* FIXME: is this correct ? */
+ r420_pipes_init(rdev);
+ /* Wait for mc idle */
+ if (rs600_mc_wait_for_idle(rdev))
+@@ -312,7 +310,6 @@ void rs600_gpu_init(struct radeon_device
+
+ void rs600_vram_info(struct radeon_device *rdev)
+ {
+- /* FIXME: to do or is these values sane ? */
+ rdev->mc.vram_is_ddr = true;
+ rdev->mc.vram_width = 128;
+
+@@ -321,6 +318,12 @@ void rs600_vram_info(struct radeon_devic
+
+ rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);
+ rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0);
++
++ if (rdev->mc.mc_vram_size > rdev->mc.aper_size)
++ rdev->mc.mc_vram_size = rdev->mc.aper_size;
++
++ if (rdev->mc.real_vram_size > rdev->mc.aper_size)
++ rdev->mc.real_vram_size = rdev->mc.aper_size;
+ }
+
+ void rs600_bandwidth_update(struct radeon_device *rdev)
+--- a/drivers/gpu/drm/radeon/rs690.c
++++ b/drivers/gpu/drm/radeon/rs690.c
+@@ -134,7 +134,7 @@ void rs690_vram_info(struct radeon_devic
+ fixed20_12 a;
+
+ rs400_gart_adjust_size(rdev);
+- /* DDR for all card after R300 & IGP */
++
+ rdev->mc.vram_is_ddr = true;
+ rdev->mc.vram_width = 128;
+
+@@ -143,6 +143,13 @@ void rs690_vram_info(struct radeon_devic
+
+ rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);
+ rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0);
++
++ if (rdev->mc.mc_vram_size > rdev->mc.aper_size)
++ rdev->mc.mc_vram_size = rdev->mc.aper_size;
++
++ if (rdev->mc.real_vram_size > rdev->mc.aper_size)
++ rdev->mc.real_vram_size = rdev->mc.aper_size;
++
+ rs690_pm_info(rdev);
+ /* FIXME: we should enforce default clock in case GPU is not in
+ * default setup
--- /dev/null
+From c3a73ba13bac7fd96030f39202b2d37fb19c46a6 Mon Sep 17 00:00:00 2001
+From: Martin Michlmayr <tbm@cyrius.com>
+Date: Thu, 19 Nov 2009 16:29:45 +0000
+Subject: drm/ttm: Fix build failure due to missing struct page
+
+From: Martin Michlmayr <tbm@cyrius.com>
+
+commit c3a73ba13bac7fd96030f39202b2d37fb19c46a6 upstream.
+
+drm/ttm fails to build on MIPS because "struct page" is not known:
+| In file included from drivers/gpu/drm/ttm/ttm_memory.c:28:
+| include/drm/ttm/ttm_memory.h:154: warning: 'struct page' declared inside parameter list
+| include/drm/ttm/ttm_memory.h:154: warning: its scope is only this definition or declaration, which is probably not what you want
+| include/drm/ttm/ttm_memory.h:156: warning: 'struct page' declared inside parameter list
+| drivers/gpu/drm/ttm/ttm_memory.c:540: error: conflicting types for 'ttm_mem_global_alloc_page'
+| include/drm/ttm/ttm_memory.h:154: error: previous declaration of 'ttm_mem_global_alloc_page' was here
+| drivers/gpu/drm/ttm/ttm_memory.c:561: error: conflicting types for 'ttm_mem_global_free_page'
+| include/drm/ttm/ttm_memory.h:156: error: previous declaration of 'ttm_mem_global_free_page' was here
+
+Signed-off-by: Martin Michlmayr <tbm@cyrius.com>
+Acked-by: Thomas Hellstrom <thellstrom@vmware.com>
+Signed-off-by: Dave Airlie <airlied@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ include/drm/ttm/ttm_memory.h | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/include/drm/ttm/ttm_memory.h
++++ b/include/drm/ttm/ttm_memory.h
+@@ -33,6 +33,7 @@
+ #include <linux/wait.h>
+ #include <linux/errno.h>
+ #include <linux/kobject.h>
++#include <linux/mm.h>
+
+ /**
+ * struct ttm_mem_shrink - callback to shrink TTM memory usage.
--- /dev/null
+From 1814077fd12a9cdf478c10076e9c42094e9d9250 Mon Sep 17 00:00:00 2001
+From: Vasanthakumar Thiagarajan <vasanth@atheros.com>
+Date: Fri, 4 Dec 2009 17:41:34 +0530
+Subject: mac80211: Fix bug in computing crc over dynamic IEs in beacon
+
+From: Vasanthakumar Thiagarajan <vasanth@atheros.com>
+
+commit 1814077fd12a9cdf478c10076e9c42094e9d9250 upstream.
+
+On a 32-bit machine, BIT() macro does not give the required
+bit value if the bit is mroe than 31. In ieee802_11_parse_elems_crc(),
+BIT() is suppossed to get the bit value more than 31 (42 (id of ERP_INFO_IE),
+37 (CHANNEL_SWITCH_IE), (42), 32 (POWER_CONSTRAINT_IE), 45 (HT_CAP_IE),
+61 (HT_INFO_IE)). As we do not get the required bit value for the above
+IEs, crc over these IEs are never calculated, so any dynamic change in these
+IEs after the association is not really handled on 32-bit platforms.
+This patch fixes this issue.
+
+Signed-off-by: Vasanthakumar Thiagarajan <vasanth@atheros.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ net/mac80211/util.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/net/mac80211/util.c
++++ b/net/mac80211/util.c
+@@ -579,7 +579,7 @@ u32 ieee802_11_parse_elems_crc(u8 *start
+ if (elen > left)
+ break;
+
+- if (calc_crc && id < 64 && (filter & BIT(id)))
++ if (calc_crc && id < 64 && (filter & (1ULL << id)))
+ crc = crc32_be(crc, pos - 2, elen + 2);
+
+ switch (id) {
--- /dev/null
+From 6d3560d4fc9c5b9fe1a07a63926ea70512c69c32 Mon Sep 17 00:00:00 2001
+From: Johannes Berg <johannes@sipsolutions.net>
+Date: Sat, 31 Oct 2009 07:44:08 +0100
+Subject: mac80211: fix scan abort sanity checks
+
+From: Johannes Berg <johannes@sipsolutions.net>
+
+commit 6d3560d4fc9c5b9fe1a07a63926ea70512c69c32 upstream.
+
+Since sometimes mac80211 queues up a scan request
+to only act on it later, it must be allowed to
+(internally) cancel a not-yet-running scan, e.g.
+when the interface is taken down. This condition
+was missing since we always checked only the
+local->scanning variable which isn't yet set in
+that situation.
+
+Reported-by: Luis R. Rodriguez <mcgrof@gmail.com>
+Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ net/mac80211/scan.c | 12 ++++++++----
+ 1 file changed, 8 insertions(+), 4 deletions(-)
+
+--- a/net/mac80211/scan.c
++++ b/net/mac80211/scan.c
+@@ -264,10 +264,14 @@ void ieee80211_scan_completed(struct iee
+
+ mutex_lock(&local->scan_mtx);
+
+- if (WARN_ON(!local->scanning)) {
+- mutex_unlock(&local->scan_mtx);
+- return;
+- }
++ /*
++ * It's ok to abort a not-yet-running scan (that
++ * we have one at all will be verified by checking
++ * local->scan_req next), but not to complete it
++ * successfully.
++ */
++ if (WARN_ON(!local->scanning && !aborted))
++ aborted = true;
+
+ if (WARN_ON(!local->scan_req)) {
+ mutex_unlock(&local->scan_mtx);
--- /dev/null
+From 5d618cb81aeea19879975cd1f9a1e707694dfd7c Mon Sep 17 00:00:00 2001
+From: Javier Cardona <javier@cozybit.com>
+Date: Wed, 9 Dec 2009 18:43:00 -0800
+Subject: mac80211: Fixed bug in mesh portal paths
+
+From: Javier Cardona <javier@cozybit.com>
+
+commit 5d618cb81aeea19879975cd1f9a1e707694dfd7c upstream.
+
+Paths to mesh portals were being timed out immediately after each use in
+intermediate forwarding nodes. mppath->exp_time is set to the expiration time
+so assigning it to jiffies was marking the path as expired.
+
+Signed-off-by: Javier Cardona <javier@cozybit.com>
+Signed-off-by: Andrey Yurovsky <andrey@cozybit.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ net/mac80211/rx.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -1514,7 +1514,6 @@ ieee80211_rx_h_mesh_fwding(struct ieee80
+ mpp_path_add(mesh_hdr->eaddr2, hdr->addr4, sdata);
+ } else {
+ spin_lock_bh(&mppath->state_lock);
+- mppath->exp_time = jiffies;
+ if (compare_ether_addr(mppath->mpp, hdr->addr4) != 0)
+ memcpy(mppath->mpp, hdr->addr4, ETH_ALEN);
+ spin_unlock_bh(&mppath->state_lock);
--- /dev/null
+From 7b324d28a94dac5a451e8cba66e8d324601e5b9a Mon Sep 17 00:00:00 2001
+From: Javier Cardona <javier@cozybit.com>
+Date: Wed, 9 Dec 2009 18:43:01 -0800
+Subject: mac80211: Revert 'Use correct sign for mesh active path refresh'
+
+From: Javier Cardona <javier@cozybit.com>
+
+commit 7b324d28a94dac5a451e8cba66e8d324601e5b9a upstream.
+
+The patch ("mac80211: Use correct sign for mesh active path
+refresh.") was actually a bug. Reverted it and improved the
+explanation of how mesh path refresh works.
+
+Signed-off-by: Javier Cardona <javier@cozybit.com>
+Signed-off-by: Andrey Yurovsky <andrey@cozybit.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ net/mac80211/mesh.h | 5 +++--
+ net/mac80211/mesh_hwmp.c | 2 +-
+ 2 files changed, 4 insertions(+), 3 deletions(-)
+
+--- a/net/mac80211/mesh.h
++++ b/net/mac80211/mesh.h
+@@ -186,8 +186,9 @@ struct mesh_rmc {
+ */
+ #define MESH_PREQ_MIN_INT 10
+ #define MESH_DIAM_TRAVERSAL_TIME 50
+-/* Paths will be refreshed if they are closer than PATH_REFRESH_TIME to their
+- * expiration
++/* A path will be refreshed if it is used PATH_REFRESH_TIME milliseconds before
++ * timing out. This way it will remain ACTIVE and no data frames will be
++ * unnecesarily held in the pending queue.
+ */
+ #define MESH_PATH_REFRESH_TIME 1000
+ #define MESH_MIN_DISCOVERY_TIMEOUT (2 * MESH_DIAM_TRAVERSAL_TIME)
+--- a/net/mac80211/mesh_hwmp.c
++++ b/net/mac80211/mesh_hwmp.c
+@@ -813,7 +813,7 @@ int mesh_nexthop_lookup(struct sk_buff *
+ }
+
+ if (mpath->flags & MESH_PATH_ACTIVE) {
+- if (time_after(jiffies, mpath->exp_time +
++ if (time_after(jiffies, mpath->exp_time -
+ msecs_to_jiffies(sdata->u.mesh.mshcfg.path_refresh_time))
+ && !memcmp(sdata->dev->dev_addr, hdr->addr4,
+ ETH_ALEN)
--- /dev/null
+From 4f16fc107d9c9b8a72aa19b189a9216e90a7aaef Mon Sep 17 00:00:00 2001
+From: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
+Date: Mon, 14 Dec 2009 17:59:58 -0800
+Subject: mm: hugetlb: fix hugepage memory leak in mincore()
+
+From: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
+
+commit 4f16fc107d9c9b8a72aa19b189a9216e90a7aaef upstream.
+
+Most callers of pmd_none_or_clear_bad() check whether the target page is
+in a hugepage or not, but mincore() and walk_page_range() do not check it.
+ So if we use mincore() on a hugepage on x86 machine, the hugepage memory
+is leaked as shown below. This patch fixes it by extending mincore()
+system call to support hugepages.
+
+Details
+=======
+My test program (leak_mincore) works as follows:
+ - creat() and mmap() a file on hugetlbfs (file size is 200MB == 100 hugepages,)
+ - read()/write() something on it,
+ - call mincore() for first ten pages and printf() the values of *vec
+ - munmap() and unlink() the file on hugetlbfs
+
+Without my patch
+----------------
+$ cat /proc/meminfo| grep "HugePage"
+HugePages_Total: 1000
+HugePages_Free: 1000
+HugePages_Rsvd: 0
+HugePages_Surp: 0
+$ ./leak_mincore
+vec[0] 0
+vec[1] 0
+vec[2] 0
+vec[3] 0
+vec[4] 0
+vec[5] 0
+vec[6] 0
+vec[7] 0
+vec[8] 0
+vec[9] 0
+$ cat /proc/meminfo |grep "HugePage"
+HugePages_Total: 1000
+HugePages_Free: 999
+HugePages_Rsvd: 0
+HugePages_Surp: 0
+$ ls /hugetlbfs/
+$
+
+Return values in *vec from mincore() are set to 0, while the hugepage
+should be in memory, and 1 hugepage is still accounted as used while
+there is no file on hugetlbfs.
+
+With my patch
+-------------
+$ cat /proc/meminfo| grep "HugePage"
+HugePages_Total: 1000
+HugePages_Free: 1000
+HugePages_Rsvd: 0
+HugePages_Surp: 0
+$ ./leak_mincore
+vec[0] 1
+vec[1] 1
+vec[2] 1
+vec[3] 1
+vec[4] 1
+vec[5] 1
+vec[6] 1
+vec[7] 1
+vec[8] 1
+vec[9] 1
+$ cat /proc/meminfo |grep "HugePage"
+HugePages_Total: 1000
+HugePages_Free: 1000
+HugePages_Rsvd: 0
+HugePages_Surp: 0
+$ ls /hugetlbfs/
+$
+
+Return value in *vec set to 1 and no memory leaks.
+
+[akpm@linux-foundation.org: cleanup]
+[akpm@linux-foundation.org: build fix]
+Signed-off-by: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
+Cc: Andi Kleen <ak@linux.intel.com>
+Cc: Wu Fengguang <fengguang.wu@intel.com>
+Cc: Hugh Dickins <hugh.dickins@tiscali.co.uk>
+Cc: Mel Gorman <mel@csn.ul.ie>
+Cc: Lee Schermerhorn <lee.schermerhorn@hp.com>
+Cc: Andy Whitcroft <apw@canonical.com>
+Cc: David Rientjes <rientjes@google.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+--- a/mm/mincore.c
++++ b/mm/mincore.c
+@@ -14,6 +14,7 @@
+ #include <linux/syscalls.h>
+ #include <linux/swap.h>
+ #include <linux/swapops.h>
++#include <linux/hugetlb.h>
+
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -72,6 +73,42 @@ static long do_mincore(unsigned long addr, unsigned char *vec, unsigned long pag
+ if (!vma || addr < vma->vm_start)
+ return -ENOMEM;
+
++#ifdef CONFIG_HUGETLB_PAGE
++ if (is_vm_hugetlb_page(vma)) {
++ struct hstate *h;
++ unsigned long nr_huge;
++ unsigned char present;
++
++ i = 0;
++ nr = min(pages, (vma->vm_end - addr) >> PAGE_SHIFT);
++ h = hstate_vma(vma);
++ nr_huge = ((addr + pages * PAGE_SIZE - 1) >> huge_page_shift(h))
++ - (addr >> huge_page_shift(h)) + 1;
++ nr_huge = min(nr_huge,
++ (vma->vm_end - addr) >> huge_page_shift(h));
++ while (1) {
++ /* hugepage always in RAM for now,
++ * but generally it needs to be check */
++ ptep = huge_pte_offset(current->mm,
++ addr & huge_page_mask(h));
++ present = !!(ptep &&
++ !huge_pte_none(huge_ptep_get(ptep)));
++ while (1) {
++ vec[i++] = present;
++ addr += PAGE_SIZE;
++ /* reach buffer limit */
++ if (i == nr)
++ return nr;
++ /* check hugepage border */
++ if (!((addr & ~huge_page_mask(h))
++ >> PAGE_SHIFT))
++ break;
++ }
++ }
++ return nr;
++ }
++#endif
++
+ /*
+ * Calculate how many pages there are left in the last level of the
+ * PTE array for our address.
--- /dev/null
+From d33b9f45bd24a6391bc05e2b5a13c1b5787ca9c2 Mon Sep 17 00:00:00 2001
+From: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
+Date: Mon, 14 Dec 2009 17:59:59 -0800
+Subject: mm: hugetlb: fix hugepage memory leak in walk_page_range()
+
+From: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
+
+commit d33b9f45bd24a6391bc05e2b5a13c1b5787ca9c2 upstream.
+
+Most callers of pmd_none_or_clear_bad() check whether the target page is
+in a hugepage or not, but walk_page_range() do not check it. So if we
+read /proc/pid/pagemap for the hugepage on x86 machine, the hugepage
+memory is leaked as shown below. This patch fixes it.
+
+Details
+=======
+My test program (leak_pagemap) works as follows:
+ - creat() and mmap() a file on hugetlbfs (file size is 200MB == 100 hugepages,)
+ - read()/write() something on it,
+ - call page-types with option -p (walk around the page tables),
+ - munmap() and unlink() the file on hugetlbfs
+
+Without my patches
+------------------
+$ cat /proc/meminfo |grep "HugePage"
+HugePages_Total: 1000
+HugePages_Free: 1000
+HugePages_Rsvd: 0
+HugePages_Surp: 0
+$ ./leak_pagemap
+[snip output]
+$ cat /proc/meminfo |grep "HugePage"
+HugePages_Total: 1000
+HugePages_Free: 900
+HugePages_Rsvd: 0
+HugePages_Surp: 0
+$ ls /hugetlbfs/
+$
+
+100 hugepages are accounted as used while there is no file on hugetlbfs.
+
+With my patches
+---------------
+$ cat /proc/meminfo |grep "HugePage"
+HugePages_Total: 1000
+HugePages_Free: 1000
+HugePages_Rsvd: 0
+HugePages_Surp: 0
+$ ./leak_pagemap
+[snip output]
+$ cat /proc/meminfo |grep "HugePage"
+HugePages_Total: 1000
+HugePages_Free: 1000
+HugePages_Rsvd: 0
+HugePages_Surp: 0
+$ ls /hugetlbfs
+$
+
+No memory leaks.
+
+Signed-off-by: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
+Cc: Andi Kleen <ak@linux.intel.com>
+Cc: Wu Fengguang <fengguang.wu@intel.com>
+Cc: Hugh Dickins <hugh.dickins@tiscali.co.uk>
+Cc: Mel Gorman <mel@csn.ul.ie>
+Cc: Lee Schermerhorn <lee.schermerhorn@hp.com>
+Cc: Andy Whitcroft <apw@canonical.com>
+Cc: David Rientjes <rientjes@google.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ mm/pagewalk.c | 16 +++++++++++++++-
+ 1 file changed, 15 insertions(+), 1 deletion(-)
+
+--- a/mm/pagewalk.c
++++ b/mm/pagewalk.c
+@@ -1,6 +1,7 @@
+ #include <linux/mm.h>
+ #include <linux/highmem.h>
+ #include <linux/sched.h>
++#include <linux/hugetlb.h>
+
+ static int walk_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
+ struct mm_walk *walk)
+@@ -107,6 +108,7 @@ int walk_page_range(unsigned long addr,
+ pgd_t *pgd;
+ unsigned long next;
+ int err = 0;
++ struct vm_area_struct *vma;
+
+ if (addr >= end)
+ return err;
+@@ -117,11 +119,22 @@ int walk_page_range(unsigned long addr,
+ pgd = pgd_offset(walk->mm, addr);
+ do {
+ next = pgd_addr_end(addr, end);
++
++ /* skip hugetlb vma to avoid hugepage PMD being cleared
++ * in pmd_none_or_clear_bad(). */
++ vma = find_vma(walk->mm, addr);
++ if (vma && is_vm_hugetlb_page(vma)) {
++ if (vma->vm_end < next)
++ next = vma->vm_end;
++ continue;
++ }
++
+ if (pgd_none_or_clear_bad(pgd)) {
+ if (walk->pte_hole)
+ err = walk->pte_hole(addr, next, walk);
+ if (err)
+ break;
++ pgd++;
+ continue;
+ }
+ if (walk->pgd_entry)
+@@ -131,7 +144,8 @@ int walk_page_range(unsigned long addr,
+ err = walk_pud_range(pgd, addr, next, walk);
+ if (err)
+ break;
+- } while (pgd++, addr = next, addr != end);
++ pgd++;
++ } while (addr = next, addr != end);
+
+ return err;
+ }
--- /dev/null
+From e090aa80321b64c3b793f3b047e31ecf1af9538d Mon Sep 17 00:00:00 2001
+From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
+Date: Tue, 8 Dec 2009 18:45:45 +0000
+Subject: powerpc: Fix usage of 64-bit instruction in 32-bit altivec code
+
+From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
+
+commit e090aa80321b64c3b793f3b047e31ecf1af9538d upstream.
+
+e821ea70f3b4873b50056a1e0f74befed1014c09 introduced a bug by copying
+some 64-bit originated code as-is to be used by both 32 and 64-bit
+but this code contains a 64-bit ony "cmpdi" instruction.
+
+This changes it to cmpwi, which is fine since VRSAVE can only contains
+a 32-bit value anyway.
+
+Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/powerpc/kernel/vector.S | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/powerpc/kernel/vector.S
++++ b/arch/powerpc/kernel/vector.S
+@@ -58,7 +58,7 @@ _GLOBAL(load_up_altivec)
+ * all 1's
+ */
+ mfspr r4,SPRN_VRSAVE
+- cmpdi 0,r4,0
++ cmpwi 0,r4,0
+ bne+ 1f
+ li r4,-1
+ mtspr SPRN_VRSAVE,r4
--- /dev/null
+From 1496e89ae2a0962748e55165a590fa3209c6f158 Mon Sep 17 00:00:00 2001
+From: Darrick J. Wong <djwong@us.ibm.com>
+Date: Thu, 3 Dec 2009 16:19:59 +0000
+Subject: powerpc/therm_adt746x: Record pwm invert bit at module load time]
+
+From: Darrick J. Wong <djwong@us.ibm.com>
+
+commit 1496e89ae2a0962748e55165a590fa3209c6f158 upstream.
+
+In commit 0512a9a8e277a9de2820211eef964473b714ae65, we unilaterally zero the
+"pwm invert" bit in the fan behavior configuration register. On my PowerBook
+G4, this results in the fans going to full speed at low temperature and
+shutting off at high temperature because the pwm invert bit is supposed to be
+set.
+
+Therefore, record the pwm invert bit at driver load time, and write the bit
+into the fan behavior control register. This restores correct behavior on my
+PBG4 and should work around the bit being set to the wrong value after
+suspend/resume (which is what the original patch was trying to fix). It also
+fixes a minor omission where the pwm invert bit correction is NOT performed
+when switching into automatic mode.
+
+Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
+Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/macintosh/therm_adt746x.c | 13 +++++++++++--
+ 1 file changed, 11 insertions(+), 2 deletions(-)
+
+--- a/drivers/macintosh/therm_adt746x.c
++++ b/drivers/macintosh/therm_adt746x.c
+@@ -79,6 +79,7 @@ struct thermostat {
+ u8 limits[3];
+ int last_speed[2];
+ int last_var[2];
++ int pwm_inv[2];
+ };
+
+ static enum {ADT7460, ADT7467} therm_type;
+@@ -229,19 +230,23 @@ static void write_fan_speed(struct therm
+
+ if (speed >= 0) {
+ manual = read_reg(th, MANUAL_MODE[fan]);
++ manual &= ~INVERT_MASK;
+ write_reg(th, MANUAL_MODE[fan],
+- (manual|MANUAL_MASK) & (~INVERT_MASK));
++ manual | MANUAL_MASK | th->pwm_inv[fan]);
+ write_reg(th, FAN_SPD_SET[fan], speed);
+ } else {
+ /* back to automatic */
+ if(therm_type == ADT7460) {
+ manual = read_reg(th,
+ MANUAL_MODE[fan]) & (~MANUAL_MASK);
+-
++ manual &= ~INVERT_MASK;
++ manual |= th->pwm_inv[fan];
+ write_reg(th,
+ MANUAL_MODE[fan], manual|REM_CONTROL[fan]);
+ } else {
+ manual = read_reg(th, MANUAL_MODE[fan]);
++ manual &= ~INVERT_MASK;
++ manual |= th->pwm_inv[fan];
+ write_reg(th, MANUAL_MODE[fan], manual&(~AUTO_MASK));
+ }
+ }
+@@ -418,6 +423,10 @@ static int probe_thermostat(struct i2c_c
+
+ thermostat = th;
+
++ /* record invert bit status because fw can corrupt it after suspend */
++ th->pwm_inv[0] = read_reg(th, MANUAL_MODE[0]) & INVERT_MASK;
++ th->pwm_inv[1] = read_reg(th, MANUAL_MODE[1]) & INVERT_MASK;
++
+ /* be sure to really write fan speed the first time */
+ th->last_speed[0] = -2;
+ th->last_speed[1] = -2;
--- /dev/null
+From 529586dc39b0ec47c6290c4e7bed6ea3ffd1d8fb Mon Sep 17 00:00:00 2001
+From: Bolko Maass <krautilein@gmx.de>
+Date: Fri, 27 Nov 2009 05:44:33 +0000
+Subject: powerpc/windfarm: Add detection for second cpu pump
+
+From: Bolko Maass <krautilein@gmx.de>
+
+commit 529586dc39b0ec47c6290c4e7bed6ea3ffd1d8fb upstream.
+
+Windfarm SMU control is explicitly missing support for a second CPU pump in G5 PowerMacs. Such machines actually exist (specifically Quads with a second pump), so this patch adds detection for it.
+
+Signed-off by: Bolko Maass <bmaass@math.uni-bremen.de>
+Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/macintosh/windfarm_smu_controls.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/macintosh/windfarm_smu_controls.c
++++ b/drivers/macintosh/windfarm_smu_controls.c
+@@ -202,6 +202,8 @@ static struct smu_fan_control *smu_fan_c
+ fct->ctrl.name = "cpu-front-fan-1";
+ else if (!strcmp(l, "CPU A PUMP"))
+ fct->ctrl.name = "cpu-pump-0";
++ else if (!strcmp(l, "CPU B PUMP"))
++ fct->ctrl.name = "cpu-pump-1";
+ else if (!strcmp(l, "Slots Fan") || !strcmp(l, "Slots fan") ||
+ !strcmp(l, "EXPANSION SLOTS INTAKE"))
+ fct->ctrl.name = "slots-fan";
--- /dev/null
+From 70d57139f932b9ca21026253d02af71cf53d764a Mon Sep 17 00:00:00 2001
+From: Larry Finger <Larry.Finger@lwfinger.net>
+Date: Sat, 5 Dec 2009 19:25:22 -0600
+Subject: rtl8187: Fix wrong rfkill switch mask for some models
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Larry Finger <Larry.Finger@lwfinger.net>
+
+commit 70d57139f932b9ca21026253d02af71cf53d764a upstream.
+
+There are different bits used to convey the setting of the rfkill
+switch to the driver. The current driver only supports one of these
+possibilities. These changes were derived from the latest version
+of the vendor driver.
+
+This patch fixes the regression noted in kernel Bugzilla #14743.
+
+Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
+Reported-and-tested-by: Antti Kaijanmäki <antti@kaijanmaki.net>
+Tested-by: Hin-Tak Leung <hintak.leung@gmail.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/net/wireless/rtl818x/rtl8187.h | 5 +++++
+ drivers/net/wireless/rtl818x/rtl8187_dev.c | 12 ++++++++++--
+ drivers/net/wireless/rtl818x/rtl8187_rfkill.c | 4 ++--
+ 3 files changed, 17 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/wireless/rtl818x/rtl8187_dev.c
++++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c
+@@ -1329,6 +1329,7 @@ static int __devinit rtl8187_probe(struc
+ struct ieee80211_channel *channel;
+ const char *chip_name;
+ u16 txpwr, reg;
++ u16 product_id = le16_to_cpu(udev->descriptor.idProduct);
+ int err, i;
+
+ dev = ieee80211_alloc_hw(sizeof(*priv), &rtl8187_ops);
+@@ -1488,6 +1489,13 @@ static int __devinit rtl8187_probe(struc
+ (*channel++).hw_value = txpwr & 0xFF;
+ (*channel++).hw_value = txpwr >> 8;
+ }
++ /* Handle the differing rfkill GPIO bit in different models */
++ priv->rfkill_mask = RFKILL_MASK_8187_89_97;
++ if (product_id == 0x8197 || product_id == 0x8198) {
++ eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_SELECT_GPIO, ®);
++ if (reg & 0xFF00)
++ priv->rfkill_mask = RFKILL_MASK_8198;
++ }
+
+ /*
+ * XXX: Once this driver supports anything that requires
+@@ -1516,9 +1524,9 @@ static int __devinit rtl8187_probe(struc
+ mutex_init(&priv->conf_mutex);
+ skb_queue_head_init(&priv->b_tx_status.queue);
+
+- printk(KERN_INFO "%s: hwaddr %pM, %s V%d + %s\n",
++ printk(KERN_INFO "%s: hwaddr %pM, %s V%d + %s, rfkill mask %d\n",
+ wiphy_name(dev->wiphy), dev->wiphy->perm_addr,
+- chip_name, priv->asic_rev, priv->rf->name);
++ chip_name, priv->asic_rev, priv->rf->name, priv->rfkill_mask);
+
+ #ifdef CONFIG_RTL8187_LEDS
+ eeprom_93cx6_read(&eeprom, 0x3F, ®);
+--- a/drivers/net/wireless/rtl818x/rtl8187.h
++++ b/drivers/net/wireless/rtl818x/rtl8187.h
+@@ -23,6 +23,7 @@
+ #define RTL8187_EEPROM_TXPWR_CHAN_1 0x16 /* 3 channels */
+ #define RTL8187_EEPROM_TXPWR_CHAN_6 0x1B /* 2 channels */
+ #define RTL8187_EEPROM_TXPWR_CHAN_4 0x3D /* 2 channels */
++#define RTL8187_EEPROM_SELECT_GPIO 0x3B
+
+ #define RTL8187_REQT_READ 0xC0
+ #define RTL8187_REQT_WRITE 0x40
+@@ -31,6 +32,9 @@
+
+ #define RTL8187_MAX_RX 0x9C4
+
++#define RFKILL_MASK_8187_89_97 0x2
++#define RFKILL_MASK_8198 0x4
++
+ struct rtl8187_rx_info {
+ struct urb *urb;
+ struct ieee80211_hw *dev;
+@@ -123,6 +127,7 @@ struct rtl8187_priv {
+ u8 noise;
+ u8 slot_time;
+ u8 aifsn[4];
++ u8 rfkill_mask;
+ struct {
+ __le64 buf;
+ struct sk_buff_head queue;
+--- a/drivers/net/wireless/rtl818x/rtl8187_rfkill.c
++++ b/drivers/net/wireless/rtl818x/rtl8187_rfkill.c
+@@ -25,10 +25,10 @@ static bool rtl8187_is_radio_enabled(str
+ u8 gpio;
+
+ gpio = rtl818x_ioread8(priv, &priv->map->GPIO0);
+- rtl818x_iowrite8(priv, &priv->map->GPIO0, gpio & ~0x02);
++ rtl818x_iowrite8(priv, &priv->map->GPIO0, gpio & ~priv->rfkill_mask);
+ gpio = rtl818x_ioread8(priv, &priv->map->GPIO1);
+
+- return gpio & 0x02;
++ return gpio & priv->rfkill_mask;
+ }
+
+ void rtl8187_rfkill_init(struct ieee80211_hw *hw)
--- /dev/null
+From 68cb4f8e246bbbc649980be0628cae9265870a91 Mon Sep 17 00:00:00 2001
+From: Ian Jackson <ian.jackson@eu.citrix.com>
+Date: Wed, 18 Nov 2009 11:08:11 +0100
+Subject: Serial: Do not read IIR in serial8250_start_tx when UART_BUG_TXEN
+
+From: Ian Jackson <ian.jackson@eu.citrix.com>
+
+commit 68cb4f8e246bbbc649980be0628cae9265870a91 upstream.
+
+Do not read IIR in serial8250_start_tx when UART_BUG_TXEN
+
+Reading the IIR clears some oustanding interrupts so it is not safe.
+Instead, simply transmit immediately if the buffer is empty without
+regard to IIR.
+
+Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
+Reviewed-by: Markus Armbruster <armbru@redhat.com>
+Reviewed-by: Jiri Kosina <jkosina@suse.cz>
+Cc: Alan Cox <alan@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/serial/8250.c | 8 +++-----
+ 1 file changed, 3 insertions(+), 5 deletions(-)
+
+--- a/drivers/serial/8250.c
++++ b/drivers/serial/8250.c
+@@ -1339,14 +1339,12 @@ static void serial8250_start_tx(struct u
+ serial_out(up, UART_IER, up->ier);
+
+ if (up->bugs & UART_BUG_TXEN) {
+- unsigned char lsr, iir;
++ unsigned char lsr;
+ lsr = serial_in(up, UART_LSR);
+ up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
+- iir = serial_in(up, UART_IIR) & 0x0f;
+ if ((up->port.type == PORT_RM9000) ?
+- (lsr & UART_LSR_THRE &&
+- (iir == UART_IIR_NO_INT || iir == UART_IIR_THRI)) :
+- (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT))
++ (lsr & UART_LSR_THRE) :
++ (lsr & UART_LSR_TEMT))
+ transmit_chars(up);
+ }
+ }
futex-take-mmap_sem-for-get_user_pages-in-fault_in_user_writeable.patch
devpts_get_tty-should-validate-inode.patch
debugfs-fix-create-mutex-racy-fops-and-private-data.patch
+driver-core-fix-race-in-dev_driver_string.patch
+serial-do-not-read-iir-in-serial8250_start_tx-when-uart_bug_txen.patch
+mac80211-fix-bug-in-computing-crc-over-dynamic-ies-in-beacon.patch
+mac80211-fixed-bug-in-mesh-portal-paths.patch
+mac80211-revert-use-correct-sign-for-mesh-active-path-refresh.patch
+mac80211-fix-scan-abort-sanity-checks.patch
+wireless-correctly-report-signal-value-for-ieee80211_hw_signal_unspec.patch
+rtl8187-fix-wrong-rfkill-switch-mask-for-some-models.patch
+x86-fix-bogus-warning-in-apic_noop.apic_write.patch
+mm-hugetlb-fix-hugepage-memory-leak-in-mincore.patch
+mm-hugetlb-fix-hugepage-memory-leak-in-walk_page_range.patch
+powerpc-windfarm-add-detection-for-second-cpu-pump.patch
+powerpc-therm_adt746x-record-pwm-invert-bit-at-module-load-time.patch
+powerpc-fix-usage-of-64-bit-instruction-in-32-bit-altivec-code.patch
+drm-radeon-kms-add-quirk-for-his-x1300-board.patch
+drm-radeon-kms-handle-vblanks-properly-with-dpms-on.patch
+drm-radeon-kms-fix-legacy-crtc2-dpms.patch
+drm-radeon-kms-fix-vram-setup-on-rs600.patch
+drm-radeon-kms-rs6xx-rs740-clamp-vram-to-aperture-size.patch
+drm-ttm-fix-build-failure-due-to-missing-struct-page.patch
+drm-i915-set-the-error-code-after-failing-to-insert-new-offset-into-mm-ht.patch
+drm-i915-add-the-missing-clonemask-for-display-port-on-ironlake.patch
+xen-xenbus-make-device_attr-s-static.patch
+xen-re-register-runstate-area-earlier-on-resume.patch
+xen-restore-runstate_info-even-if-have_vcpu_info_placement.patch
+xen-correctly-restore-pfn_to_mfn_list_list-after-resume.patch
+xen-register-timer-interrupt-with-irqf_timer.patch
+xen-register-runstate-on-secondary-cpus.patch
+xen-don-t-call-dpm_resume_noirq-with-interrupts-disabled.patch
+xen-register-runstate-info-for-boot-cpu-early.patch
+xen-call-clock-resume-notifier-on-all-cpus.patch
+xen-improve-error-handling-in-do_suspend.patch
+xen-don-t-leak-irqs-over-suspend-resume.patch
+xen-use-iret-for-return-from-64b-kernel-to-32b-usermode.patch
+xen-explicitly-create-destroy-stop_machine-workqueues-outside-suspend-resume-region.patch
+xen-balloon-fix-totalram_pages-counting.patch
+xen-try-harder-to-balloon-up-under-memory-pressure.patch
+dm-exception-store-free-tmp_store-on-persistent-flag-error.patch
+dm-snapshot-only-take-lock-for-statustype-info-not-table.patch
+dm-crypt-move-private-iv-fields-to-structs.patch
+dm-crypt-restructure-essiv-error-path.patch
+dm-avoid-_hash_lock-deadlock.patch
+dm-snapshot-cope-with-chunk-size-larger-than-origin.patch
+dm-crypt-separate-essiv-allocation-from-initialisation.patch
+dm-crypt-make-wipe-message-also-wipe-essiv-key.patch
--- /dev/null
+From 19deffbeba930030cfaf000b920333c6ba99ad52 Mon Sep 17 00:00:00 2001
+From: John W. Linville <linville@tuxdriver.com>
+Date: Tue, 8 Dec 2009 17:10:13 -0500
+Subject: wireless: correctly report signal value for IEEE80211_HW_SIGNAL_UNSPEC
+
+From: John W. Linville <linville@tuxdriver.com>
+
+commit 19deffbeba930030cfaf000b920333c6ba99ad52 upstream.
+
+This part was missed in "cfg80211: implement get_wireless_stats",
+probably because sta_set_sinfo already existed and was only handling
+dBm signals.
+
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ net/mac80211/cfg.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/net/mac80211/cfg.c
++++ b/net/mac80211/cfg.c
+@@ -338,7 +338,8 @@ static void sta_set_sinfo(struct sta_inf
+ sinfo->rx_packets = sta->rx_packets;
+ sinfo->tx_packets = sta->tx_packets;
+
+- if (sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) {
++ if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) ||
++ (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) {
+ sinfo->filled |= STATION_INFO_SIGNAL;
+ sinfo->signal = (s8)sta->last_signal;
+ }
--- /dev/null
+From a946d8f11f0da9cfc714248036fcfd3a794d1e27 Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Mon, 7 Dec 2009 12:59:46 +0100
+Subject: x86: Fix bogus warning in apic_noop.apic_write()
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+commit a946d8f11f0da9cfc714248036fcfd3a794d1e27 upstream.
+
+apic_noop is used to provide dummy apic functions. It's installed
+when the CPU has no APIC or when the APIC is disabled on the kernel
+command line.
+
+The apic_noop implementation of apic_write() warns when the CPU has
+an APIC or when the APIC is not disabled.
+
+That's bogus. The warning should only happen when the CPU has an
+APIC _AND_ the APIC is not disabled. apic_noop.apic_read() has the
+correct check.
+
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Cc: Cyrill Gorcunov <gorcunov@openvz.org>
+LKML-Reference: <alpine.LFD.2.00.0912071255420.3089@localhost.localdomain>
+Signed-off-by: Ingo Molnar <mingo@elte.hu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/x86/kernel/apic/apic.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/x86/kernel/apic/apic.c
++++ b/arch/x86/kernel/apic/apic.c
+@@ -246,7 +246,7 @@ static int modern_apic(void)
+ */
+ static void native_apic_write_dummy(u32 reg, u32 v)
+ {
+- WARN_ON_ONCE((cpu_has_apic || !disable_apic));
++ WARN_ON_ONCE(cpu_has_apic && !disable_apic);
+ }
+
+ static u32 native_apic_read_dummy(u32 reg)
--- /dev/null
+From 3d65c9488cadd2f11bd4d60c7266e639ece5d0d6 Mon Sep 17 00:00:00 2001
+From: Gianluca Guida <gianluca.guida@citrix.com>
+Date: Thu, 30 Jul 2009 22:54:36 +0100
+Subject: Xen balloon: fix totalram_pages counting.
+
+From: Gianluca Guida <gianluca.guida@citrix.com>
+
+commit 3d65c9488cadd2f11bd4d60c7266e639ece5d0d6 upstream.
+
+Change totalram_pages when a single page is added/removed to the
+ballooned list. This avoid totalram_pages to be set erroneously to
+max_pfn at boot.
+
+Signed-off-by: Gianluca Guida <gianluca.guida@citrix.com>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/xen/balloon.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+--- a/drivers/xen/balloon.c
++++ b/drivers/xen/balloon.c
+@@ -136,6 +136,8 @@ static void balloon_append(struct page *
+ list_add(&page->lru, &ballooned_pages);
+ balloon_stats.balloon_low++;
+ }
++
++ totalram_pages--;
+ }
+
+ /* balloon_retrieve: rescue a page from the balloon, if it is not empty. */
+@@ -156,6 +158,8 @@ static struct page *balloon_retrieve(voi
+ else
+ balloon_stats.balloon_low--;
+
++ totalram_pages++;
++
+ return page;
+ }
+
+@@ -260,7 +264,6 @@ static int increase_reservation(unsigned
+ }
+
+ balloon_stats.current_pages += nr_pages;
+- totalram_pages = balloon_stats.current_pages;
+
+ out:
+ spin_unlock_irqrestore(&balloon_lock, flags);
+@@ -323,7 +326,6 @@ static int decrease_reservation(unsigned
+ BUG_ON(ret != nr_pages);
+
+ balloon_stats.current_pages -= nr_pages;
+- totalram_pages = balloon_stats.current_pages;
+
+ spin_unlock_irqrestore(&balloon_lock, flags);
+
+@@ -422,7 +424,6 @@ static int __init balloon_init(void)
+ pr_info("xen_balloon: Initialising balloon driver.\n");
+
+ balloon_stats.current_pages = min(xen_start_info->nr_pages, max_pfn);
+- totalram_pages = balloon_stats.current_pages;
+ balloon_stats.target_pages = balloon_stats.current_pages;
+ balloon_stats.balloon_low = 0;
+ balloon_stats.balloon_high = 0;
--- /dev/null
+From f6eafe3665bcc374c66775d58312d1c06c55303f Mon Sep 17 00:00:00 2001
+From: Ian Campbell <Ian.Campbell@citrix.com>
+Date: Wed, 25 Nov 2009 14:12:08 +0000
+Subject: xen: call clock resume notifier on all CPUs
+
+From: Ian Campbell <Ian.Campbell@citrix.com>
+
+commit f6eafe3665bcc374c66775d58312d1c06c55303f upstream.
+
+tick_resume() is never called on secondary processors. Presumably this
+is because they are offlined for suspend on native and so this is
+normally taken care of in the CPU onlining path. Under Xen we keep all
+CPUs online over a suspend.
+
+This patch papers over the issue for me but I will investigate a more
+generic, less hacky, way of doing to the same.
+
+tick_suspend is also only called on the boot CPU which I presume should
+be fixed too.
+
+Signed-off-by: Ian Campbell <Ian.Campbell@citrix.com>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/x86/xen/suspend.c | 15 ++++++++++++++-
+ 1 file changed, 14 insertions(+), 1 deletion(-)
+
+--- a/arch/x86/xen/suspend.c
++++ b/arch/x86/xen/suspend.c
+@@ -1,4 +1,5 @@
+ #include <linux/types.h>
++#include <linux/clockchips.h>
+
+ #include <xen/interface/xen.h>
+ #include <xen/grant_table.h>
+@@ -46,7 +47,19 @@ void xen_post_suspend(int suspend_cancel
+
+ }
+
++static void xen_vcpu_notify_restore(void *data)
++{
++ unsigned long reason = (unsigned long)data;
++
++ /* Boot processor notified via generic timekeeping_resume() */
++ if ( smp_processor_id() == 0)
++ return;
++
++ clockevents_notify(reason, NULL);
++}
++
+ void xen_arch_resume(void)
+ {
+- /* nothing */
++ smp_call_function(xen_vcpu_notify_restore,
++ (void *)CLOCK_EVT_NOTIFY_RESUME, 1);
+ }
--- /dev/null
+From fa24ba62ea2869308ffc9f0b286ac9650b4ca6cb Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell@citrix.com>
+Date: Sat, 21 Nov 2009 11:32:49 +0000
+Subject: xen: correctly restore pfn_to_mfn_list_list after resume
+
+From: Ian Campbell <ian.campbell@citrix.com>
+
+commit fa24ba62ea2869308ffc9f0b286ac9650b4ca6cb upstream.
+
+pvops kernels >= 2.6.30 can currently only be saved and restored once. The
+second attempt to save results in:
+
+ ERROR Internal error: Frame# in pfn-to-mfn frame list is not in pseudophys
+ ERROR Internal error: entry 0: p2m_frame_list[0] is 0xf2c2c2c2, max 0x120000
+ ERROR Internal error: Failed to map/save the p2m frame list
+
+I finally narrowed it down to:
+
+ commit cdaead6b4e657f960d6d6f9f380e7dfeedc6a09b
+ Author: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
+ Date: Fri Feb 27 15:34:59 2009 -0800
+
+ xen: split construction of p2m mfn tables from registration
+
+ Build the p2m_mfn_list_list early with the rest of the p2m table, but
+ register it later when the real shared_info structure is in place.
+
+ Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
+
+The unforeseen side-effect of this change was to cause the mfn list list to not
+be rebuilt on resume. Prior to this change it would have been rebuilt via
+xen_post_suspend() -> xen_setup_shared_info() -> xen_setup_mfn_list_list().
+
+Fix by explicitly calling xen_build_mfn_list_list() from xen_post_suspend().
+
+Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/x86/xen/mmu.c | 2 +-
+ arch/x86/xen/suspend.c | 2 ++
+ arch/x86/xen/xen-ops.h | 1 +
+ 3 files changed, 4 insertions(+), 1 deletion(-)
+
+--- a/arch/x86/xen/mmu.c
++++ b/arch/x86/xen/mmu.c
+@@ -185,7 +185,7 @@ static inline unsigned p2m_index(unsigne
+ }
+
+ /* Build the parallel p2m_top_mfn structures */
+-static void __init xen_build_mfn_list_list(void)
++void xen_build_mfn_list_list(void)
+ {
+ unsigned pfn, idx;
+
+--- a/arch/x86/xen/suspend.c
++++ b/arch/x86/xen/suspend.c
+@@ -27,6 +27,8 @@ void xen_pre_suspend(void)
+
+ void xen_post_suspend(int suspend_cancelled)
+ {
++ xen_build_mfn_list_list();
++
+ xen_setup_shared_info();
+
+ if (suspend_cancelled) {
+--- a/arch/x86/xen/xen-ops.h
++++ b/arch/x86/xen/xen-ops.h
+@@ -25,6 +25,7 @@ extern struct shared_info *HYPERVISOR_sh
+
+ void xen_setup_mfn_list_list(void);
+ void xen_setup_shared_info(void);
++void xen_build_mfn_list_list(void);
+ void xen_setup_machphys_mapping(void);
+ pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd, unsigned long max_pfn);
+ void xen_ident_map_ISA(void);
--- /dev/null
+From 922cc38ab71d1360978e65207e4a4f4988987127 Mon Sep 17 00:00:00 2001
+From: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
+Date: Tue, 24 Nov 2009 09:58:49 -0800
+Subject: xen: don't call dpm_resume_noirq() with interrupts disabled.
+
+From: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
+
+commit 922cc38ab71d1360978e65207e4a4f4988987127 upstream.
+
+dpm_resume_noirq() takes a mutex, so it can't be called from a no-interrupt
+context. Don't call it from within the stop-machine function, but just
+afterwards, since we're resuming anyway, regardless of what happened.
+
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/xen/manage.c | 7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+--- a/drivers/xen/manage.c
++++ b/drivers/xen/manage.c
+@@ -43,7 +43,6 @@ static int xen_suspend(void *data)
+ if (err) {
+ printk(KERN_ERR "xen_suspend: sysdev_suspend failed: %d\n",
+ err);
+- dpm_resume_noirq(PMSG_RESUME);
+ return err;
+ }
+
+@@ -69,7 +68,6 @@ static int xen_suspend(void *data)
+ }
+
+ sysdev_resume();
+- dpm_resume_noirq(PMSG_RESUME);
+
+ return 0;
+ }
+@@ -108,6 +106,9 @@ static void do_suspend(void)
+ }
+
+ err = stop_machine(xen_suspend, &cancelled, cpumask_of(0));
++
++ dpm_resume_noirq(PMSG_RESUME);
++
+ if (err) {
+ printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
+ goto out;
+@@ -119,8 +120,6 @@ static void do_suspend(void)
+ } else
+ xs_suspend_cancel();
+
+- dpm_resume_noirq(PMSG_RESUME);
+-
+ resume_devices:
+ dpm_resume_end(PMSG_RESUME);
+
--- /dev/null
+From fed5ea87e02aaf902ff38c65b4514233db03dc09 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell@citrix.com>
+Date: Tue, 1 Dec 2009 16:15:30 +0000
+Subject: xen: don't leak IRQs over suspend/resume.
+
+From: Ian Campbell <ian.campbell@citrix.com>
+
+commit fed5ea87e02aaf902ff38c65b4514233db03dc09 upstream.
+
+On resume irq_info[*].evtchn is reset to 0 since event channel mappings
+are not preserved over suspend/resume. The other contents of irq_info
+is preserved to allow rebind_evtchn_irq() to function.
+
+However when a device resumes it will try to unbind from the
+previous IRQ (e.g. blkfront goes blkfront_resume() -> blkif_free() ->
+unbind_from_irqhandler() -> unbind_from_irq()). This will fail due to the
+check for VALID_EVTCHN in unbind_from_irq() and the IRQ is leaked. The
+device will then continue to resume and allocate a new IRQ, eventually
+leading to find_unbound_irq() panic()ing.
+
+Fix this by changing unbind_from_irq() to handle teardown of interrupts
+which have type!=IRQT_UNBOUND but are not currently bound to a specific
+event channel.
+
+Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/xen/events.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/xen/events.c
++++ b/drivers/xen/events.c
+@@ -474,6 +474,9 @@ static void unbind_from_irq(unsigned int
+ bind_evtchn_to_cpu(evtchn, 0);
+
+ evtchn_to_irq[evtchn] = -1;
++ }
++
++ if (irq_info[irq].type != IRQT_UNBOUND) {
+ irq_info[irq] = mk_unbound_info();
+
+ dynamic_irq_cleanup(irq);
--- /dev/null
+From b4606f2165153833247823e8c04c5e88cb3d298b Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell@citrix.com>
+Date: Tue, 1 Dec 2009 11:47:15 +0000
+Subject: xen: explicitly create/destroy stop_machine workqueues outside suspend/resume region.
+
+From: Ian Campbell <ian.campbell@citrix.com>
+
+commit b4606f2165153833247823e8c04c5e88cb3d298b upstream.
+
+I have observed cases where the implicit stop_machine_destroy() done by
+stop_machine() hangs while destroying the workqueues, specifically in
+kthread_stop(). This seems to be because timer ticks are not restarted
+until after stop_machine() returns.
+
+Fortunately stop_machine provides a facility to pre-create/post-destroy
+the workqueues so use this to ensure that workqueues are only destroyed
+after everything is really up and running again.
+
+I only actually observed this failure with 2.6.30. It seems that newer
+kernels are somehow more robust against doing kthread_stop() without timer
+interrupts (I tried some backports of some likely looking candidates but
+did not track down the commit which added this robustness). However this
+change seems like a reasonable belt&braces thing to do.
+
+Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/xen/manage.c | 12 +++++++++++-
+ 1 file changed, 11 insertions(+), 1 deletion(-)
+
+--- a/drivers/xen/manage.c
++++ b/drivers/xen/manage.c
+@@ -79,6 +79,12 @@ static void do_suspend(void)
+
+ shutting_down = SHUTDOWN_SUSPEND;
+
++ err = stop_machine_create();
++ if (err) {
++ printk(KERN_ERR "xen suspend: failed to setup stop_machine %d\n", err);
++ goto out;
++ }
++
+ #ifdef CONFIG_PREEMPT
+ /* If the kernel is preemptible, we need to freeze all the processes
+ to prevent them from being in the middle of a pagetable update
+@@ -86,7 +92,7 @@ static void do_suspend(void)
+ err = freeze_processes();
+ if (err) {
+ printk(KERN_ERR "xen suspend: freeze failed %d\n", err);
+- goto out;
++ goto out_destroy_sm;
+ }
+ #endif
+
+@@ -129,7 +135,11 @@ out_resume:
+ out_thaw:
+ #ifdef CONFIG_PREEMPT
+ thaw_processes();
++
++out_destroy_sm:
+ #endif
++ stop_machine_destroy();
++
+ out:
+ shutting_down = SHUTDOWN_INVALID;
+ }
--- /dev/null
+From 65f63384b391bf4d384327d8a7c6de9860290b5c Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell@citrix.com>
+Date: Tue, 1 Dec 2009 11:47:14 +0000
+Subject: xen: improve error handling in do_suspend.
+
+From: Ian Campbell <ian.campbell@citrix.com>
+
+commit 65f63384b391bf4d384327d8a7c6de9860290b5c upstream.
+
+The existing error handling has a few issues:
+- If freeze_processes() fails it exits with shutting_down = SHUTDOWN_SUSPEND.
+- If dpm_suspend_noirq() fails it exits without resuming xenbus.
+- If stop_machine() fails it exits without resuming xenbus or calling
+ dpm_resume_end().
+- xs_suspend()/xs_resume() and dpm_suspend_noirq()/dpm_resume_noirq() were not
+ nested in the obvious way.
+
+Fix by ensuring each failure case goto's the correct label. Treat a failure of
+stop_machine() as a cancelled suspend in order to follow the correct resume
+path.
+
+Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/xen/manage.c | 20 +++++++++++---------
+ 1 file changed, 11 insertions(+), 9 deletions(-)
+
+--- a/drivers/xen/manage.c
++++ b/drivers/xen/manage.c
+@@ -86,32 +86,32 @@ static void do_suspend(void)
+ err = freeze_processes();
+ if (err) {
+ printk(KERN_ERR "xen suspend: freeze failed %d\n", err);
+- return;
++ goto out;
+ }
+ #endif
+
+ err = dpm_suspend_start(PMSG_SUSPEND);
+ if (err) {
+ printk(KERN_ERR "xen suspend: dpm_suspend_start %d\n", err);
+- goto out;
++ goto out_thaw;
+ }
+
+- printk(KERN_DEBUG "suspending xenstore...\n");
+- xs_suspend();
+-
+ err = dpm_suspend_noirq(PMSG_SUSPEND);
+ if (err) {
+ printk(KERN_ERR "dpm_suspend_noirq failed: %d\n", err);
+- goto resume_devices;
++ goto out_resume;
+ }
+
++ printk(KERN_DEBUG "suspending xenstore...\n");
++ xs_suspend();
++
+ err = stop_machine(xen_suspend, &cancelled, cpumask_of(0));
+
+ dpm_resume_noirq(PMSG_RESUME);
+
+ if (err) {
+ printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
+- goto out;
++ cancelled = 1;
+ }
+
+ if (!cancelled) {
+@@ -120,15 +120,17 @@ static void do_suspend(void)
+ } else
+ xs_suspend_cancel();
+
+-resume_devices:
++out_resume:
+ dpm_resume_end(PMSG_RESUME);
+
+ /* Make sure timer events get retriggered on all CPUs */
+ clock_was_set();
+-out:
++
++out_thaw:
+ #ifdef CONFIG_PREEMPT
+ thaw_processes();
+ #endif
++out:
+ shutting_down = SHUTDOWN_INVALID;
+ }
+ #endif /* CONFIG_PM_SLEEP */
--- /dev/null
+From be012920ecba161ad20303a3f6d9e96c58cf97c7 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <Ian.Campbell@citrix.com>
+Date: Sat, 21 Nov 2009 08:35:55 +0800
+Subject: xen: re-register runstate area earlier on resume.
+
+From: Ian Campbell <Ian.Campbell@citrix.com>
+
+commit be012920ecba161ad20303a3f6d9e96c58cf97c7 upstream.
+
+This is necessary to ensure the runstate area is available to
+xen_sched_clock before any calls to printk which will require it in
+order to provide a timestamp.
+
+I chose to pull the xen_setup_runstate_info out of xen_time_init into
+the caller in order to maintain parity with calling
+xen_setup_runstate_info separately from calling xen_time_resume.
+
+Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/x86/xen/enlighten.c | 2 ++
+ arch/x86/xen/time.c | 5 ++---
+ arch/x86/xen/xen-ops.h | 1 +
+ 3 files changed, 5 insertions(+), 3 deletions(-)
+
+--- a/arch/x86/xen/enlighten.c
++++ b/arch/x86/xen/enlighten.c
+@@ -148,6 +148,8 @@ void xen_vcpu_restore(void)
+ HYPERVISOR_vcpu_op(VCPUOP_down, cpu, NULL))
+ BUG();
+
++ xen_setup_runstate_info(cpu);
++
+ xen_vcpu_setup(cpu);
+
+ if (other_cpu &&
+--- a/arch/x86/xen/time.c
++++ b/arch/x86/xen/time.c
+@@ -100,7 +100,7 @@ bool xen_vcpu_stolen(int vcpu)
+ return per_cpu(runstate, vcpu).state == RUNSTATE_runnable;
+ }
+
+-static void setup_runstate_info(int cpu)
++void xen_setup_runstate_info(int cpu)
+ {
+ struct vcpu_register_runstate_memory_area area;
+
+@@ -442,8 +442,6 @@ void xen_setup_timer(int cpu)
+
+ evt->cpumask = cpumask_of(cpu);
+ evt->irq = irq;
+-
+- setup_runstate_info(cpu);
+ }
+
+ void xen_teardown_timer(int cpu)
+@@ -494,6 +492,7 @@ __init void xen_time_init(void)
+
+ setup_force_cpu_cap(X86_FEATURE_TSC);
+
++ xen_setup_runstate_info(cpu);
+ xen_setup_timer(cpu);
+ xen_setup_cpu_clockevents();
+ }
+--- a/arch/x86/xen/xen-ops.h
++++ b/arch/x86/xen/xen-ops.h
+@@ -41,6 +41,7 @@ void __init xen_build_dynamic_phys_to_ma
+
+ void xen_init_irq_ops(void);
+ void xen_setup_timer(int cpu);
++void xen_setup_runstate_info(int cpu);
+ void xen_teardown_timer(int cpu);
+ cycle_t xen_clocksource_read(void);
+ void xen_setup_cpu_clockevents(void);
--- /dev/null
+From 499d19b82b586aef18727b9ae1437f8f37b66e91 Mon Sep 17 00:00:00 2001
+From: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
+Date: Tue, 24 Nov 2009 09:38:25 -0800
+Subject: xen: register runstate info for boot CPU early
+
+From: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
+
+commit 499d19b82b586aef18727b9ae1437f8f37b66e91 upstream.
+
+printk timestamping uses sched_clock, which in turn relies on runstate
+info under Xen. So make sure we set it up before any printks can
+be called.
+
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/x86/xen/enlighten.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/arch/x86/xen/enlighten.c
++++ b/arch/x86/xen/enlighten.c
+@@ -1181,6 +1181,8 @@ asmlinkage void __init xen_start_kernel(
+
+ xen_raw_console_write("about to get started...\n");
+
++ xen_setup_runstate_info(0);
++
+ /* Start the world */
+ #ifdef CONFIG_X86_32
+ i386_start_kernel();
--- /dev/null
+From 028896721ac04f6fa0697f3ecac3f98761746363 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell@citrix.com>
+Date: Tue, 24 Nov 2009 09:32:48 -0800
+Subject: xen: register runstate on secondary CPUs
+
+From: Ian Campbell <ian.campbell@citrix.com>
+
+commit 028896721ac04f6fa0697f3ecac3f98761746363 upstream.
+
+The commit "xen: re-register runstate area earlier on resume" caused us
+to never try and setup the runstate area for secondary CPUs. Ensure that
+we do this...
+
+Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/x86/xen/smp.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/x86/xen/smp.c
++++ b/arch/x86/xen/smp.c
+@@ -295,6 +295,7 @@ static int __cpuinit xen_cpu_up(unsigned
+ (unsigned long)task_stack_page(idle) -
+ KERNEL_STACK_OFFSET + THREAD_SIZE;
+ #endif
++ xen_setup_runstate_info(cpu);
+ xen_setup_timer(cpu);
+ xen_init_lock_cpu(cpu);
+
--- /dev/null
+From f350c7922faad3397c98c81a9e5658f5a1ef0214 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell@citrix.com>
+Date: Tue, 24 Nov 2009 10:16:23 +0000
+Subject: xen: register timer interrupt with IRQF_TIMER
+
+From: Ian Campbell <ian.campbell@citrix.com>
+
+commit f350c7922faad3397c98c81a9e5658f5a1ef0214 upstream.
+
+Otherwise the timer is disabled by dpm_suspend_noirq() which in turn prevents
+correct operation of stop_machine on multi-processor systems and breaks
+suspend.
+
+Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/x86/xen/time.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/x86/xen/time.c
++++ b/arch/x86/xen/time.c
+@@ -434,7 +434,7 @@ void xen_setup_timer(int cpu)
+ name = "<timer kasprintf failed>";
+
+ irq = bind_virq_to_irqhandler(VIRQ_TIMER, cpu, xen_timer_interrupt,
+- IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING,
++ IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING|IRQF_TIMER,
+ name, NULL);
+
+ evt = &per_cpu(xen_clock_events, cpu);
--- /dev/null
+From 3905bb2aa7bb801b31946b37a4635ebac4009051 Mon Sep 17 00:00:00 2001
+From: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
+Date: Sat, 21 Nov 2009 08:46:29 +0800
+Subject: xen: restore runstate_info even if !have_vcpu_info_placement
+
+From: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
+
+commit 3905bb2aa7bb801b31946b37a4635ebac4009051 upstream.
+
+Even if have_vcpu_info_placement is not set, we still need to set up
+the runstate area on each resumed vcpu.
+
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/x86/xen/enlighten.c | 25 +++++++++++--------------
+ 1 file changed, 11 insertions(+), 14 deletions(-)
+
+--- a/arch/x86/xen/enlighten.c
++++ b/arch/x86/xen/enlighten.c
+@@ -138,26 +138,23 @@ static void xen_vcpu_setup(int cpu)
+ */
+ void xen_vcpu_restore(void)
+ {
+- if (have_vcpu_info_placement) {
+- int cpu;
++ int cpu;
+
+- for_each_online_cpu(cpu) {
+- bool other_cpu = (cpu != smp_processor_id());
++ for_each_online_cpu(cpu) {
++ bool other_cpu = (cpu != smp_processor_id());
+
+- if (other_cpu &&
+- HYPERVISOR_vcpu_op(VCPUOP_down, cpu, NULL))
+- BUG();
++ if (other_cpu &&
++ HYPERVISOR_vcpu_op(VCPUOP_down, cpu, NULL))
++ BUG();
+
+- xen_setup_runstate_info(cpu);
++ xen_setup_runstate_info(cpu);
+
++ if (have_vcpu_info_placement)
+ xen_vcpu_setup(cpu);
+
+- if (other_cpu &&
+- HYPERVISOR_vcpu_op(VCPUOP_up, cpu, NULL))
+- BUG();
+- }
+-
+- BUG_ON(!have_vcpu_info_placement);
++ if (other_cpu &&
++ HYPERVISOR_vcpu_op(VCPUOP_up, cpu, NULL))
++ BUG();
+ }
+ }
+
--- /dev/null
+From bc2c0303226ec716854d3c208c7f84fe7aa35cd7 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell@citrix.com>
+Date: Fri, 5 Jun 2009 11:58:37 +0100
+Subject: xen: try harder to balloon up under memory pressure.
+
+From: Ian Campbell <ian.campbell@citrix.com>
+
+commit bc2c0303226ec716854d3c208c7f84fe7aa35cd7 upstream.
+
+Currently if the balloon driver is unable to increase the guest's
+reservation it assumes the failure was due to reaching its full
+allocation, gives up on the ballooning operation and records the limit
+it reached as the "hard limit". The driver will not try again until
+the target is set again (even to the same value).
+
+However it is possible that ballooning has in fact failed due to
+memory pressure in the host and therefore it is desirable to keep
+attempting to reach the target in case memory becomes available. The
+most likely scenario is that some guests are ballooning down while
+others are ballooning up and therefore there is temporary memory
+pressure while things stabilise. You would not expect a well behaved
+toolstack to ask a domain to balloon to more than its allocation nor
+would you expect it to deliberately over-commit memory by setting
+balloon targets which exceed the total host memory.
+
+This patch drops the concept of a hard limit and causes the balloon
+driver to retry increasing the reservation on a timer in the same
+manner as when decreasing the reservation.
+
+Also if we partially succeed in increasing the reservation
+(i.e. receive less pages than we asked for) then we may as well keep
+those pages rather than returning them to Xen.
+
+Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/xen/balloon.c | 31 +++++--------------------------
+ 1 file changed, 5 insertions(+), 26 deletions(-)
+
+--- a/drivers/xen/balloon.c
++++ b/drivers/xen/balloon.c
+@@ -66,8 +66,6 @@ struct balloon_stats {
+ /* We aim for 'current allocation' == 'target allocation'. */
+ unsigned long current_pages;
+ unsigned long target_pages;
+- /* We may hit the hard limit in Xen. If we do then we remember it. */
+- unsigned long hard_limit;
+ /*
+ * Drivers may alter the memory reservation independently, but they
+ * must inform the balloon driver so we avoid hitting the hard limit.
+@@ -185,7 +183,7 @@ static void balloon_alarm(unsigned long
+
+ static unsigned long current_target(void)
+ {
+- unsigned long target = min(balloon_stats.target_pages, balloon_stats.hard_limit);
++ unsigned long target = balloon_stats.target_pages;
+
+ target = min(target,
+ balloon_stats.current_pages +
+@@ -221,23 +219,10 @@ static int increase_reservation(unsigned
+ set_xen_guest_handle(reservation.extent_start, frame_list);
+ reservation.nr_extents = nr_pages;
+ rc = HYPERVISOR_memory_op(XENMEM_populate_physmap, &reservation);
+- if (rc < nr_pages) {
+- if (rc > 0) {
+- int ret;
+-
+- /* We hit the Xen hard limit: reprobe. */
+- reservation.nr_extents = rc;
+- ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation,
+- &reservation);
+- BUG_ON(ret != rc);
+- }
+- if (rc >= 0)
+- balloon_stats.hard_limit = (balloon_stats.current_pages + rc -
+- balloon_stats.driver_pages);
++ if (rc < 0)
+ goto out;
+- }
+
+- for (i = 0; i < nr_pages; i++) {
++ for (i = 0; i < rc; i++) {
+ page = balloon_retrieve();
+ BUG_ON(page == NULL);
+
+@@ -263,12 +248,12 @@ static int increase_reservation(unsigned
+ __free_page(page);
+ }
+
+- balloon_stats.current_pages += nr_pages;
++ balloon_stats.current_pages += rc;
+
+ out:
+ spin_unlock_irqrestore(&balloon_lock, flags);
+
+- return 0;
++ return rc < 0 ? rc : rc != nr_pages;
+ }
+
+ static int decrease_reservation(unsigned long nr_pages)
+@@ -369,7 +354,6 @@ static void balloon_process(struct work_
+ static void balloon_set_new_target(unsigned long target)
+ {
+ /* No need for lock. Not read-modify-write updates. */
+- balloon_stats.hard_limit = ~0UL;
+ balloon_stats.target_pages = target;
+ schedule_work(&balloon_worker);
+ }
+@@ -428,7 +412,6 @@ static int __init balloon_init(void)
+ balloon_stats.balloon_low = 0;
+ balloon_stats.balloon_high = 0;
+ balloon_stats.driver_pages = 0UL;
+- balloon_stats.hard_limit = ~0UL;
+
+ init_timer(&balloon_timer);
+ balloon_timer.data = 0;
+@@ -473,9 +456,6 @@ module_exit(balloon_exit);
+ BALLOON_SHOW(current_kb, "%lu\n", PAGES2KB(balloon_stats.current_pages));
+ BALLOON_SHOW(low_kb, "%lu\n", PAGES2KB(balloon_stats.balloon_low));
+ BALLOON_SHOW(high_kb, "%lu\n", PAGES2KB(balloon_stats.balloon_high));
+-BALLOON_SHOW(hard_limit_kb,
+- (balloon_stats.hard_limit!=~0UL) ? "%lu\n" : "???\n",
+- (balloon_stats.hard_limit!=~0UL) ? PAGES2KB(balloon_stats.hard_limit) : 0);
+ BALLOON_SHOW(driver_kb, "%lu\n", PAGES2KB(balloon_stats.driver_pages));
+
+ static ssize_t show_target_kb(struct sys_device *dev, struct sysdev_attribute *attr,
+@@ -545,7 +525,6 @@ static struct attribute *balloon_info_at
+ &attr_current_kb.attr,
+ &attr_low_kb.attr,
+ &attr_high_kb.attr,
+- &attr_hard_limit_kb.attr,
+ &attr_driver_kb.attr,
+ NULL
+ };
--- /dev/null
+From 6aaf5d633bb6cead81b396d861d7bae4b9a0ba7e Mon Sep 17 00:00:00 2001
+From: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
+Date: Wed, 25 Nov 2009 13:15:38 -0800
+Subject: xen: use iret for return from 64b kernel to 32b usermode
+
+From: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
+
+commit 6aaf5d633bb6cead81b396d861d7bae4b9a0ba7e upstream.
+
+If Xen wants to return to a 32b usermode with sysret it must use the
+right form. When using VCGF_in_syscall to trigger this, it looks at
+the code segment and does a 32b sysret if it is FLAT_USER_CS32.
+However, this is different from __USER32_CS, so it fails to return
+properly if we use the normal Linux segment.
+
+So avoid the whole mess by dropping VCGF_in_syscall and simply use
+plain iret to return to usermode.
+
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
+Acked-by: Jan Beulich <jbeulich@novell.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/x86/xen/xen-asm_64.S | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/arch/x86/xen/xen-asm_64.S
++++ b/arch/x86/xen/xen-asm_64.S
+@@ -96,7 +96,7 @@ ENTRY(xen_sysret32)
+ pushq $__USER32_CS
+ pushq %rcx
+
+- pushq $VGCF_in_syscall
++ pushq $0
+ 1: jmp hypercall_iret
+ ENDPATCH(xen_sysret32)
+ RELOC(xen_sysret32, 1b+1)
+@@ -151,7 +151,7 @@ ENTRY(xen_syscall32_target)
+ ENTRY(xen_sysenter_target)
+ lea 16(%rsp), %rsp /* strip %rcx, %r11 */
+ mov $-ENOSYS, %rax
+- pushq $VGCF_in_syscall
++ pushq $0
+ jmp hypercall_iret
+ ENDPROC(xen_syscall32_target)
+ ENDPROC(xen_sysenter_target)
--- /dev/null
+From db05fed0ad72f264e39bcb366795f7367384ec92 Mon Sep 17 00:00:00 2001
+From: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
+Date: Tue, 24 Nov 2009 16:41:47 -0800
+Subject: xen/xenbus: make DEVICE_ATTR()s static
+
+From: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
+
+commit db05fed0ad72f264e39bcb366795f7367384ec92 upstream.
+
+They don't need to be global, and may cause linker clashes.
+
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/xen/xenbus/xenbus_probe.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/xen/xenbus/xenbus_probe.c
++++ b/drivers/xen/xenbus/xenbus_probe.c
+@@ -454,21 +454,21 @@ static ssize_t xendev_show_nodename(stru
+ {
+ return sprintf(buf, "%s\n", to_xenbus_device(dev)->nodename);
+ }
+-DEVICE_ATTR(nodename, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_nodename, NULL);
++static DEVICE_ATTR(nodename, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_nodename, NULL);
+
+ static ssize_t xendev_show_devtype(struct device *dev,
+ struct device_attribute *attr, char *buf)
+ {
+ return sprintf(buf, "%s\n", to_xenbus_device(dev)->devicetype);
+ }
+-DEVICE_ATTR(devtype, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_devtype, NULL);
++static DEVICE_ATTR(devtype, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_devtype, NULL);
+
+ static ssize_t xendev_show_modalias(struct device *dev,
+ struct device_attribute *attr, char *buf)
+ {
+ return sprintf(buf, "xen:%s\n", to_xenbus_device(dev)->devicetype);
+ }
+-DEVICE_ATTR(modalias, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_modalias, NULL);
++static DEVICE_ATTR(modalias, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_modalias, NULL);
+
+ int xenbus_probe_node(struct xen_bus_type *bus,
+ const char *type,