]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.10-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 4 Jun 2014 05:58:58 +0000 (22:58 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 4 Jun 2014 05:58:58 +0000 (22:58 -0700)
added patches:
asoc-wm8962-update-register-class_d_control_1-to-be-non-volatile.patch
iwlwifi-pcie-disable-interrupts-upon-pcie-alloc.patch
metag-fix-memory-barriers.patch
metag-reduce-maximum-stack-size-to-256mb.patch
x86-64-modify_ldt-make-support-for-16-bit-segments-a-runtime-option.patch
xen-blkfront-restore-the-non-persistent-data-path.patch
xen-blkfront-revoke-foreign-access-for-grants-not-mapped-by-the-backend.patch

queue-3.10/asoc-wm8962-update-register-class_d_control_1-to-be-non-volatile.patch [new file with mode: 0644]
queue-3.10/iwlwifi-pcie-disable-interrupts-upon-pcie-alloc.patch [new file with mode: 0644]
queue-3.10/metag-fix-memory-barriers.patch [new file with mode: 0644]
queue-3.10/metag-reduce-maximum-stack-size-to-256mb.patch [new file with mode: 0644]
queue-3.10/series
queue-3.10/x86-64-modify_ldt-make-support-for-16-bit-segments-a-runtime-option.patch [new file with mode: 0644]
queue-3.10/xen-blkfront-restore-the-non-persistent-data-path.patch [new file with mode: 0644]
queue-3.10/xen-blkfront-revoke-foreign-access-for-grants-not-mapped-by-the-backend.patch [new file with mode: 0644]

diff --git a/queue-3.10/asoc-wm8962-update-register-class_d_control_1-to-be-non-volatile.patch b/queue-3.10/asoc-wm8962-update-register-class_d_control_1-to-be-non-volatile.patch
new file mode 100644 (file)
index 0000000..21c223d
--- /dev/null
@@ -0,0 +1,86 @@
+From 44330ab516c15dda8a1e660eeaf0003f84e43e3f Mon Sep 17 00:00:00 2001
+From: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
+Date: Tue, 13 May 2014 13:45:15 +0100
+Subject: ASoC: wm8962: Update register CLASS_D_CONTROL_1 to be non-volatile
+
+From: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
+
+commit 44330ab516c15dda8a1e660eeaf0003f84e43e3f upstream.
+
+The register CLASS_D_CONTROL_1 is marked as volatile because it contains
+a bit, DAC_MUTE, which is also mirrored in the ADC_DAC_CONTROL_1
+register. This causes problems for the "Speaker Switch" control, which
+will report an error if the CODEC is suspended because it relies on a
+volatile register.
+
+To resolve this issue mark CLASS_D_CONTROL_1 as non-volatile and
+manually keep the register cache in sync by updating both bits when
+changing the mute status.
+
+Reported-by: Shawn Guo <shawn.guo@linaro.org>
+Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
+Tested-by: Shawn Guo <shawn.guo@linaro.org>
+Signed-off-by: Mark Brown <broonie@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/soc/codecs/wm8962.c |   15 ++++++++++++---
+ sound/soc/codecs/wm8962.h |    4 ++++
+ 2 files changed, 16 insertions(+), 3 deletions(-)
+
+--- a/sound/soc/codecs/wm8962.c
++++ b/sound/soc/codecs/wm8962.c
+@@ -153,6 +153,7 @@ static struct reg_default wm8962_reg[] =
+       { 40, 0x0000 },   /* R40    - SPKOUTL volume */
+       { 41, 0x0000 },   /* R41    - SPKOUTR volume */
++      { 49, 0x0010 },   /* R49    - Class D Control 1 */
+       { 51, 0x0003 },   /* R51    - Class D Control 2 */
+       { 56, 0x0506 },   /* R56    - Clocking 4 */
+@@ -794,7 +795,6 @@ static bool wm8962_volatile_register(str
+       case WM8962_ALC2:
+       case WM8962_THERMAL_SHUTDOWN_STATUS:
+       case WM8962_ADDITIONAL_CONTROL_4:
+-      case WM8962_CLASS_D_CONTROL_1:
+       case WM8962_DC_SERVO_6:
+       case WM8962_INTERRUPT_STATUS_1:
+       case WM8962_INTERRUPT_STATUS_2:
+@@ -2901,13 +2901,22 @@ static int wm8962_set_fll(struct snd_soc
+ static int wm8962_mute(struct snd_soc_dai *dai, int mute)
+ {
+       struct snd_soc_codec *codec = dai->codec;
+-      int val;
++      int val, ret;
+       if (mute)
+-              val = WM8962_DAC_MUTE;
++              val = WM8962_DAC_MUTE | WM8962_DAC_MUTE_ALT;
+       else
+               val = 0;
++      /**
++       * The DAC mute bit is mirrored in two registers, update both to keep
++       * the register cache consistent.
++       */
++      ret = snd_soc_update_bits(codec, WM8962_CLASS_D_CONTROL_1,
++                                WM8962_DAC_MUTE_ALT, val);
++      if (ret < 0)
++              return ret;
++
+       return snd_soc_update_bits(codec, WM8962_ADC_DAC_CONTROL_1,
+                                  WM8962_DAC_MUTE, val);
+ }
+--- a/sound/soc/codecs/wm8962.h
++++ b/sound/soc/codecs/wm8962.h
+@@ -1954,6 +1954,10 @@
+ #define WM8962_SPKOUTL_ENA_MASK                 0x0040  /* SPKOUTL_ENA */
+ #define WM8962_SPKOUTL_ENA_SHIFT                     6  /* SPKOUTL_ENA */
+ #define WM8962_SPKOUTL_ENA_WIDTH                     1  /* SPKOUTL_ENA */
++#define WM8962_DAC_MUTE_ALT                     0x0010  /* DAC_MUTE */
++#define WM8962_DAC_MUTE_ALT_MASK                0x0010  /* DAC_MUTE */
++#define WM8962_DAC_MUTE_ALT_SHIFT                    4  /* DAC_MUTE */
++#define WM8962_DAC_MUTE_ALT_WIDTH                    1  /* DAC_MUTE */
+ #define WM8962_SPKOUTL_PGA_MUTE                 0x0002  /* SPKOUTL_PGA_MUTE */
+ #define WM8962_SPKOUTL_PGA_MUTE_MASK            0x0002  /* SPKOUTL_PGA_MUTE */
+ #define WM8962_SPKOUTL_PGA_MUTE_SHIFT                1  /* SPKOUTL_PGA_MUTE */
diff --git a/queue-3.10/iwlwifi-pcie-disable-interrupts-upon-pcie-alloc.patch b/queue-3.10/iwlwifi-pcie-disable-interrupts-upon-pcie-alloc.patch
new file mode 100644 (file)
index 0000000..19ae46b
--- /dev/null
@@ -0,0 +1,68 @@
+From 83f7a85f1134c6e914453f5747435415a23d516b Mon Sep 17 00:00:00 2001
+From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
+Date: Sun, 13 Apr 2014 16:03:11 +0300
+Subject: iwlwifi: pcie: disable interrupts upon PCIe alloc
+
+From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
+
+commit 83f7a85f1134c6e914453f5747435415a23d516b upstream.
+
+In case RFKILL is in KILL position, the NIC will issue an
+interrupt straight away. This interrupt won't be sent
+because it is masked in the hardware.
+But if our interrupt service routine is called for another
+reason (SHARED_IRQ), then we'll look at the interrupt cause
+and service it. This can cause bad things if we are not
+ready yet.
+Explicitly clean the interrupt cause register to make sure
+we won't service anything before we are ready to.
+
+Reported-and-tested-by: Alexander Monakov <amonakov@gmail.com>
+Reviewed-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/net/wireless/iwlwifi/pcie/trans.c |   10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
++++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
+@@ -1538,6 +1538,10 @@ struct iwl_trans *iwl_trans_pcie_alloc(s
+        * PCI Tx retries from interfering with C3 CPU state */
+       pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00);
++      trans->dev = &pdev->dev;
++      trans_pcie->pci_dev = pdev;
++      iwl_disable_interrupts(trans);
++
+       err = pci_enable_msi(pdev);
+       if (err) {
+               dev_err(&pdev->dev, "pci_enable_msi failed(0X%x)\n", err);
+@@ -1549,8 +1553,6 @@ struct iwl_trans *iwl_trans_pcie_alloc(s
+               }
+       }
+-      trans->dev = &pdev->dev;
+-      trans_pcie->pci_dev = pdev;
+       trans->hw_rev = iwl_read32(trans, CSR_HW_REV);
+       trans->hw_id = (pdev->device << 16) + pdev->subsystem_device;
+       snprintf(trans->hw_id_str, sizeof(trans->hw_id_str),
+@@ -1574,8 +1576,6 @@ struct iwl_trans *iwl_trans_pcie_alloc(s
+       if (!trans->dev_cmd_pool)
+               goto out_pci_disable_msi;
+-      trans_pcie->inta_mask = CSR_INI_SET_MASK;
+-
+       if (iwl_pcie_alloc_ict(trans))
+               goto out_free_cmd_pool;
+@@ -1586,6 +1586,8 @@ struct iwl_trans *iwl_trans_pcie_alloc(s
+               goto out_free_ict;
+       }
++      trans_pcie->inta_mask = CSR_INI_SET_MASK;
++
+       return trans;
+ out_free_ict:
diff --git a/queue-3.10/metag-fix-memory-barriers.patch b/queue-3.10/metag-fix-memory-barriers.patch
new file mode 100644 (file)
index 0000000..ef6796f
--- /dev/null
@@ -0,0 +1,62 @@
+From 2425ce84026c385b73ae72039f90d042d49e0394 Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+Date: Thu, 8 May 2014 15:51:37 -0400
+Subject: metag: fix memory barriers
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+commit 2425ce84026c385b73ae72039f90d042d49e0394 upstream.
+
+Volatile access doesn't really imply the compiler barrier. Volatile access
+is only ordered with respect to other volatile accesses, it isn't ordered
+with respect to general memory accesses. Gcc may reorder memory accesses
+around volatile access, as we can see in this simple example (if we
+compile it with optimization, both increments of *b will be collapsed to
+just one):
+
+void fn(volatile int *a, long *b)
+{
+       (*b)++;
+       *a = 10;
+       (*b)++;
+}
+
+Consequently, we need the compiler barrier after a write to the volatile
+variable, to make sure that the compiler doesn't reorder the volatile
+write with something else.
+
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Acked-by: Peter Zijlstra <peterz@infradead.org>
+Signed-off-by: James Hogan <james.hogan@imgtec.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/metag/include/asm/barrier.h |    3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/arch/metag/include/asm/barrier.h
++++ b/arch/metag/include/asm/barrier.h
+@@ -15,6 +15,7 @@ static inline void wr_fence(void)
+       volatile int *flushptr = (volatile int *) LINSYSEVENT_WR_FENCE;
+       barrier();
+       *flushptr = 0;
++      barrier();
+ }
+ #else /* CONFIG_METAG_META21 */
+@@ -35,6 +36,7 @@ static inline void wr_fence(void)
+       *flushptr = 0;
+       *flushptr = 0;
+       *flushptr = 0;
++      barrier();
+ }
+ #endif /* !CONFIG_METAG_META21 */
+@@ -68,6 +70,7 @@ static inline void fence(void)
+       volatile int *flushptr = (volatile int *) LINSYSEVENT_WR_ATOMIC_UNLOCK;
+       barrier();
+       *flushptr = 0;
++      barrier();
+ }
+ #define smp_mb()        fence()
+ #define smp_rmb()       fence()
diff --git a/queue-3.10/metag-reduce-maximum-stack-size-to-256mb.patch b/queue-3.10/metag-reduce-maximum-stack-size-to-256mb.patch
new file mode 100644 (file)
index 0000000..3db91c7
--- /dev/null
@@ -0,0 +1,74 @@
+From d71f290b4e98a39f49f2595a13be3b4d5ce8e1f1 Mon Sep 17 00:00:00 2001
+From: James Hogan <james.hogan@imgtec.com>
+Date: Tue, 13 May 2014 23:58:24 +0100
+Subject: metag: Reduce maximum stack size to 256MB
+
+From: James Hogan <james.hogan@imgtec.com>
+
+commit d71f290b4e98a39f49f2595a13be3b4d5ce8e1f1 upstream.
+
+Specify the maximum stack size for arches where the stack grows upward
+(parisc and metag) in asm/processor.h rather than hard coding in
+fs/exec.c so that metag can specify a smaller value of 256MB rather than
+1GB.
+
+This fixes a BUG on metag if the RLIMIT_STACK hard limit is increased
+beyond a safe value by root. E.g. when starting a process after running
+"ulimit -H -s unlimited" it will then attempt to use a stack size of the
+maximum 1GB which is far too big for metag's limited user virtual
+address space (stack_top is usually 0x3ffff000):
+
+BUG: failure at fs/exec.c:589/shift_arg_pages()!
+
+Signed-off-by: James Hogan <james.hogan@imgtec.com>
+Cc: Helge Deller <deller@gmx.de>
+Cc: "James E.J. Bottomley" <jejb@parisc-linux.org>
+Cc: linux-parisc@vger.kernel.org
+Cc: linux-metag@vger.kernel.org
+Cc: John David Anglin <dave.anglin@bell.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/metag/include/asm/processor.h  |    2 ++
+ arch/parisc/include/asm/processor.h |    2 ++
+ fs/exec.c                           |    6 +++---
+ 3 files changed, 7 insertions(+), 3 deletions(-)
+
+--- a/arch/metag/include/asm/processor.h
++++ b/arch/metag/include/asm/processor.h
+@@ -22,6 +22,8 @@
+ /* Add an extra page of padding at the top of the stack for the guard page. */
+ #define STACK_TOP     (TASK_SIZE - PAGE_SIZE)
+ #define STACK_TOP_MAX STACK_TOP
++/* Maximum virtual space for stack */
++#define STACK_SIZE_MAX        (1 << 28)       /* 256 MB */
+ /* This decides where the kernel will search for a free chunk of vm
+  * space during mmap's.
+--- a/arch/parisc/include/asm/processor.h
++++ b/arch/parisc/include/asm/processor.h
+@@ -53,6 +53,8 @@
+ #define STACK_TOP     TASK_SIZE
+ #define STACK_TOP_MAX DEFAULT_TASK_SIZE
++#define STACK_SIZE_MAX        (1 << 30)       /* 1 GB */
++
+ #endif
+ #ifndef __ASSEMBLY__
+--- a/fs/exec.c
++++ b/fs/exec.c
+@@ -654,10 +654,10 @@ int setup_arg_pages(struct linux_binprm
+       unsigned long rlim_stack;
+ #ifdef CONFIG_STACK_GROWSUP
+-      /* Limit stack size to 1GB */
++      /* Limit stack size */
+       stack_base = rlimit_max(RLIMIT_STACK);
+-      if (stack_base > (1 << 30))
+-              stack_base = 1 << 30;
++      if (stack_base > STACK_SIZE_MAX)
++              stack_base = STACK_SIZE_MAX;
+       /* Make sure we didn't let the argument array grow too large. */
+       if (vma->vm_end - vma->vm_start > stack_base)
index 32746d1fb50a830a9b5cabc6d28e7b74134abcd0..75c4d719a3f514bfa36a8ae0a196538e29822272 100644 (file)
@@ -76,3 +76,10 @@ workqueue-fix-a-possible-race-condition-between-rescuer-and-pwq-release.patch
 workqueue-make-rescuer_thread-empty-wq-maydays-list-before-exiting.patch
 bus-mvebu-mbus-allow-several-windows-with-the-same-target-attribute.patch
 percpu-make-pcpu_alloc_chunk-use-pcpu_mem_free-instead-of-kfree.patch
+xen-blkfront-revoke-foreign-access-for-grants-not-mapped-by-the-backend.patch
+xen-blkfront-restore-the-non-persistent-data-path.patch
+iwlwifi-pcie-disable-interrupts-upon-pcie-alloc.patch
+asoc-wm8962-update-register-class_d_control_1-to-be-non-volatile.patch
+metag-fix-memory-barriers.patch
+metag-reduce-maximum-stack-size-to-256mb.patch
+x86-64-modify_ldt-make-support-for-16-bit-segments-a-runtime-option.patch
diff --git a/queue-3.10/x86-64-modify_ldt-make-support-for-16-bit-segments-a-runtime-option.patch b/queue-3.10/x86-64-modify_ldt-make-support-for-16-bit-segments-a-runtime-option.patch
new file mode 100644 (file)
index 0000000..6f87aca
--- /dev/null
@@ -0,0 +1,86 @@
+From fa81511bb0bbb2b1aace3695ce869da9762624ff Mon Sep 17 00:00:00 2001
+From: Linus Torvalds <torvalds@linux-foundation.org>
+Date: Wed, 14 May 2014 16:33:54 -0700
+Subject: x86-64, modify_ldt: Make support for 16-bit segments a runtime option
+
+From: Linus Torvalds <torvalds@linux-foundation.org>
+
+commit fa81511bb0bbb2b1aace3695ce869da9762624ff upstream.
+
+Checkin:
+
+b3b42ac2cbae x86-64, modify_ldt: Ban 16-bit segments on 64-bit kernels
+
+disabled 16-bit segments on 64-bit kernels due to an information
+leak.  However, it does seem that people are genuinely using Wine to
+run old 16-bit Windows programs on Linux.
+
+A proper fix for this ("espfix64") is coming in the upcoming merge
+window, but as a temporary fix, create a sysctl to allow the
+administrator to re-enable support for 16-bit segments.
+
+It adds a "/proc/sys/abi/ldt16" sysctl that defaults to zero (off). If
+you hit this issue and care about your old Windows program more than
+you care about a kernel stack address information leak, you can do
+
+   echo 1 > /proc/sys/abi/ldt16
+
+as root (add it to your startup scripts), and you should be ok.
+
+The sysctl table is only added if you have COMPAT support enabled on
+x86-64, but I assume anybody who runs old windows binaries very much
+does that ;)
+
+Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
+Link: http://lkml.kernel.org/r/CA%2B55aFw9BPoD10U1LfHbOMpHWZkvJTkMcfCs9s3urPr1YyWBxw@mail.gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/kernel/ldt.c        |    4 +++-
+ arch/x86/vdso/vdso32-setup.c |    8 ++++++++
+ 2 files changed, 11 insertions(+), 1 deletion(-)
+
+--- a/arch/x86/kernel/ldt.c
++++ b/arch/x86/kernel/ldt.c
+@@ -20,6 +20,8 @@
+ #include <asm/mmu_context.h>
+ #include <asm/syscalls.h>
++int sysctl_ldt16 = 0;
++
+ #ifdef CONFIG_SMP
+ static void flush_ldt(void *current_mm)
+ {
+@@ -234,7 +236,7 @@ static int write_ldt(void __user *ptr, u
+        * IRET leaking the high bits of the kernel stack address.
+        */
+ #ifdef CONFIG_X86_64
+-      if (!ldt_info.seg_32bit) {
++      if (!ldt_info.seg_32bit && !sysctl_ldt16) {
+               error = -EINVAL;
+               goto out_unlock;
+       }
+--- a/arch/x86/vdso/vdso32-setup.c
++++ b/arch/x86/vdso/vdso32-setup.c
+@@ -41,6 +41,7 @@ enum {
+ #ifdef CONFIG_X86_64
+ #define vdso_enabled                  sysctl_vsyscall32
+ #define arch_setup_additional_pages   syscall32_setup_pages
++extern int sysctl_ldt16;
+ #endif
+ /*
+@@ -379,6 +380,13 @@ static ctl_table abi_table2[] = {
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec
++      },
++      {
++              .procname       = "ldt16",
++              .data           = &sysctl_ldt16,
++              .maxlen         = sizeof(int),
++              .mode           = 0644,
++              .proc_handler   = proc_dointvec
+       },
+       {}
+ };
diff --git a/queue-3.10/xen-blkfront-restore-the-non-persistent-data-path.patch b/queue-3.10/xen-blkfront-restore-the-non-persistent-data-path.patch
new file mode 100644 (file)
index 0000000..ce77479
--- /dev/null
@@ -0,0 +1,279 @@
+From bfe11d6de1c416cea4f3f0f35f864162063ce3fa Mon Sep 17 00:00:00 2001
+From: Roger Pau Monne <roger.pau@citrix.com>
+Date: Tue, 29 Oct 2013 18:31:14 +0100
+Subject: xen-blkfront: restore the non-persistent data path
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Roger Pau Monne <roger.pau@citrix.com>
+
+commit bfe11d6de1c416cea4f3f0f35f864162063ce3fa upstream.
+
+When persistent grants were added they were always used, even if the
+backend doesn't have this feature (there's no harm in always using the
+same set of pages). This restores the old data path when the backend
+doesn't have persistent grants, removing the burden of doing a memcpy
+when it is not actually needed.
+
+Signed-off-by: Roger Pau MonnĂ© <roger.pau@citrix.com>
+Reported-by: Felipe Franciosi <felipe.franciosi@citrix.com>
+Cc: Felipe Franciosi <felipe.franciosi@citrix.com>
+Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
+Cc: David Vrabel <david.vrabel@citrix.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
+[v2: Fix up whitespace issues]
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/block/xen-blkfront.c |  105 ++++++++++++++++++++++++++++++-------------
+ 1 file changed, 74 insertions(+), 31 deletions(-)
+
+--- a/drivers/block/xen-blkfront.c
++++ b/drivers/block/xen-blkfront.c
+@@ -104,7 +104,7 @@ struct blkfront_info
+       struct work_struct work;
+       struct gnttab_free_callback callback;
+       struct blk_shadow shadow[BLK_RING_SIZE];
+-      struct list_head persistent_gnts;
++      struct list_head grants;
+       unsigned int persistent_gnts_c;
+       unsigned long shadow_free;
+       unsigned int feature_flush;
+@@ -175,15 +175,17 @@ static int fill_grant_buffer(struct blkf
+               if (!gnt_list_entry)
+                       goto out_of_memory;
+-              granted_page = alloc_page(GFP_NOIO);
+-              if (!granted_page) {
+-                      kfree(gnt_list_entry);
+-                      goto out_of_memory;
++              if (info->feature_persistent) {
++                      granted_page = alloc_page(GFP_NOIO);
++                      if (!granted_page) {
++                              kfree(gnt_list_entry);
++                              goto out_of_memory;
++                      }
++                      gnt_list_entry->pfn = page_to_pfn(granted_page);
+               }
+-              gnt_list_entry->pfn = page_to_pfn(granted_page);
+               gnt_list_entry->gref = GRANT_INVALID_REF;
+-              list_add(&gnt_list_entry->node, &info->persistent_gnts);
++              list_add(&gnt_list_entry->node, &info->grants);
+               i++;
+       }
+@@ -191,9 +193,10 @@ static int fill_grant_buffer(struct blkf
+ out_of_memory:
+       list_for_each_entry_safe(gnt_list_entry, n,
+-                               &info->persistent_gnts, node) {
++                               &info->grants, node) {
+               list_del(&gnt_list_entry->node);
+-              __free_page(pfn_to_page(gnt_list_entry->pfn));
++              if (info->feature_persistent)
++                      __free_page(pfn_to_page(gnt_list_entry->pfn));
+               kfree(gnt_list_entry);
+               i--;
+       }
+@@ -202,14 +205,14 @@ out_of_memory:
+ }
+ static struct grant *get_grant(grant_ref_t *gref_head,
++                               unsigned long pfn,
+                                struct blkfront_info *info)
+ {
+       struct grant *gnt_list_entry;
+       unsigned long buffer_mfn;
+-      BUG_ON(list_empty(&info->persistent_gnts));
+-      gnt_list_entry = list_first_entry(&info->persistent_gnts, struct grant,
+-                                        node);
++      BUG_ON(list_empty(&info->grants));
++      gnt_list_entry = list_first_entry(&info->grants, struct grant, node);
+       list_del(&gnt_list_entry->node);
+       if (gnt_list_entry->gref != GRANT_INVALID_REF) {
+@@ -220,6 +223,10 @@ static struct grant *get_grant(grant_ref
+       /* Assign a gref to this page */
+       gnt_list_entry->gref = gnttab_claim_grant_reference(gref_head);
+       BUG_ON(gnt_list_entry->gref == -ENOSPC);
++      if (!info->feature_persistent) {
++              BUG_ON(!pfn);
++              gnt_list_entry->pfn = pfn;
++      }
+       buffer_mfn = pfn_to_mfn(gnt_list_entry->pfn);
+       gnttab_grant_foreign_access_ref(gnt_list_entry->gref,
+                                       info->xbdev->otherend_id,
+@@ -430,12 +437,12 @@ static int blkif_queue_request(struct re
+                       fsect = sg->offset >> 9;
+                       lsect = fsect + (sg->length >> 9) - 1;
+-                      gnt_list_entry = get_grant(&gref_head, info);
++                      gnt_list_entry = get_grant(&gref_head, page_to_pfn(sg_page(sg)), info);
+                       ref = gnt_list_entry->gref;
+                       info->shadow[id].grants_used[i] = gnt_list_entry;
+-                      if (rq_data_dir(req)) {
++                      if (rq_data_dir(req) && info->feature_persistent) {
+                               char *bvec_data;
+                               void *shared_data;
+@@ -828,16 +835,17 @@ static void blkif_free(struct blkfront_i
+               blk_stop_queue(info->rq);
+       /* Remove all persistent grants */
+-      if (!list_empty(&info->persistent_gnts)) {
++      if (!list_empty(&info->grants)) {
+               list_for_each_entry_safe(persistent_gnt, n,
+-                                       &info->persistent_gnts, node) {
++                                       &info->grants, node) {
+                       list_del(&persistent_gnt->node);
+                       if (persistent_gnt->gref != GRANT_INVALID_REF) {
+                               gnttab_end_foreign_access(persistent_gnt->gref,
+                                                         0, 0UL);
+                               info->persistent_gnts_c--;
+                       }
+-                      __free_page(pfn_to_page(persistent_gnt->pfn));
++                      if (info->feature_persistent)
++                              __free_page(pfn_to_page(persistent_gnt->pfn));
+                       kfree(persistent_gnt);
+               }
+       }
+@@ -874,7 +882,7 @@ static void blkif_completion(struct blk_
+       nseg = s->req.u.rw.nr_segments;
+-      if (bret->operation == BLKIF_OP_READ) {
++      if (bret->operation == BLKIF_OP_READ && info->feature_persistent) {
+               /*
+                * Copy the data received from the backend into the bvec.
+                * Since bv_offset can be different than 0, and bv_len different
+@@ -902,7 +910,10 @@ static void blkif_completion(struct blk_
+                        * we add it at the head of the list, so it will be
+                        * reused first.
+                        */
+-                      list_add(&s->grants_used[i]->node, &info->persistent_gnts);
++                      if (!info->feature_persistent)
++                              pr_alert_ratelimited("backed has not unmapped grant: %u\n",
++                                                   s->grants_used[i]->gref);
++                      list_add(&s->grants_used[i]->node, &info->grants);
+                       info->persistent_gnts_c++;
+               } else {
+                       /*
+@@ -913,7 +924,7 @@ static void blkif_completion(struct blk_
+                        */
+                       gnttab_end_foreign_access(s->grants_used[i]->gref, 0, 0UL);
+                       s->grants_used[i]->gref = GRANT_INVALID_REF;
+-                      list_add_tail(&s->grants_used[i]->node, &info->persistent_gnts);
++                      list_add_tail(&s->grants_used[i]->node, &info->grants);
+               }
+       }
+ }
+@@ -1052,12 +1063,6 @@ static int setup_blkring(struct xenbus_d
+       for (i = 0; i < BLK_RING_SIZE; i++)
+               sg_init_table(info->shadow[i].sg, BLKIF_MAX_SEGMENTS_PER_REQUEST);
+-      /* Allocate memory for grants */
+-      err = fill_grant_buffer(info, BLK_RING_SIZE *
+-                                    BLKIF_MAX_SEGMENTS_PER_REQUEST);
+-      if (err)
+-              goto fail;
+-
+       err = xenbus_grant_ring(dev, virt_to_mfn(info->ring.sring));
+       if (err < 0) {
+               free_page((unsigned long)sring);
+@@ -1216,7 +1221,7 @@ static int blkfront_probe(struct xenbus_
+       spin_lock_init(&info->io_lock);
+       info->xbdev = dev;
+       info->vdevice = vdevice;
+-      INIT_LIST_HEAD(&info->persistent_gnts);
++      INIT_LIST_HEAD(&info->grants);
+       info->persistent_gnts_c = 0;
+       info->connected = BLKIF_STATE_DISCONNECTED;
+       INIT_WORK(&info->work, blkif_restart_queue);
+@@ -1245,7 +1250,8 @@ static int blkif_recover(struct blkfront
+       int i;
+       struct blkif_request *req;
+       struct blk_shadow *copy;
+-      int j;
++      unsigned int persistent;
++      int j, rc;
+       /* Stage 1: Make a safe copy of the shadow state. */
+       copy = kmemdup(info->shadow, sizeof(info->shadow),
+@@ -1260,6 +1266,24 @@ static int blkif_recover(struct blkfront
+       info->shadow_free = info->ring.req_prod_pvt;
+       info->shadow[BLK_RING_SIZE-1].req.u.rw.id = 0x0fffffff;
++      /* Check if the backend supports persistent grants */
++      rc = xenbus_gather(XBT_NIL, info->xbdev->otherend,
++                         "feature-persistent", "%u", &persistent,
++                         NULL);
++      if (rc)
++              info->feature_persistent = 0;
++      else
++              info->feature_persistent = persistent;
++
++      /* Allocate memory for grants */
++      rc = fill_grant_buffer(info, BLK_RING_SIZE *
++                                   BLKIF_MAX_SEGMENTS_PER_REQUEST);
++      if (rc) {
++              xenbus_dev_fatal(info->xbdev, rc, "setting grant buffer failed");
++              kfree(copy);
++              return rc;
++      }
++
+       /* Stage 3: Find pending requests and requeue them. */
+       for (i = 0; i < BLK_RING_SIZE; i++) {
+               /* Not in use? */
+@@ -1324,8 +1348,12 @@ static int blkfront_resume(struct xenbus
+       blkif_free(info, info->connected == BLKIF_STATE_CONNECTED);
+       err = talk_to_blkback(dev, info);
+-      if (info->connected == BLKIF_STATE_SUSPENDED && !err)
+-              err = blkif_recover(info);
++
++      /*
++       * We have to wait for the backend to switch to
++       * connected state, since we want to read which
++       * features it supports.
++       */
+       return err;
+ }
+@@ -1429,9 +1457,16 @@ static void blkfront_connect(struct blkf
+                      sectors);
+               set_capacity(info->gd, sectors);
+               revalidate_disk(info->gd);
++              return;
+-              /* fall through */
+       case BLKIF_STATE_SUSPENDED:
++              /*
++               * If we are recovering from suspension, we need to wait
++               * for the backend to announce it's features before
++               * reconnecting, we need to know if the backend supports
++               * persistent grants.
++               */
++              blkif_recover(info);
+               return;
+       default:
+@@ -1499,6 +1534,14 @@ static void blkfront_connect(struct blkf
+       else
+               info->feature_persistent = persistent;
++      /* Allocate memory for grants */
++      err = fill_grant_buffer(info, BLK_RING_SIZE *
++                                    BLKIF_MAX_SEGMENTS_PER_REQUEST);
++      if (err) {
++              xenbus_dev_fatal(info->xbdev, err, "setting grant buffer failed");
++              return;
++      }
++
+       err = xlvbd_alloc_gendisk(sectors, info, binfo, sector_size);
+       if (err) {
+               xenbus_dev_fatal(info->xbdev, err, "xlvbd_add at %s",
diff --git a/queue-3.10/xen-blkfront-revoke-foreign-access-for-grants-not-mapped-by-the-backend.patch b/queue-3.10/xen-blkfront-revoke-foreign-access-for-grants-not-mapped-by-the-backend.patch
new file mode 100644 (file)
index 0000000..9fb3cfd
--- /dev/null
@@ -0,0 +1,70 @@
+From fbe363c476afe8ec992d3baf682670a4bd1b6ce6 Mon Sep 17 00:00:00 2001
+From: Roger Pau Monne <roger.pau@citrix.com>
+Date: Mon, 12 Aug 2013 12:53:44 +0200
+Subject: xen-blkfront: revoke foreign access for grants not mapped by the backend
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Roger Pau Monne <roger.pau@citrix.com>
+
+commit fbe363c476afe8ec992d3baf682670a4bd1b6ce6 upstream.
+
+There's no need to keep the foreign access in a grant if it is not
+persistently mapped by the backend. This allows us to free grants that
+are not mapped by the backend, thus preventing blkfront from hoarding
+all grants.
+
+The main effect of this is that blkfront will only persistently map
+the same grants as the backend, and it will always try to use grants
+that are already mapped by the backend. Also the number of persistent
+grants in blkfront is the same as in blkback (and is controlled by the
+value in blkback).
+
+Signed-off-by: Roger Pau MonnĂ© <roger.pau@citrix.com>
+Reviewed-by: David Vrabel <david.vrabel@citrix.com>
+Acked-by: Matt Wilson <msw@amazon.com>
+Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
+Cc: David Vrabel <david.vrabel@citrix.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+
+---
+ drivers/block/xen-blkfront.c |   24 +++++++++++++++++++++---
+ 1 file changed, 21 insertions(+), 3 deletions(-)
+
+--- a/drivers/block/xen-blkfront.c
++++ b/drivers/block/xen-blkfront.c
+@@ -894,9 +894,27 @@ static void blkif_completion(struct blk_
+               }
+       }
+       /* Add the persistent grant into the list of free grants */
+-      for (i = 0; i < s->req.u.rw.nr_segments; i++) {
+-              list_add(&s->grants_used[i]->node, &info->persistent_gnts);
+-              info->persistent_gnts_c++;
++      for (i = 0; i < nseg; i++) {
++              if (gnttab_query_foreign_access(s->grants_used[i]->gref)) {
++                      /*
++                       * If the grant is still mapped by the backend (the
++                       * backend has chosen to make this grant persistent)
++                       * we add it at the head of the list, so it will be
++                       * reused first.
++                       */
++                      list_add(&s->grants_used[i]->node, &info->persistent_gnts);
++                      info->persistent_gnts_c++;
++              } else {
++                      /*
++                       * If the grant is not mapped by the backend we end the
++                       * foreign access and add it to the tail of the list,
++                       * so it will not be picked again unless we run out of
++                       * persistent grants.
++                       */
++                      gnttab_end_foreign_access(s->grants_used[i]->gref, 0, 0UL);
++                      s->grants_used[i]->gref = GRANT_INVALID_REF;
++                      list_add_tail(&s->grants_used[i]->node, &info->persistent_gnts);
++              }
+       }
+ }