]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
2.6.39 patches
authorGreg Kroah-Hartman <gregkh@suse.de>
Mon, 1 Aug 2011 18:58:34 +0000 (11:58 -0700)
committerGreg Kroah-Hartman <gregkh@suse.de>
Mon, 1 Aug 2011 18:58:34 +0000 (11:58 -0700)
17 files changed:
queue-2.6.39/cifs-clean-up-wsize-negotiation-and-allow-for-larger-wsize.patch [new file with mode: 0644]
queue-2.6.39/cifs-fix-wsize-negotiation-to-respect-max-buffer-size-and.patch [new file with mode: 0644]
queue-2.6.39/cifs-lower-default-and-max-wsize-to-what-2.6.39-can-handle.patch [new file with mode: 0644]
queue-2.6.39/davinci-dm365-evm-fix-video-input-mux-bits.patch [new file with mode: 0644]
queue-2.6.39/ext4-fix-oops-in-ext4_quota_off.patch [new file with mode: 0644]
queue-2.6.39/libata-fix-unexpectedly-frozen-port-after-ata_eh_reset.patch [new file with mode: 0644]
queue-2.6.39/mm-compaction-abort-compaction-if-too-many-pages-are-isolated-and-caller-is-asynchronous-v2.patch [new file with mode: 0644]
queue-2.6.39/mm-compaction-ensure-that-the-compaction-free-scanner-does-not-move-to-the-next-zone.patch [new file with mode: 0644]
queue-2.6.39/mm-vmscan-do-not-apply-pressure-to-slab-if-we-are-not-applying-pressure-to-zone.patch [new file with mode: 0644]
queue-2.6.39/mm-vmscan-do-not-use-page_count-without-a-page-pin.patch [new file with mode: 0644]
queue-2.6.39/mm-vmscan-only-read-new_classzone_idx-from-pgdat-when-reclaiming-successfully.patch [new file with mode: 0644]
queue-2.6.39/revert-dibxxxx-get-rid-of-dma-buffer-on-stack.patch [new file with mode: 0644]
queue-2.6.39/series
queue-2.6.39/vfs-fix-race-in-rcu-lookup-of-pruned-dentry.patch [new file with mode: 0644]
queue-2.6.39/vmscan-fix-a-livelock-in-kswapd.patch [new file with mode: 0644]
queue-2.6.39/x86-make-dell-latitude-e5420-use-reboot-pci.patch [new file with mode: 0644]
queue-2.6.39/xfs-restart-busy-extent-search-after-node-removal.patch [new file with mode: 0644]

diff --git a/queue-2.6.39/cifs-clean-up-wsize-negotiation-and-allow-for-larger-wsize.patch b/queue-2.6.39/cifs-clean-up-wsize-negotiation-and-allow-for-larger-wsize.patch
new file mode 100644 (file)
index 0000000..f246e94
--- /dev/null
@@ -0,0 +1,126 @@
+From f7910cbd9fa319ee4501074f1f3b5ce23c4b1518 Mon Sep 17 00:00:00 2001
+From: Jeff Layton <jlayton@redhat.com>
+Date: Thu, 19 May 2011 16:22:58 -0400
+Subject: cifs: clean up wsize negotiation and allow for larger wsize
+
+From: Jeff Layton <jlayton@redhat.com>
+
+commit f7910cbd9fa319ee4501074f1f3b5ce23c4b1518 upstream.
+
+Now that we can handle larger wsizes in writepages, fix up the
+negotiation of the wsize to allow for that. find_get_pages only seems to
+give out a max of 256 pages at a time, so that gives us a reasonable
+default of 1M for the wsize.
+
+If the server however does not support large writes via POSIX
+extensions, then we cap the wsize to (128k - PAGE_CACHE_SIZE). That
+gives us a size that goes up to the max frame size specified in RFC1001.
+
+Finally, if CAP_LARGE_WRITE_AND_X isn't set, then further cap it to the
+largest size allowed by the protocol (USHRT_MAX).
+
+Signed-off-by: Jeff Layton <jlayton@redhat.com>
+Reviewed-and-Tested-by: Pavel Shilovsky <piastry@etersoft.ru>
+Signed-off-by: Steve French <sfrench@us.ibm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ fs/cifs/connect.c |   69 ++++++++++++++++++++++++++++++++++++++----------------
+ 1 file changed, 49 insertions(+), 20 deletions(-)
+
+--- a/fs/cifs/connect.c
++++ b/fs/cifs/connect.c
+@@ -2571,23 +2571,6 @@ static void setup_cifs_sb(struct smb_vol
+       else /* default */
+               cifs_sb->rsize = CIFSMaxBufSize;
+-      if (pvolume_info->wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
+-              cERROR(1, "wsize %d too large, using 4096 instead",
+-                        pvolume_info->wsize);
+-              cifs_sb->wsize = 4096;
+-      } else if (pvolume_info->wsize)
+-              cifs_sb->wsize = pvolume_info->wsize;
+-      else
+-              cifs_sb->wsize = min_t(const int,
+-                                      PAGEVEC_SIZE * PAGE_CACHE_SIZE,
+-                                      127*1024);
+-              /* old default of CIFSMaxBufSize was too small now
+-                 that SMB Write2 can send multiple pages in kvec.
+-                 RFC1001 does not describe what happens when frame
+-                 bigger than 128K is sent so use that as max in
+-                 conjunction with 52K kvec constraint on arch with 4K
+-                 page size  */
+-
+       if (cifs_sb->rsize < 2048) {
+               cifs_sb->rsize = 2048;
+               /* Windows ME may prefer this */
+@@ -2665,6 +2648,53 @@ static void setup_cifs_sb(struct smb_vol
+                          "mount option supported");
+ }
++/*
++ * When the server supports very large writes via POSIX extensions, we can
++ * allow up to 2^24 - PAGE_CACHE_SIZE.
++ *
++ * Note that this might make for "interesting" allocation problems during
++ * writeback however (as we have to allocate an array of pointers for the
++ * pages). A 16M write means ~32kb page array with PAGE_CACHE_SIZE == 4096.
++ */
++#define CIFS_MAX_WSIZE ((1<<24) - PAGE_CACHE_SIZE)
++
++/*
++ * When the server doesn't allow large posix writes, default to a wsize of
++ * 128k - PAGE_CACHE_SIZE -- one page less than the largest frame size
++ * described in RFC1001. This allows space for the header without going over
++ * that by default.
++ */
++#define CIFS_MAX_RFC1001_WSIZE (128 * 1024 - PAGE_CACHE_SIZE)
++
++/*
++ * The default wsize is 1M. find_get_pages seems to return a maximum of 256
++ * pages in a single call. With PAGE_CACHE_SIZE == 4k, this means we can fill
++ * a single wsize request with a single call.
++ */
++#define CIFS_DEFAULT_WSIZE (1024 * 1024)
++
++static unsigned int
++cifs_negotiate_wsize(struct cifsTconInfo *tcon, struct smb_vol *pvolume_info)
++{
++      __u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
++      struct TCP_Server_Info *server = tcon->ses->server;
++      unsigned int wsize = pvolume_info->wsize ? pvolume_info->wsize :
++                              CIFS_DEFAULT_WSIZE;
++
++      /* can server support 24-bit write sizes? (via UNIX extensions) */
++      if (!tcon->unix_ext || !(unix_cap & CIFS_UNIX_LARGE_WRITE_CAP))
++              wsize = min_t(unsigned int, wsize, CIFS_MAX_RFC1001_WSIZE);
++
++      /* no CAP_LARGE_WRITE_X? Limit it to 16 bits */
++      if (!(server->capabilities & CAP_LARGE_WRITE_X))
++              wsize = min_t(unsigned int, wsize, USHRT_MAX);
++
++      /* hard limit of CIFS_MAX_WSIZE */
++      wsize = min_t(unsigned int, wsize, CIFS_MAX_WSIZE);
++
++      return wsize;
++}
++
+ static int
+ is_path_accessible(int xid, struct cifsTconInfo *tcon,
+                  struct cifs_sb_info *cifs_sb, const char *full_path)
+@@ -2866,13 +2896,12 @@ try_mount_again:
+               cifs_sb->rsize = 1024 * 127;
+               cFYI(DBG2, "no very large read support, rsize now 127K");
+       }
+-      if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
+-              cifs_sb->wsize = min(cifs_sb->wsize,
+-                             (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
+       if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
+               cifs_sb->rsize = min(cifs_sb->rsize,
+                              (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
++      cifs_sb->wsize = cifs_negotiate_wsize(tcon, volume_info);
++
+ remote_path_check:
+       /* check if a whole path (including prepath) is not remote */
+       if (!rc && tcon) {
diff --git a/queue-2.6.39/cifs-fix-wsize-negotiation-to-respect-max-buffer-size-and.patch b/queue-2.6.39/cifs-fix-wsize-negotiation-to-respect-max-buffer-size-and.patch
new file mode 100644 (file)
index 0000000..8f0d318
--- /dev/null
@@ -0,0 +1,89 @@
+From 1190f6a067bf27b2ee7e06ec0776a17fe0f6c4d8 Mon Sep 17 00:00:00 2001
+From: Jeff Layton <jlayton@redhat.com>
+Date: Wed, 22 Jun 2011 17:33:57 -0400
+Subject: cifs: fix wsize negotiation to respect max buffer size and
+ active signing (try #4)
+
+From: Jeff Layton <jlayton@redhat.com>
+
+commit 1190f6a067bf27b2ee7e06ec0776a17fe0f6c4d8 upstream.
+
+Hopefully last version. Base signing check on CAP_UNIX instead of
+tcon->unix_ext, also clean up the comments a bit more.
+
+According to Hongwei Sun's blog posting here:
+
+    http://blogs.msdn.com/b/openspecification/archive/2009/04/10/smb-maximum-transmit-buffer-size-and-performance-tuning.aspx
+
+CAP_LARGE_WRITEX is ignored when signing is active. Also, the maximum
+size for a write without CAP_LARGE_WRITEX should be the maxBuf that
+the server sent in the NEGOTIATE request.
+
+Fix the wsize negotiation to take this into account. While we're at it,
+alter the other wsize definitions to use sizeof(WRITE_REQ) to allow for
+slightly larger amounts of data to potentially be written per request.
+
+Signed-off-by: Jeff Layton <jlayton@redhat.com>
+Signed-off-by: Steve French <sfrench@us.ibm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ fs/cifs/connect.c |   33 ++++++++++++++++++++-------------
+ 1 file changed, 20 insertions(+), 13 deletions(-)
+
+--- a/fs/cifs/connect.c
++++ b/fs/cifs/connect.c
+@@ -2650,21 +2650,21 @@ static void setup_cifs_sb(struct smb_vol
+ /*
+  * When the server supports very large writes via POSIX extensions, we can
+- * allow up to 2^24 - PAGE_CACHE_SIZE.
++ * allow up to 2^24-1, minus the size of a WRITE_AND_X header, not including
++ * the RFC1001 length.
+  *
+  * Note that this might make for "interesting" allocation problems during
+- * writeback however (as we have to allocate an array of pointers for the
+- * pages). A 16M write means ~32kb page array with PAGE_CACHE_SIZE == 4096.
++ * writeback however as we have to allocate an array of pointers for the
++ * pages. A 16M write means ~32kb page array with PAGE_CACHE_SIZE == 4096.
+  */
+-#define CIFS_MAX_WSIZE ((1<<24) - PAGE_CACHE_SIZE)
++#define CIFS_MAX_WSIZE ((1<<24) - 1 - sizeof(WRITE_REQ) + 4)
+ /*
+- * When the server doesn't allow large posix writes, default to a wsize of
+- * 128k - PAGE_CACHE_SIZE -- one page less than the largest frame size
+- * described in RFC1001. This allows space for the header without going over
+- * that by default.
++ * When the server doesn't allow large posix writes, only allow a wsize of
++ * 128k minus the size of the WRITE_AND_X header. That allows for a write up
++ * to the maximum size described by RFC1002.
+  */
+-#define CIFS_MAX_RFC1001_WSIZE (128 * 1024 - PAGE_CACHE_SIZE)
++#define CIFS_MAX_RFC1002_WSIZE (128 * 1024 - sizeof(WRITE_REQ) + 4)
+ /*
+  * The default wsize is 1M. find_get_pages seems to return a maximum of 256
+@@ -2683,11 +2683,18 @@ cifs_negotiate_wsize(struct cifsTconInfo
+       /* can server support 24-bit write sizes? (via UNIX extensions) */
+       if (!tcon->unix_ext || !(unix_cap & CIFS_UNIX_LARGE_WRITE_CAP))
+-              wsize = min_t(unsigned int, wsize, CIFS_MAX_RFC1001_WSIZE);
++              wsize = min_t(unsigned int, wsize, CIFS_MAX_RFC1002_WSIZE);
+-      /* no CAP_LARGE_WRITE_X? Limit it to 16 bits */
+-      if (!(server->capabilities & CAP_LARGE_WRITE_X))
+-              wsize = min_t(unsigned int, wsize, USHRT_MAX);
++      /*
++       * no CAP_LARGE_WRITE_X or is signing enabled without CAP_UNIX set?
++       * Limit it to max buffer offered by the server, minus the size of the
++       * WRITEX header, not including the 4 byte RFC1001 length.
++       */
++      if (!(server->capabilities & CAP_LARGE_WRITE_X) ||
++          (!(server->capabilities & CAP_UNIX) &&
++           (server->sec_mode & (SECMODE_SIGN_ENABLED|SECMODE_SIGN_REQUIRED))))
++              wsize = min_t(unsigned int, wsize,
++                              server->maxBuf - sizeof(WRITE_REQ) + 4);
+       /* hard limit of CIFS_MAX_WSIZE */
+       wsize = min_t(unsigned int, wsize, CIFS_MAX_WSIZE);
diff --git a/queue-2.6.39/cifs-lower-default-and-max-wsize-to-what-2.6.39-can-handle.patch b/queue-2.6.39/cifs-lower-default-and-max-wsize-to-what-2.6.39-can-handle.patch
new file mode 100644 (file)
index 0000000..7c9705b
--- /dev/null
@@ -0,0 +1,71 @@
+From jlayton@redhat.com  Mon Aug  1 11:49:28 2011
+From: Jeff Layton <jlayton@redhat.com>
+Date: Wed, 13 Jul 2011 06:40:37 -0400
+Subject: cifs: lower default and max wsize to what 2.6.39 can handle
+To: stable@kernel.org
+Cc: linux-cifs@vger.kernel.org, linux-kernel@vger.kernel.org, helge.hafting@hist.no
+Message-ID: <1310553637-26792-1-git-send-email-jlayton@redhat.com>
+
+From: Jeff Layton <jlayton@redhat.com>
+
+This patch is intended for 2.6.39-stable kernels only and is needed to
+fix a regression introduced in 2.6.39. Prior to 2.6.39, when signing was
+enabled on a socket the client only sent single-page writes. This
+changed with commit ca83ce3, which made signed and unsigned connections
+use the same codepaths for write calls.
+
+This caused a regression when working with windows servers. Windows
+machines will reject writes larger than the MaxBufferSize when signing
+is active, but do not clear the CAP_LARGE_WRITE_X flag in the protocol
+negotiation. The upshot is that when signing is active, windows servers
+often reject large writes from the client in 2.6.39.
+
+Because 3.0 adds support for larger wsize values, simply cherry picking
+the upstream patches that fix the wsize negotiation isn't sufficient to
+fix this issue. We also need to alter the maximum and default values to
+something suitable for 2.6.39.
+
+Cc: <stable@kernel.org> # .39.x: f7910cb: cifs: clean up wsize negotiation and allow for larger wsize
+Cc: <stable@kernel.org> # .39.x: 1190f6a: cifs: fix wsize negotiation to respect max buffer size and active signing (try #4)
+Signed-off-by: Jeff Layton <jlayton@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ fs/cifs/connect.c |   20 ++++----------------
+ 1 file changed, 4 insertions(+), 16 deletions(-)
+
+--- a/fs/cifs/connect.c
++++ b/fs/cifs/connect.c
+@@ -2648,16 +2648,8 @@ static void setup_cifs_sb(struct smb_vol
+                          "mount option supported");
+ }
+-/*
+- * When the server supports very large writes via POSIX extensions, we can
+- * allow up to 2^24-1, minus the size of a WRITE_AND_X header, not including
+- * the RFC1001 length.
+- *
+- * Note that this might make for "interesting" allocation problems during
+- * writeback however as we have to allocate an array of pointers for the
+- * pages. A 16M write means ~32kb page array with PAGE_CACHE_SIZE == 4096.
+- */
+-#define CIFS_MAX_WSIZE ((1<<24) - 1 - sizeof(WRITE_REQ) + 4)
++/* Prior to 3.0, cifs couldn't handle writes larger than this */
++#define CIFS_MAX_WSIZE (PAGEVEC_SIZE * PAGE_CACHE_SIZE)
+ /*
+  * When the server doesn't allow large posix writes, only allow a wsize of
+@@ -2666,12 +2658,8 @@ static void setup_cifs_sb(struct smb_vol
+  */
+ #define CIFS_MAX_RFC1002_WSIZE (128 * 1024 - sizeof(WRITE_REQ) + 4)
+-/*
+- * The default wsize is 1M. find_get_pages seems to return a maximum of 256
+- * pages in a single call. With PAGE_CACHE_SIZE == 4k, this means we can fill
+- * a single wsize request with a single call.
+- */
+-#define CIFS_DEFAULT_WSIZE (1024 * 1024)
++/* Make the default the same as the max */
++#define CIFS_DEFAULT_WSIZE CIFS_MAX_WSIZE
+ static unsigned int
+ cifs_negotiate_wsize(struct cifsTconInfo *tcon, struct smb_vol *pvolume_info)
diff --git a/queue-2.6.39/davinci-dm365-evm-fix-video-input-mux-bits.patch b/queue-2.6.39/davinci-dm365-evm-fix-video-input-mux-bits.patch
new file mode 100644 (file)
index 0000000..24336eb
--- /dev/null
@@ -0,0 +1,43 @@
+From 9daedd833a38edd90cf7baa1b1fcf61c3a0721e3 Mon Sep 17 00:00:00 2001
+From: Jon Povey <jon.povey@racelogic.co.uk>
+Date: Tue, 19 Jul 2011 12:30:11 +0900
+Subject: davinci: DM365 EVM: fix video input mux bits
+
+From: Jon Povey <jon.povey@racelogic.co.uk>
+
+commit 9daedd833a38edd90cf7baa1b1fcf61c3a0721e3 upstream.
+
+Video input mux settings for tvp7002 and imager inputs were swapped.
+Comment was correct.
+
+Tested on EVM with tvp7002 input.
+
+Signed-off-by: Jon Povey <jon.povey@racelogic.co.uk>
+Acked-by: Manjunath Hadli <manjunath.hadli@ti.com>
+Signed-off-by: Sekhar Nori <nsekhar@ti.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/arm/mach-davinci/board-dm365-evm.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/arch/arm/mach-davinci/board-dm365-evm.c
++++ b/arch/arm/mach-davinci/board-dm365-evm.c
+@@ -520,7 +520,7 @@ fail:
+        */
+       if (have_imager()) {
+               label = "HD imager";
+-              mux |= 1;
++              mux |= 2;
+               /* externally mux MMC1/ENET/AIC33 to imager */
+               mux |= BIT(6) | BIT(5) | BIT(3);
+@@ -540,7 +540,7 @@ fail:
+               resets &= ~BIT(1);
+               if (have_tvp7002()) {
+-                      mux |= 2;
++                      mux |= 1;
+                       resets &= ~BIT(2);
+                       label = "tvp7002 HD";
+               } else {
diff --git a/queue-2.6.39/ext4-fix-oops-in-ext4_quota_off.patch b/queue-2.6.39/ext4-fix-oops-in-ext4_quota_off.patch
new file mode 100644 (file)
index 0000000..df7d4a8
--- /dev/null
@@ -0,0 +1,39 @@
+From 0b26859027ce0005ef89520af20351360e51ad76 Mon Sep 17 00:00:00 2001
+From: Amir Goldstein <amir73il@gmail.com>
+Date: Mon, 16 May 2011 09:59:13 -0400
+Subject: ext4: fix oops in ext4_quota_off()
+
+From: Amir Goldstein <amir73il@gmail.com>
+
+commit 0b26859027ce0005ef89520af20351360e51ad76 upstream.
+
+If quota is not enabled when ext4_quota_off() is called, we must not
+dereference quota file inode since it is NULL.  Check properly for
+this.
+
+This fixes a bug in commit 21f976975cbe (ext4: remove unnecessary
+[cm]time update of quota file), which was merged for 2.6.39-rc3.
+
+Reported-by: Amir Goldstein <amir73il@users.sf.net>
+Signed-off-by: Amir Goldstein <amir73il@users.sf.net>
+Signed-off-by: Jan Kara <jack@suse.cz>
+Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
+Cc: Chris Dunlop <chris@onthe.net.au>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ fs/ext4/super.c |    3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/fs/ext4/super.c
++++ b/fs/ext4/super.c
+@@ -4635,6 +4635,9 @@ static int ext4_quota_off(struct super_b
+       if (test_opt(sb, DELALLOC))
+               sync_filesystem(sb);
++      if (!inode)
++              goto out;
++
+       /* Update modification times of quota files when userspace can
+        * start looking at them */
+       handle = ext4_journal_start(inode, 1);
diff --git a/queue-2.6.39/libata-fix-unexpectedly-frozen-port-after-ata_eh_reset.patch b/queue-2.6.39/libata-fix-unexpectedly-frozen-port-after-ata_eh_reset.patch
new file mode 100644 (file)
index 0000000..01d3819
--- /dev/null
@@ -0,0 +1,70 @@
+From 8c56cacc724c7650b893d43068fa66044aa29a61 Mon Sep 17 00:00:00 2001
+From: Tejun Heo <tj@kernel.org>
+Date: Wed, 25 May 2011 13:19:39 +0200
+Subject: libata: fix unexpectedly frozen port after ata_eh_reset()
+
+From: Tejun Heo <tj@kernel.org>
+
+commit 8c56cacc724c7650b893d43068fa66044aa29a61 upstream.
+
+To work around controllers which can't properly plug events while
+reset, ata_eh_reset() clears error states and ATA_PFLAG_EH_PENDING
+after reset but before RESET is marked done.  As reset is the final
+recovery action and full verification of devices including onlineness
+and classfication match is done afterwards, this shouldn't lead to
+lost devices or missed hotplug events.
+
+Unfortunately, it forgot to thaw the port when clearing EH_PENDING, so
+if the condition happens after resetting an empty port, the port could
+be left frozen and EH will end without thawing it, making the port
+unresponsive to further hotplug events.
+
+Thaw if the port is frozen after clearing EH_PENDING.  This problem is
+reported by Bruce Stenning in the following thread.
+
+ http://thread.gmane.org/gmane.linux.kernel/1123265
+
+stable: I think we should weather this patch a bit longer in -rcX
+       before sending it to -stable.  Please wait at least a month
+       after this patch makes upstream.  Thanks.
+
+-v2: Fixed spelling in the comment per Dave Howorth.
+
+Signed-off-by: Tejun Heo <tj@kernel.org>
+Reported-by: Bruce Stenning <b.stenning@indigovision.com>
+Cc: Dave Howorth <dhoworth@mrc-lmb.cam.ac.uk>
+Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/ata/libata-eh.c |   12 ++++++++----
+ 1 file changed, 8 insertions(+), 4 deletions(-)
+
+--- a/drivers/ata/libata-eh.c
++++ b/drivers/ata/libata-eh.c
+@@ -2802,10 +2802,11 @@ int ata_eh_reset(struct ata_link *link,
+       }
+       /*
+-       * Some controllers can't be frozen very well and may set
+-       * spuruious error conditions during reset.  Clear accumulated
+-       * error information.  As reset is the final recovery action,
+-       * nothing is lost by doing this.
++       * Some controllers can't be frozen very well and may set spurious
++       * error conditions during reset.  Clear accumulated error
++       * information and re-thaw the port if frozen.  As reset is the
++       * final recovery action and we cross check link onlineness against
++       * device classification later, no hotplug event is lost by this.
+        */
+       spin_lock_irqsave(link->ap->lock, flags);
+       memset(&link->eh_info, 0, sizeof(link->eh_info));
+@@ -2814,6 +2815,9 @@ int ata_eh_reset(struct ata_link *link,
+       ap->pflags &= ~ATA_PFLAG_EH_PENDING;
+       spin_unlock_irqrestore(link->ap->lock, flags);
++      if (ap->pflags & ATA_PFLAG_FROZEN)
++              ata_eh_thaw_port(ap);
++
+       /*
+        * Make sure onlineness and classification result correspond.
+        * Hotplug could have happened during reset and some
diff --git a/queue-2.6.39/mm-compaction-abort-compaction-if-too-many-pages-are-isolated-and-caller-is-asynchronous-v2.patch b/queue-2.6.39/mm-compaction-abort-compaction-if-too-many-pages-are-isolated-and-caller-is-asynchronous-v2.patch
new file mode 100644 (file)
index 0000000..1f9abe6
--- /dev/null
@@ -0,0 +1,114 @@
+From mgorman@suse.de  Mon Aug  1 11:42:31 2011
+From: Mel Gorman <mgorman@suse.de>
+Date: Tue, 19 Jul 2011 10:15:51 +0100
+Subject: [stable] [PATCH 3/3] mm: compaction: abort compaction if too many pages are isolated and caller is asynchronous V2
+To: stable@kernel.org
+Cc: Andrea Arcangeli <aarcange@redhat.com>, Andrew Morton <akpm@linux-foundation.org>, Thomas Sattler <tsattler@gmx.de>, Mel Gorman <mgorman@suse.de>
+Message-ID: <1311066951-25546-4-git-send-email-mgorman@suse.de>
+
+From: Mel Gorman <mgorman@suse.de>
+
+commit: f9e35b3b41f47c4e17d8132edbcab305a6aaa4b0 upstream
+
+Asynchronous compaction is used when promoting to huge pages.  This is all
+very nice but if there are a number of processes in compacting memory, a
+large number of pages can be isolated.  An "asynchronous" process can
+stall for long periods of time as a result with a user reporting that
+firefox can stall for 10s of seconds.  This patch aborts asynchronous
+compaction if too many pages are isolated as it's better to fail a
+hugepage promotion than stall a process.
+
+[minchan.kim@gmail.com: return COMPACT_PARTIAL for abort]
+Reported-and-tested-by: Ury Stankevich <urykhy@gmail.com>
+Signed-off-by: Mel Gorman <mgorman@suse.de>
+Reviewed-by: Minchan Kim <minchan.kim@gmail.com>
+Reviewed-by: Michal Hocko <mhocko@suse.cz>
+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/compaction.c |   29 ++++++++++++++++++++++++-----
+ 1 file changed, 24 insertions(+), 5 deletions(-)
+
+--- a/mm/compaction.c
++++ b/mm/compaction.c
+@@ -251,11 +251,18 @@ static bool too_many_isolated(struct zon
+       return isolated > (inactive + active) / 2;
+ }
++/* possible outcome of isolate_migratepages */
++typedef enum {
++      ISOLATE_ABORT,          /* Abort compaction now */
++      ISOLATE_NONE,           /* No pages isolated, continue scanning */
++      ISOLATE_SUCCESS,        /* Pages isolated, migrate */
++} isolate_migrate_t;
++
+ /*
+  * Isolate all pages that can be migrated from the block pointed to by
+  * the migrate scanner within compact_control.
+  */
+-static unsigned long isolate_migratepages(struct zone *zone,
++static isolate_migrate_t isolate_migratepages(struct zone *zone,
+                                       struct compact_control *cc)
+ {
+       unsigned long low_pfn, end_pfn;
+@@ -272,7 +279,7 @@ static unsigned long isolate_migratepage
+       /* Do not cross the free scanner or scan within a memory hole */
+       if (end_pfn > cc->free_pfn || !pfn_valid(low_pfn)) {
+               cc->migrate_pfn = end_pfn;
+-              return 0;
++              return ISOLATE_NONE;
+       }
+       /*
+@@ -281,10 +288,14 @@ static unsigned long isolate_migratepage
+        * delay for some time until fewer pages are isolated
+        */
+       while (unlikely(too_many_isolated(zone))) {
++              /* async migration should just abort */
++              if (!cc->sync)
++                      return ISOLATE_ABORT;
++
+               congestion_wait(BLK_RW_ASYNC, HZ/10);
+               if (fatal_signal_pending(current))
+-                      return 0;
++                      return ISOLATE_ABORT;
+       }
+       /* Time to isolate some pages for migration */
+@@ -369,7 +380,7 @@ static unsigned long isolate_migratepage
+       trace_mm_compaction_isolate_migratepages(nr_scanned, nr_isolated);
+-      return cc->nr_migratepages;
++      return ISOLATE_SUCCESS;
+ }
+ /*
+@@ -533,8 +544,15 @@ static int compact_zone(struct zone *zon
+               unsigned long nr_migrate, nr_remaining;
+               int err;
+-              if (!isolate_migratepages(zone, cc))
++              switch (isolate_migratepages(zone, cc)) {
++              case ISOLATE_ABORT:
++                      ret = COMPACT_PARTIAL;
++                      goto out;
++              case ISOLATE_NONE:
+                       continue;
++              case ISOLATE_SUCCESS:
++                      ;
++              }
+               nr_migrate = cc->nr_migratepages;
+               err = migrate_pages(&cc->migratepages, compaction_alloc,
+@@ -558,6 +576,7 @@ static int compact_zone(struct zone *zon
+       }
++out:
+       /* Release free pages and check accounting */
+       cc->nr_freepages -= release_freepages(&cc->freepages);
+       VM_BUG_ON(cc->nr_freepages != 0);
diff --git a/queue-2.6.39/mm-compaction-ensure-that-the-compaction-free-scanner-does-not-move-to-the-next-zone.patch b/queue-2.6.39/mm-compaction-ensure-that-the-compaction-free-scanner-does-not-move-to-the-next-zone.patch
new file mode 100644 (file)
index 0000000..a4a70ba
--- /dev/null
@@ -0,0 +1,70 @@
+From mgorman@suse.de  Mon Aug  1 11:41:52 2011
+From: Mel Gorman <mgorman@suse.de>
+Date: Tue, 19 Jul 2011 10:15:49 +0100
+Subject: mm: compaction: ensure that the compaction free scanner does not move to the next zone
+To: stable@kernel.org
+Cc: Andrea Arcangeli <aarcange@redhat.com>, Andrew Morton <akpm@linux-foundation.org>, Thomas Sattler <tsattler@gmx.de>, Mel Gorman <mgorman@suse.de>
+Message-ID: <1311066951-25546-2-git-send-email-mgorman@suse.de>
+
+From: Mel Gorman <mgorman@suse.de>
+
+commit: 7454f4ba40b419eb999a3c61a99da662bf1a2bb8 upstream
+
+Compaction works with two scanners, a migration and a free scanner.  When
+the scanners crossover, migration within the zone is complete.  The
+location of the scanner is recorded on each cycle to avoid excesive
+scanning.
+
+When a zone is small and mostly reserved, it's very easy for the migration
+scanner to be close to the end of the zone.  Then the following situation
+can occurs
+
+  o migration scanner isolates some pages near the end of the zone
+  o free scanner starts at the end of the zone but finds that the
+    migration scanner is already there
+  o free scanner gets reinitialised for the next cycle as
+    cc->migrate_pfn + pageblock_nr_pages
+    moving the free scanner into the next zone
+  o migration scanner moves into the next zone
+
+When this happens, NR_ISOLATED accounting goes haywire because some of the
+accounting happens against the wrong zone.  One zones counter remains
+positive while the other goes negative even though the overall global
+count is accurate.  This was reported on X86-32 with !SMP because !SMP
+allows the negative counters to be visible.  The fact that it is the bug
+should theoritically be possible there.
+
+Signed-off-by: Mel Gorman <mgorman@suse.de>
+Reviewed-by: Minchan Kim <minchan.kim@gmail.com>
+Reviewed-by: Michal Hocko <mhocko@suse.cz>
+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/compaction.c |   13 ++++++++++++-
+ 1 file changed, 12 insertions(+), 1 deletion(-)
+
+--- a/mm/compaction.c
++++ b/mm/compaction.c
+@@ -144,9 +144,20 @@ static void isolate_freepages(struct zon
+       int nr_freepages = cc->nr_freepages;
+       struct list_head *freelist = &cc->freepages;
++      /*
++       * Initialise the free scanner. The starting point is where we last
++       * scanned from (or the end of the zone if starting). The low point
++       * is the end of the pageblock the migration scanner is using.
++       */
+       pfn = cc->free_pfn;
+       low_pfn = cc->migrate_pfn + pageblock_nr_pages;
+-      high_pfn = low_pfn;
++
++      /*
++       * Take care that if the migration scanner is at the end of the zone
++       * that the free scanner does not accidentally move to the next zone
++       * in the next isolation cycle.
++       */
++      high_pfn = min(low_pfn, pfn);
+       /*
+        * Isolate free pages until enough are available to migrate the
diff --git a/queue-2.6.39/mm-vmscan-do-not-apply-pressure-to-slab-if-we-are-not-applying-pressure-to-zone.patch b/queue-2.6.39/mm-vmscan-do-not-apply-pressure-to-slab-if-we-are-not-applying-pressure-to-zone.patch
new file mode 100644 (file)
index 0000000..2578abb
--- /dev/null
@@ -0,0 +1,85 @@
+From mgorman@suse.de  Mon Aug  1 11:50:25 2011
+From: Mel Gorman <mgorman@suse.de>
+Date: Mon, 11 Jul 2011 10:11:21 +0100
+Subject: mm: vmscan: do not apply pressure to slab if we are not applying pressure to zone
+To: stable@kernel.org
+Cc: mgorman@suse.de
+Message-ID: <1310375483-31999-3-git-send-email-mgorman@suse.de>
+
+From: Mel Gorman <mgorman@suse.de>
+
+commit d7868dae893c83c50c7824bc2bc75f93d114669f upstream
+
+During allocator-intensive workloads, kswapd will be woken frequently
+causing free memory to oscillate between the high and min watermark.  This
+is expected behaviour.
+
+When kswapd applies pressure to zones during node balancing, it checks if
+the zone is above a high+balance_gap threshold.  If it is, it does not
+apply pressure but it unconditionally shrinks slab on a global basis which
+is excessive.  In the event kswapd is being kept awake due to a high small
+unreclaimable zone, it skips zone shrinking but still calls shrink_slab().
+
+Once pressure has been applied, the check for zone being unreclaimable is
+being made before the check is made if all_unreclaimable should be set.
+This miss of unreclaimable can cause has_under_min_watermark_zone to be
+set due to an unreclaimable zone preventing kswapd backing off on
+congestion_wait().
+
+Signed-off-by: Mel Gorman <mgorman@suse.de>
+Reported-by: Pádraig Brady <P@draigBrady.com>
+Tested-by: Pádraig Brady <P@draigBrady.com>
+Tested-by: Andrew Lutomirski <luto@mit.edu>
+Acked-by: Rik van Riel <riel@redhat.com>
+Reviewed-by: Minchan Kim <minchan.kim@gmail.com>
+Reviewed-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
+Cc: Johannes Weiner <hannes@cmpxchg.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ mm/vmscan.c |   25 ++++++++++++++-----------
+ 1 file changed, 14 insertions(+), 11 deletions(-)
+
+--- a/mm/vmscan.c
++++ b/mm/vmscan.c
+@@ -2449,19 +2449,19 @@ loop_again:
+                               KSWAPD_ZONE_BALANCE_GAP_RATIO);
+                       if (!zone_watermark_ok_safe(zone, order,
+                                       high_wmark_pages(zone) + balance_gap,
+-                                      end_zone, 0))
++                                      end_zone, 0)) {
+                               shrink_zone(priority, zone, &sc);
+-                      reclaim_state->reclaimed_slab = 0;
+-                      nr_slab = shrink_slab(sc.nr_scanned, GFP_KERNEL,
+-                                              lru_pages);
+-                      sc.nr_reclaimed += reclaim_state->reclaimed_slab;
+-                      total_scanned += sc.nr_scanned;
+-                      if (zone->all_unreclaimable)
+-                              continue;
+-                      if (nr_slab == 0 &&
+-                          !zone_reclaimable(zone))
+-                              zone->all_unreclaimable = 1;
++                              reclaim_state->reclaimed_slab = 0;
++                              nr_slab = shrink_slab(sc.nr_scanned, GFP_KERNEL,
++                                                      lru_pages);
++                              sc.nr_reclaimed += reclaim_state->reclaimed_slab;
++                              total_scanned += sc.nr_scanned;
++
++                              if (nr_slab == 0 && !zone_reclaimable(zone))
++                                      zone->all_unreclaimable = 1;
++                      }
++
+                       /*
+                        * If we've done a decent amount of scanning and
+                        * the reclaim ratio is low, start doing writepage
+@@ -2471,6 +2471,9 @@ loop_again:
+                           total_scanned > sc.nr_reclaimed + sc.nr_reclaimed / 2)
+                               sc.may_writepage = 1;
++                      if (zone->all_unreclaimable)
++                              continue;
++
+                       if (!zone_watermark_ok_safe(zone, order,
+                                       high_wmark_pages(zone), end_zone, 0)) {
+                               all_zones_ok = 0;
diff --git a/queue-2.6.39/mm-vmscan-do-not-use-page_count-without-a-page-pin.patch b/queue-2.6.39/mm-vmscan-do-not-use-page_count-without-a-page-pin.patch
new file mode 100644 (file)
index 0000000..1a85b9e
--- /dev/null
@@ -0,0 +1,54 @@
+From mgorman@suse.de  Mon Aug  1 11:42:14 2011
+From: Mel Gorman <mgorman@suse.de>
+Date: Tue, 19 Jul 2011 10:15:50 +0100
+Subject: mm: vmscan: do not use page_count without a page pin
+To: stable@kernel.org
+Cc: Andrea Arcangeli <aarcange@redhat.com>, Andrew Morton <akpm@linux-foundation.org>, Thomas Sattler <tsattler@gmx.de>, Mel Gorman <mgorman@suse.de>
+Message-ID: <1311066951-25546-3-git-send-email-mgorman@suse.de>
+
+
+From: Andrea Arcangeli <aarcange@redhat.com>
+
+commit: d179e84ba5da1d0024087d1759a2938817a00f3f upstream
+
+It is unsafe to run page_count during the physical pfn scan because
+compound_head could trip on a dangling pointer when reading
+page->first_page if the compound page is being freed by another CPU.
+
+[mgorman@suse.de: split out patch]
+Signed-off-by: Andrea Arcangeli <aarcange@redhat.com>
+Signed-off-by: Mel Gorman <mgorman@suse.de>
+Reviewed-by: Michal Hocko <mhocko@suse.cz>
+Reviewed-by: Minchan Kim <minchan.kim@gmail.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/vmscan.c |   16 ++++++++++++++--
+ 1 file changed, 14 insertions(+), 2 deletions(-)
+
+--- a/mm/vmscan.c
++++ b/mm/vmscan.c
+@@ -1114,8 +1114,20 @@ static unsigned long isolate_lru_pages(u
+                                       nr_lumpy_dirty++;
+                               scan++;
+                       } else {
+-                              /* the page is freed already. */
+-                              if (!page_count(cursor_page))
++                              /*
++                               * Check if the page is freed already.
++                               *
++                               * We can't use page_count() as that
++                               * requires compound_head and we don't
++                               * have a pin on the page here. If a
++                               * page is tail, we may or may not
++                               * have isolated the head, so assume
++                               * it's not free, it'd be tricky to
++                               * track the head status without a
++                               * page pin.
++                               */
++                              if (!PageTail(cursor_page) &&
++                                  !atomic_read(&cursor_page->_count))
+                                       continue;
+                               break;
+                       }
diff --git a/queue-2.6.39/mm-vmscan-only-read-new_classzone_idx-from-pgdat-when-reclaiming-successfully.patch b/queue-2.6.39/mm-vmscan-only-read-new_classzone_idx-from-pgdat-when-reclaiming-successfully.patch
new file mode 100644 (file)
index 0000000..810b27f
--- /dev/null
@@ -0,0 +1,129 @@
+From mgorman@suse.de  Mon Aug  1 11:50:49 2011
+From: Mel Gorman <mgorman@suse.de>
+Date: Mon, 11 Jul 2011 10:11:23 +0100
+Subject: mm: vmscan: only read new_classzone_idx from pgdat when reclaiming successfully
+To: stable@kernel.org
+Cc: mgorman@suse.de
+Message-ID: <1310375483-31999-5-git-send-email-mgorman@suse.de>
+
+From: Mel Gorman <mgorman@suse.de>
+
+commit 215ddd6664ced067afca7eebd2d1eb83f064ff5a upstream
+
+During allocator-intensive workloads, kswapd will be woken frequently
+causing free memory to oscillate between the high and min watermark.  This
+is expected behaviour.  Unfortunately, if the highest zone is small, a
+problem occurs.
+
+When balance_pgdat() returns, it may be at a lower classzone_idx than it
+started because the highest zone was unreclaimable.  Before checking if it
+should go to sleep though, it checks pgdat->classzone_idx which when there
+is no other activity will be MAX_NR_ZONES-1.  It interprets this as it has
+been woken up while reclaiming, skips scheduling and reclaims again.  As
+there is no useful reclaim work to do, it enters into a loop of shrinking
+slab consuming loads of CPU until the highest zone becomes reclaimable for
+a long period of time.
+
+There are two problems here.  1) If the returned classzone or order is
+lower, it'll continue reclaiming without scheduling.  2) if the highest
+zone was marked unreclaimable but balance_pgdat() returns immediately at
+DEF_PRIORITY, the new lower classzone is not communicated back to kswapd()
+for sleeping.
+
+This patch does two things that are related.  If the end_zone is
+unreclaimable, this information is communicated back.  Second, if the
+classzone or order was reduced due to failing to reclaim, new information
+is not read from pgdat and instead an attempt is made to go to sleep.  Due
+to this, it is also necessary that pgdat->classzone_idx be initialised
+each time to pgdat->nr_zones - 1 to avoid re-reads being interpreted as
+wakeups.
+
+Signed-off-by: Mel Gorman <mgorman@suse.de>
+Reported-by: Pádraig Brady <P@draigBrady.com>
+Tested-by: Pádraig Brady <P@draigBrady.com>
+Tested-by: Andrew Lutomirski <luto@mit.edu>
+Acked-by: Rik van Riel <riel@redhat.com>
+Cc: Minchan Kim <minchan.kim@gmail.com>
+Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
+Cc: Johannes Weiner <hannes@cmpxchg.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ mm/vmscan.c |   34 +++++++++++++++++++++-------------
+ 1 file changed, 21 insertions(+), 13 deletions(-)
+
+--- a/mm/vmscan.c
++++ b/mm/vmscan.c
+@@ -2394,7 +2394,6 @@ loop_again:
+                       if (!zone_watermark_ok_safe(zone, order,
+                                       high_wmark_pages(zone), 0, 0)) {
+                               end_zone = i;
+-                              *classzone_idx = i;
+                               break;
+                       }
+               }
+@@ -2471,8 +2470,11 @@ loop_again:
+                           total_scanned > sc.nr_reclaimed + sc.nr_reclaimed / 2)
+                               sc.may_writepage = 1;
+-                      if (zone->all_unreclaimable)
++                      if (zone->all_unreclaimable) {
++                              if (end_zone && end_zone == i)
++                                      end_zone--;
+                               continue;
++                      }
+                       if (!zone_watermark_ok_safe(zone, order,
+                                       high_wmark_pages(zone), end_zone, 0)) {
+@@ -2652,8 +2654,8 @@ static void kswapd_try_to_sleep(pg_data_
+  */
+ static int kswapd(void *p)
+ {
+-      unsigned long order;
+-      int classzone_idx;
++      unsigned long order, new_order;
++      int classzone_idx, new_classzone_idx;
+       pg_data_t *pgdat = (pg_data_t*)p;
+       struct task_struct *tsk = current;
+@@ -2683,17 +2685,23 @@ static int kswapd(void *p)
+       tsk->flags |= PF_MEMALLOC | PF_SWAPWRITE | PF_KSWAPD;
+       set_freezable();
+-      order = 0;
+-      classzone_idx = MAX_NR_ZONES - 1;
++      order = new_order = 0;
++      classzone_idx = new_classzone_idx = pgdat->nr_zones - 1;
+       for ( ; ; ) {
+-              unsigned long new_order;
+-              int new_classzone_idx;
+               int ret;
+-              new_order = pgdat->kswapd_max_order;
+-              new_classzone_idx = pgdat->classzone_idx;
+-              pgdat->kswapd_max_order = 0;
+-              pgdat->classzone_idx = MAX_NR_ZONES - 1;
++              /*
++               * If the last balance_pgdat was unsuccessful it's unlikely a
++               * new request of a similar or harder type will succeed soon
++               * so consider going to sleep on the basis we reclaimed at
++               */
++              if (classzone_idx >= new_classzone_idx && order == new_order) {
++                      new_order = pgdat->kswapd_max_order;
++                      new_classzone_idx = pgdat->classzone_idx;
++                      pgdat->kswapd_max_order =  0;
++                      pgdat->classzone_idx = pgdat->nr_zones - 1;
++              }
++
+               if (order < new_order || classzone_idx > new_classzone_idx) {
+                       /*
+                        * Don't sleep if someone wants a larger 'order'
+@@ -2706,7 +2714,7 @@ static int kswapd(void *p)
+                       order = pgdat->kswapd_max_order;
+                       classzone_idx = pgdat->classzone_idx;
+                       pgdat->kswapd_max_order = 0;
+-                      pgdat->classzone_idx = MAX_NR_ZONES - 1;
++                      pgdat->classzone_idx = pgdat->nr_zones - 1;
+               }
+               ret = try_to_freeze();
diff --git a/queue-2.6.39/revert-dibxxxx-get-rid-of-dma-buffer-on-stack.patch b/queue-2.6.39/revert-dibxxxx-get-rid-of-dma-buffer-on-stack.patch
new file mode 100644 (file)
index 0000000..6e858ab
--- /dev/null
@@ -0,0 +1,1185 @@
+From e4f708b85622e2bbc25e6ae1e05bf0eed4d3e29e Mon Sep 17 00:00:00 2001
+From: Greg Kroah-Hartman <gregkh@suse.de>
+Date: Mon, 1 Aug 2011 11:53:11 -0700
+Subject: Revert "DiBxxxx: get rid of DMA buffer on stack"
+
+This reverts commit 673de951a6cbaa7a9c4518e03e78b88809828497 which was
+commit 5a0deeed5741117ee8625d6305d0034e219f102c upstream.
+
+Based on comments from users, this broke things.
+
+Acked-by: Olivier Grenie <Olivier.Grenie@dibcom.com>
+Cc: Florian Mickler <florian@mickler.org>
+Cc: Patrick Boettcher <patrick.boettcher@dibcom.fr>
+Cc: Mauro Carvalho Chehab <mchehab@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ drivers/media/dvb/frontends/dib0070.c        |   40 +-----
+ drivers/media/dvb/frontends/dib0090.c        |   71 ++---------
+ drivers/media/dvb/frontends/dib7000m.c       |   47 ++-----
+ drivers/media/dvb/frontends/dib7000p.c       |   72 +++--------
+ drivers/media/dvb/frontends/dib8000.c        |  126 +++++--------------
+ drivers/media/dvb/frontends/dib9000.c        |  172 +++++++++------------------
+ drivers/media/dvb/frontends/dibx000_common.c |  113 +++++++----------
+ drivers/media/dvb/frontends/dibx000_common.h |    5 
+ 8 files changed, 202 insertions(+), 444 deletions(-)
+
+--- a/drivers/media/dvb/frontends/dib0070.c
++++ b/drivers/media/dvb/frontends/dib0070.c
+@@ -73,47 +73,27 @@ struct dib0070_state {
+     u8  wbd_gain_current;
+       u16 wbd_offset_3_3[2];
+-
+-      /* for the I2C transfer */
+-      struct i2c_msg msg[2];
+-      u8 i2c_write_buffer[3];
+-      u8 i2c_read_buffer[2];
+ };
+ static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg)
+ {
+-      state->i2c_write_buffer[0] = reg;
+-
+-      memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
+-      state->msg[0].addr = state->cfg->i2c_address;
+-      state->msg[0].flags = 0;
+-      state->msg[0].buf = state->i2c_write_buffer;
+-      state->msg[0].len = 1;
+-      state->msg[1].addr = state->cfg->i2c_address;
+-      state->msg[1].flags = I2C_M_RD;
+-      state->msg[1].buf = state->i2c_read_buffer;
+-      state->msg[1].len = 2;
+-
+-      if (i2c_transfer(state->i2c, state->msg, 2) != 2) {
++      u8 b[2];
++      struct i2c_msg msg[2] = {
++              { .addr = state->cfg->i2c_address, .flags = 0,        .buf = &reg, .len = 1 },
++              { .addr = state->cfg->i2c_address, .flags = I2C_M_RD, .buf = b,  .len = 2 },
++      };
++      if (i2c_transfer(state->i2c, msg, 2) != 2) {
+               printk(KERN_WARNING "DiB0070 I2C read failed\n");
+               return 0;
+       }
+-      return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
++      return (b[0] << 8) | b[1];
+ }
+ static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val)
+ {
+-      state->i2c_write_buffer[0] = reg;
+-      state->i2c_write_buffer[1] = val >> 8;
+-      state->i2c_write_buffer[2] = val & 0xff;
+-
+-      memset(state->msg, 0, sizeof(struct i2c_msg));
+-      state->msg[0].addr = state->cfg->i2c_address;
+-      state->msg[0].flags = 0;
+-      state->msg[0].buf = state->i2c_write_buffer;
+-      state->msg[0].len = 3;
+-
+-      if (i2c_transfer(state->i2c, state->msg, 1) != 1) {
++      u8 b[3] = { reg, val >> 8, val & 0xff };
++      struct i2c_msg msg = { .addr = state->cfg->i2c_address, .flags = 0, .buf = b, .len = 3 };
++      if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+               printk(KERN_WARNING "DiB0070 I2C write failed\n");
+               return -EREMOTEIO;
+       }
+--- a/drivers/media/dvb/frontends/dib0090.c
++++ b/drivers/media/dvb/frontends/dib0090.c
+@@ -191,11 +191,6 @@ struct dib0090_state {
+       u8 wbd_calibration_gain;
+       const struct dib0090_wbd_slope *current_wbd_table;
+       u16 wbdmux;
+-
+-      /* for the I2C transfer */
+-      struct i2c_msg msg[2];
+-      u8 i2c_write_buffer[3];
+-      u8 i2c_read_buffer[2];
+ };
+ struct dib0090_fw_state {
+@@ -203,48 +198,27 @@ struct dib0090_fw_state {
+       struct dvb_frontend *fe;
+       struct dib0090_identity identity;
+       const struct dib0090_config *config;
+-
+-      /* for the I2C transfer */
+-      struct i2c_msg msg;
+-      u8 i2c_write_buffer[2];
+-      u8 i2c_read_buffer[2];
+ };
+ static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg)
+ {
+-      state->i2c_write_buffer[0] = reg;
+-
+-      memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
+-      state->msg[0].addr = state->config->i2c_address;
+-      state->msg[0].flags = 0;
+-      state->msg[0].buf = state->i2c_write_buffer;
+-      state->msg[0].len = 1;
+-      state->msg[1].addr = state->config->i2c_address;
+-      state->msg[1].flags = I2C_M_RD;
+-      state->msg[1].buf = state->i2c_read_buffer;
+-      state->msg[1].len = 2;
+-
+-      if (i2c_transfer(state->i2c, state->msg, 2) != 2) {
++      u8 b[2];
++      struct i2c_msg msg[2] = {
++              {.addr = state->config->i2c_address, .flags = 0, .buf = &reg, .len = 1},
++              {.addr = state->config->i2c_address, .flags = I2C_M_RD, .buf = b, .len = 2},
++      };
++      if (i2c_transfer(state->i2c, msg, 2) != 2) {
+               printk(KERN_WARNING "DiB0090 I2C read failed\n");
+               return 0;
+       }
+-
+-      return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
++      return (b[0] << 8) | b[1];
+ }
+ static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val)
+ {
+-      state->i2c_write_buffer[0] = reg & 0xff;
+-      state->i2c_write_buffer[1] = val >> 8;
+-      state->i2c_write_buffer[2] = val & 0xff;
+-
+-      memset(state->msg, 0, sizeof(struct i2c_msg));
+-      state->msg[0].addr = state->config->i2c_address;
+-      state->msg[0].flags = 0;
+-      state->msg[0].buf = state->i2c_write_buffer;
+-      state->msg[0].len = 3;
+-
+-      if (i2c_transfer(state->i2c, state->msg, 1) != 1) {
++      u8 b[3] = { reg & 0xff, val >> 8, val & 0xff };
++      struct i2c_msg msg = {.addr = state->config->i2c_address, .flags = 0, .buf = b, .len = 3 };
++      if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+               printk(KERN_WARNING "DiB0090 I2C write failed\n");
+               return -EREMOTEIO;
+       }
+@@ -253,31 +227,20 @@ static int dib0090_write_reg(struct dib0
+ static u16 dib0090_fw_read_reg(struct dib0090_fw_state *state, u8 reg)
+ {
+-      state->i2c_write_buffer[0] = reg;
+-
+-      memset(&state->msg, 0, sizeof(struct i2c_msg));
+-      state->msg.addr = reg;
+-      state->msg.flags = I2C_M_RD;
+-      state->msg.buf = state->i2c_read_buffer;
+-      state->msg.len = 2;
+-      if (i2c_transfer(state->i2c, &state->msg, 1) != 1) {
++      u8 b[2];
++      struct i2c_msg msg = {.addr = reg, .flags = I2C_M_RD, .buf = b, .len = 2 };
++      if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+               printk(KERN_WARNING "DiB0090 I2C read failed\n");
+               return 0;
+       }
+-      return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
++      return (b[0] << 8) | b[1];
+ }
+ static int dib0090_fw_write_reg(struct dib0090_fw_state *state, u8 reg, u16 val)
+ {
+-      state->i2c_write_buffer[0] = val >> 8;
+-      state->i2c_write_buffer[1] = val & 0xff;
+-
+-      memset(&state->msg, 0, sizeof(struct i2c_msg));
+-      state->msg.addr = reg;
+-      state->msg.flags = 0;
+-      state->msg.buf = state->i2c_write_buffer;
+-      state->msg.len = 2;
+-      if (i2c_transfer(state->i2c, &state->msg, 1) != 1) {
++      u8 b[2] = { val >> 8, val & 0xff };
++      struct i2c_msg msg = {.addr = reg, .flags = 0, .buf = b, .len = 2 };
++      if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+               printk(KERN_WARNING "DiB0090 I2C write failed\n");
+               return -EREMOTEIO;
+       }
+--- a/drivers/media/dvb/frontends/dib7000m.c
++++ b/drivers/media/dvb/frontends/dib7000m.c
+@@ -50,11 +50,6 @@ struct dib7000m_state {
+       u16 revision;
+       u8 agc_state;
+-
+-      /* for the I2C transfer */
+-      struct i2c_msg msg[2];
+-      u8 i2c_write_buffer[4];
+-      u8 i2c_read_buffer[2];
+ };
+ enum dib7000m_power_mode {
+@@ -69,39 +64,29 @@ enum dib7000m_power_mode {
+ static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg)
+ {
+-      state->i2c_write_buffer[0] = (reg >> 8) | 0x80;
+-      state->i2c_write_buffer[1] = reg & 0xff;
+-
+-      memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
+-      state->msg[0].addr = state->i2c_addr >> 1;
+-      state->msg[0].flags = 0;
+-      state->msg[0].buf = state->i2c_write_buffer;
+-      state->msg[0].len = 2;
+-      state->msg[1].addr = state->i2c_addr >> 1;
+-      state->msg[1].flags = I2C_M_RD;
+-      state->msg[1].buf = state->i2c_read_buffer;
+-      state->msg[1].len = 2;
++      u8 wb[2] = { (reg >> 8) | 0x80, reg & 0xff };
++      u8 rb[2];
++      struct i2c_msg msg[2] = {
++              { .addr = state->i2c_addr >> 1, .flags = 0,        .buf = wb, .len = 2 },
++              { .addr = state->i2c_addr >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2 },
++      };
+-      if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
++      if (i2c_transfer(state->i2c_adap, msg, 2) != 2)
+               dprintk("i2c read error on %d",reg);
+-      return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
++      return (rb[0] << 8) | rb[1];
+ }
+ static int dib7000m_write_word(struct dib7000m_state *state, u16 reg, u16 val)
+ {
+-      state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
+-      state->i2c_write_buffer[1] = reg & 0xff;
+-      state->i2c_write_buffer[2] = (val >> 8) & 0xff;
+-      state->i2c_write_buffer[3] = val & 0xff;
+-
+-      memset(&state->msg[0], 0, sizeof(struct i2c_msg));
+-      state->msg[0].addr = state->i2c_addr >> 1;
+-      state->msg[0].flags = 0;
+-      state->msg[0].buf = state->i2c_write_buffer;
+-      state->msg[0].len = 4;
+-
+-      return i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0;
++      u8 b[4] = {
++              (reg >> 8) & 0xff, reg & 0xff,
++              (val >> 8) & 0xff, val & 0xff,
++      };
++      struct i2c_msg msg = {
++              .addr = state->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4
++      };
++      return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
+ }
+ static void dib7000m_write_tab(struct dib7000m_state *state, u16 *buf)
+ {
+--- a/drivers/media/dvb/frontends/dib7000p.c
++++ b/drivers/media/dvb/frontends/dib7000p.c
+@@ -63,11 +63,6 @@ struct dib7000p_state {
+       u16 tuner_enable;
+       struct i2c_adapter dib7090_tuner_adap;
+-
+-      /* for the I2C transfer */
+-      struct i2c_msg msg[2];
+-      u8 i2c_write_buffer[4];
+-      u8 i2c_read_buffer[2];
+ };
+ enum dib7000p_power_mode {
+@@ -81,39 +76,29 @@ static int dib7090_set_diversity_in(stru
+ static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg)
+ {
+-      state->i2c_write_buffer[0] = reg >> 8;
+-      state->i2c_write_buffer[1] = reg & 0xff;
+-
+-      memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
+-      state->msg[0].addr = state->i2c_addr >> 1;
+-      state->msg[0].flags = 0;
+-      state->msg[0].buf = state->i2c_write_buffer;
+-      state->msg[0].len = 2;
+-      state->msg[1].addr = state->i2c_addr >> 1;
+-      state->msg[1].flags = I2C_M_RD;
+-      state->msg[1].buf = state->i2c_read_buffer;
+-      state->msg[1].len = 2;
++      u8 wb[2] = { reg >> 8, reg & 0xff };
++      u8 rb[2];
++      struct i2c_msg msg[2] = {
++              {.addr = state->i2c_addr >> 1, .flags = 0, .buf = wb, .len = 2},
++              {.addr = state->i2c_addr >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2},
++      };
+-      if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
++      if (i2c_transfer(state->i2c_adap, msg, 2) != 2)
+               dprintk("i2c read error on %d", reg);
+-      return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
++      return (rb[0] << 8) | rb[1];
+ }
+ static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val)
+ {
+-      state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
+-      state->i2c_write_buffer[1] = reg & 0xff;
+-      state->i2c_write_buffer[2] = (val >> 8) & 0xff;
+-      state->i2c_write_buffer[3] = val & 0xff;
+-
+-      memset(&state->msg[0], 0, sizeof(struct i2c_msg));
+-      state->msg[0].addr = state->i2c_addr >> 1;
+-      state->msg[0].flags = 0;
+-      state->msg[0].buf = state->i2c_write_buffer;
+-      state->msg[0].len = 4;
+-
+-      return i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0;
++      u8 b[4] = {
++              (reg >> 8) & 0xff, reg & 0xff,
++              (val >> 8) & 0xff, val & 0xff,
++      };
++      struct i2c_msg msg = {
++              .addr = state->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4
++      };
++      return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
+ }
+ static void dib7000p_write_tab(struct dib7000p_state *state, u16 * buf)
+@@ -1565,24 +1550,11 @@ static void dib7000p_release(struct dvb_
+ int dib7000pc_detection(struct i2c_adapter *i2c_adap)
+ {
+-      u8 *tx, *rx;
++      u8 tx[2], rx[2];
+       struct i2c_msg msg[2] = {
+-              {.addr = 18 >> 1, .flags = 0, .len = 2},
+-              {.addr = 18 >> 1, .flags = I2C_M_RD, .len = 2},
++              {.addr = 18 >> 1, .flags = 0, .buf = tx, .len = 2},
++              {.addr = 18 >> 1, .flags = I2C_M_RD, .buf = rx, .len = 2},
+       };
+-      int ret = 0;
+-
+-      tx = kzalloc(2*sizeof(u8), GFP_KERNEL);
+-      if (!tx)
+-              return -ENOMEM;
+-      rx = kzalloc(2*sizeof(u8), GFP_KERNEL);
+-      if (!rx) {
+-              goto rx_memory_error;
+-              ret = -ENOMEM;
+-      }
+-
+-      msg[0].buf = tx;
+-      msg[1].buf = rx;
+       tx[0] = 0x03;
+       tx[1] = 0x00;
+@@ -1602,11 +1574,7 @@ int dib7000pc_detection(struct i2c_adapt
+               }
+       dprintk("-D-  DiB7000PC not detected");
+-
+-      kfree(rx);
+-rx_memory_error:
+-      kfree(tx);
+-      return ret;
++      return 0;
+ }
+ EXPORT_SYMBOL(dib7000pc_detection);
+--- a/drivers/media/dvb/frontends/dib8000.c
++++ b/drivers/media/dvb/frontends/dib8000.c
+@@ -35,8 +35,6 @@ MODULE_PARM_DESC(debug, "turn on debuggi
+ struct i2c_device {
+       struct i2c_adapter *adap;
+       u8 addr;
+-      u8 *i2c_write_buffer;
+-      u8 *i2c_read_buffer;
+ };
+ struct dib8000_state {
+@@ -72,11 +70,6 @@ struct dib8000_state {
+       u32 status;
+       struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS];
+-
+-      /* for the I2C transfer */
+-      struct i2c_msg msg[2];
+-      u8 i2c_write_buffer[4];
+-      u8 i2c_read_buffer[2];
+ };
+ enum dib8000_power_mode {
+@@ -86,41 +79,22 @@ enum dib8000_power_mode {
+ static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg)
+ {
++      u8 wb[2] = { reg >> 8, reg & 0xff };
++      u8 rb[2];
+       struct i2c_msg msg[2] = {
+-              {.addr = i2c->addr >> 1, .flags = 0,
+-                      .buf = i2c->i2c_write_buffer, .len = 2},
+-              {.addr = i2c->addr >> 1, .flags = I2C_M_RD,
+-                      .buf = i2c->i2c_read_buffer, .len = 2},
++              {.addr = i2c->addr >> 1,.flags = 0,.buf = wb,.len = 2},
++              {.addr = i2c->addr >> 1,.flags = I2C_M_RD,.buf = rb,.len = 2},
+       };
+-      msg[0].buf[0] = reg >> 8;
+-      msg[0].buf[1] = reg & 0xff;
+-
+       if (i2c_transfer(i2c->adap, msg, 2) != 2)
+               dprintk("i2c read error on %d", reg);
+-      return (msg[1].buf[0] << 8) | msg[1].buf[1];
++      return (rb[0] << 8) | rb[1];
+ }
+ static u16 dib8000_read_word(struct dib8000_state *state, u16 reg)
+ {
+-      state->i2c_write_buffer[0] = reg >> 8;
+-      state->i2c_write_buffer[1] = reg & 0xff;
+-
+-      memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
+-      state->msg[0].addr = state->i2c.addr >> 1;
+-      state->msg[0].flags = 0;
+-      state->msg[0].buf = state->i2c_write_buffer;
+-      state->msg[0].len = 2;
+-      state->msg[1].addr = state->i2c.addr >> 1;
+-      state->msg[1].flags = I2C_M_RD;
+-      state->msg[1].buf = state->i2c_read_buffer;
+-      state->msg[1].len = 2;
+-
+-      if (i2c_transfer(state->i2c.adap, state->msg, 2) != 2)
+-              dprintk("i2c read error on %d", reg);
+-
+-      return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
++      return dib8000_i2c_read16(&state->i2c, reg);
+ }
+ static u32 dib8000_read32(struct dib8000_state *state, u16 reg)
+@@ -135,34 +109,19 @@ static u32 dib8000_read32(struct dib8000
+ static int dib8000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val)
+ {
+-      struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0,
+-              .buf = i2c->i2c_write_buffer, .len = 4};
+-      int ret = 0;
+-
+-      msg.buf[0] = (reg >> 8) & 0xff;
+-      msg.buf[1] = reg & 0xff;
+-      msg.buf[2] = (val >> 8) & 0xff;
+-      msg.buf[3] = val & 0xff;
+-
+-      ret = i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
+-
+-      return ret;
++      u8 b[4] = {
++              (reg >> 8) & 0xff, reg & 0xff,
++              (val >> 8) & 0xff, val & 0xff,
++      };
++      struct i2c_msg msg = {
++              .addr = i2c->addr >> 1,.flags = 0,.buf = b,.len = 4
++      };
++      return i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
+ }
+ static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val)
+ {
+-      state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
+-      state->i2c_write_buffer[1] = reg & 0xff;
+-      state->i2c_write_buffer[2] = (val >> 8) & 0xff;
+-      state->i2c_write_buffer[3] = val & 0xff;
+-
+-      memset(&state->msg[0], 0, sizeof(struct i2c_msg));
+-      state->msg[0].addr = state->i2c.addr >> 1;
+-      state->msg[0].flags = 0;
+-      state->msg[0].buf = state->i2c_write_buffer;
+-      state->msg[0].len = 4;
+-
+-      return i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ? -EREMOTEIO : 0;
++      return dib8000_i2c_write16(&state->i2c, reg, val);
+ }
+ static const s16 coeff_2k_sb_1seg_dqpsk[8] = {
+@@ -1021,31 +980,30 @@ static void dib8000_update_timf(struct d
+       dprintk("Updated timing frequency: %d (default: %d)", state->timf, state->timf_default);
+ }
+-static const u16 adc_target_16dB[11] = {
+-      (1 << 13) - 825 - 117,
+-      (1 << 13) - 837 - 117,
+-      (1 << 13) - 811 - 117,
+-      (1 << 13) - 766 - 117,
+-      (1 << 13) - 737 - 117,
+-      (1 << 13) - 693 - 117,
+-      (1 << 13) - 648 - 117,
+-      (1 << 13) - 619 - 117,
+-      (1 << 13) - 575 - 117,
+-      (1 << 13) - 531 - 117,
+-      (1 << 13) - 501 - 117
+-};
+-static const u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 };
+-
+ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosearching)
+ {
+       u16 mode, max_constellation, seg_diff_mask = 0, nbseg_diff = 0;
+       u8 guard, crate, constellation, timeI;
++      u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 };
+       u16 i, coeff[4], P_cfr_left_edge = 0, P_cfr_right_edge = 0, seg_mask13 = 0x1fff;        // All 13 segments enabled
+       const s16 *ncoeff = NULL, *ana_fe;
+       u16 tmcc_pow = 0;
+       u16 coff_pow = 0x2800;
+       u16 init_prbs = 0xfff;
+       u16 ana_gain = 0;
++      u16 adc_target_16dB[11] = {
++              (1 << 13) - 825 - 117,
++              (1 << 13) - 837 - 117,
++              (1 << 13) - 811 - 117,
++              (1 << 13) - 766 - 117,
++              (1 << 13) - 737 - 117,
++              (1 << 13) - 693 - 117,
++              (1 << 13) - 648 - 117,
++              (1 << 13) - 619 - 117,
++              (1 << 13) - 575 - 117,
++              (1 << 13) - 531 - 117,
++              (1 << 13) - 501 - 117
++      };
+       if (state->ber_monitored_layer != LAYER_ALL)
+               dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & 0x60) | state->ber_monitored_layer);
+@@ -2421,22 +2379,10 @@ EXPORT_SYMBOL(dib8000_get_slave_frontend
+ int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr)
+ {
+-      int k = 0, ret = 0;
++      int k = 0;
+       u8 new_addr = 0;
+       struct i2c_device client = {.adap = host };
+-      client.i2c_write_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
+-      if (!client.i2c_write_buffer) {
+-              dprintk("%s: not enough memory", __func__);
+-              return -ENOMEM;
+-      }
+-      client.i2c_read_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
+-      if (!client.i2c_read_buffer) {
+-              dprintk("%s: not enough memory", __func__);
+-              ret = -ENOMEM;
+-              goto error_memory;
+-      }
+-
+       for (k = no_of_demods - 1; k >= 0; k--) {
+               /* designated i2c address */
+               new_addr = first_addr + (k << 1);
+@@ -2448,8 +2394,7 @@ int dib8000_i2c_enumeration(struct i2c_a
+                       client.addr = default_addr;
+                       if (dib8000_identify(&client) == 0) {
+                               dprintk("#%d: not identified", k);
+-                              ret  = -EINVAL;
+-                              goto error;
++                              return -EINVAL;
+                       }
+               }
+@@ -2475,12 +2420,7 @@ int dib8000_i2c_enumeration(struct i2c_a
+               dib8000_i2c_write16(&client, 1286, 0);
+       }
+-error:
+-      kfree(client.i2c_read_buffer);
+-error_memory:
+-      kfree(client.i2c_write_buffer);
+-
+-      return ret;
++      return 0;
+ }
+ EXPORT_SYMBOL(dib8000_i2c_enumeration);
+@@ -2579,8 +2519,6 @@ struct dvb_frontend *dib8000_attach(stru
+       memcpy(&state->cfg, cfg, sizeof(struct dib8000_config));
+       state->i2c.adap = i2c_adap;
+       state->i2c.addr = i2c_addr;
+-      state->i2c.i2c_write_buffer = state->i2c_write_buffer;
+-      state->i2c.i2c_read_buffer = state->i2c_read_buffer;
+       state->gpio_val = cfg->gpio_val;
+       state->gpio_dir = cfg->gpio_dir;
+--- a/drivers/media/dvb/frontends/dib9000.c
++++ b/drivers/media/dvb/frontends/dib9000.c
+@@ -27,8 +27,6 @@ MODULE_PARM_DESC(debug, "turn on debuggi
+ struct i2c_device {
+       struct i2c_adapter *i2c_adap;
+       u8 i2c_addr;
+-      u8 *i2c_read_buffer;
+-      u8 *i2c_write_buffer;
+ };
+ /* lock */
+@@ -94,16 +92,11 @@ struct dib9000_state {
+       struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS];
+       u16 component_bus_speed;
+-
+-      /* for the I2C transfer */
+-      struct i2c_msg msg[2];
+-      u8 i2c_write_buffer[255];
+-      u8 i2c_read_buffer[255];
+ };
+-static const u32 fe_info[44] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++u32 fe_info[44] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+-      0, 0, 0, 0, 0, 0, 0, 0
++      0, 0, 0
+ };
+ enum dib9000_power_mode {
+@@ -224,33 +217,25 @@ static u16 dib9000_read16_attr(struct di
+       u32 chunk_size = 126;
+       u32 l;
+       int ret;
++      u8 wb[2] = { reg >> 8, reg & 0xff };
++      struct i2c_msg msg[2] = {
++              {.addr = state->i2c.i2c_addr >> 1, .flags = 0, .buf = wb, .len = 2},
++              {.addr = state->i2c.i2c_addr >> 1, .flags = I2C_M_RD, .buf = b, .len = len},
++      };
+       if (state->platform.risc.fw_is_running && (reg < 1024))
+               return dib9000_risc_apb_access_read(state, reg, attribute, NULL, 0, b, len);
+-      memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
+-      state->msg[0].addr = state->i2c.i2c_addr >> 1;
+-      state->msg[0].flags = 0;
+-      state->msg[0].buf = state->i2c_write_buffer;
+-      state->msg[0].len = 2;
+-      state->msg[1].addr = state->i2c.i2c_addr >> 1;
+-      state->msg[1].flags = I2C_M_RD;
+-      state->msg[1].buf = b;
+-      state->msg[1].len = len;
+-
+-      state->i2c_write_buffer[0] = reg >> 8;
+-      state->i2c_write_buffer[1] = reg & 0xff;
+-
+       if (attribute & DATA_BUS_ACCESS_MODE_8BIT)
+-              state->i2c_write_buffer[0] |= (1 << 5);
++              wb[0] |= (1 << 5);
+       if (attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)
+-              state->i2c_write_buffer[0] |= (1 << 4);
++              wb[0] |= (1 << 4);
+       do {
+               l = len < chunk_size ? len : chunk_size;
+-              state->msg[1].len = l;
+-              state->msg[1].buf = b;
+-              ret = i2c_transfer(state->i2c.i2c_adap, state->msg, 2) != 2 ? -EREMOTEIO : 0;
++              msg[1].len = l;
++              msg[1].buf = b;
++              ret = i2c_transfer(state->i2c.i2c_adap, msg, 2) != 2 ? -EREMOTEIO : 0;
+               if (ret != 0) {
+                       dprintk("i2c read error on %d", reg);
+                       return -EREMOTEIO;
+@@ -268,47 +253,50 @@ static u16 dib9000_read16_attr(struct di
+ static u16 dib9000_i2c_read16(struct i2c_device *i2c, u16 reg)
+ {
++      u8 b[2];
++      u8 wb[2] = { reg >> 8, reg & 0xff };
+       struct i2c_msg msg[2] = {
+-              {.addr = i2c->i2c_addr >> 1, .flags = 0,
+-                      .buf = i2c->i2c_write_buffer, .len = 2},
+-              {.addr = i2c->i2c_addr >> 1, .flags = I2C_M_RD,
+-                      .buf = i2c->i2c_read_buffer, .len = 2},
++              {.addr = i2c->i2c_addr >> 1, .flags = 0, .buf = wb, .len = 2},
++              {.addr = i2c->i2c_addr >> 1, .flags = I2C_M_RD, .buf = b, .len = 2},
+       };
+-      i2c->i2c_write_buffer[0] = reg >> 8;
+-      i2c->i2c_write_buffer[1] = reg & 0xff;
+-
+       if (i2c_transfer(i2c->i2c_adap, msg, 2) != 2) {
+               dprintk("read register %x error", reg);
+               return 0;
+       }
+-      return (i2c->i2c_read_buffer[0] << 8) | i2c->i2c_read_buffer[1];
++      return (b[0] << 8) | b[1];
+ }
+ static inline u16 dib9000_read_word(struct dib9000_state *state, u16 reg)
+ {
+-      if (dib9000_read16_attr(state, reg, state->i2c_read_buffer, 2, 0) != 0)
++      u8 b[2];
++      if (dib9000_read16_attr(state, reg, b, 2, 0) != 0)
+               return 0;
+-      return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
++      return (b[0] << 8 | b[1]);
+ }
+ static inline u16 dib9000_read_word_attr(struct dib9000_state *state, u16 reg, u16 attribute)
+ {
+-      if (dib9000_read16_attr(state, reg, state->i2c_read_buffer, 2,
+-                              attribute) != 0)
++      u8 b[2];
++      if (dib9000_read16_attr(state, reg, b, 2, attribute) != 0)
+               return 0;
+-      return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
++      return (b[0] << 8 | b[1]);
+ }
+ #define dib9000_read16_noinc_attr(state, reg, b, len, attribute) dib9000_read16_attr(state, reg, b, len, (attribute) | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)
+ static u16 dib9000_write16_attr(struct dib9000_state *state, u16 reg, const u8 * buf, u32 len, u16 attribute)
+ {
++      u8 b[255];
+       u32 chunk_size = 126;
+       u32 l;
+       int ret;
++      struct i2c_msg msg = {
++              .addr = state->i2c.i2c_addr >> 1, .flags = 0, .buf = b, .len = len + 2
++      };
++
+       if (state->platform.risc.fw_is_running && (reg < 1024)) {
+               if (dib9000_risc_apb_access_write
+                   (state, reg, DATA_BUS_ACCESS_MODE_16BIT | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT | attribute, buf, len) != 0)
+@@ -316,26 +304,20 @@ static u16 dib9000_write16_attr(struct d
+               return 0;
+       }
+-      memset(&state->msg[0], 0, sizeof(struct i2c_msg));
+-      state->msg[0].addr = state->i2c.i2c_addr >> 1;
+-      state->msg[0].flags = 0;
+-      state->msg[0].buf = state->i2c_write_buffer;
+-      state->msg[0].len = len + 2;
+-
+-      state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
+-      state->i2c_write_buffer[1] = (reg) & 0xff;
++      b[0] = (reg >> 8) & 0xff;
++      b[1] = (reg) & 0xff;
+       if (attribute & DATA_BUS_ACCESS_MODE_8BIT)
+-              state->i2c_write_buffer[0] |= (1 << 5);
++              b[0] |= (1 << 5);
+       if (attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)
+-              state->i2c_write_buffer[0] |= (1 << 4);
++              b[0] |= (1 << 4);
+       do {
+               l = len < chunk_size ? len : chunk_size;
+-              state->msg[0].len = l + 2;
+-              memcpy(&state->i2c_write_buffer[2], buf, l);
++              msg.len = l + 2;
++              memcpy(&b[2], buf, l);
+-              ret = i2c_transfer(state->i2c.i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0;
++              ret = i2c_transfer(state->i2c.i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
+               buf += l;
+               len -= l;
+@@ -349,16 +331,11 @@ static u16 dib9000_write16_attr(struct d
+ static int dib9000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val)
+ {
++      u8 b[4] = { (reg >> 8) & 0xff, reg & 0xff, (val >> 8) & 0xff, val & 0xff };
+       struct i2c_msg msg = {
+-              .addr = i2c->i2c_addr >> 1, .flags = 0,
+-              .buf = i2c->i2c_write_buffer, .len = 4
++              .addr = i2c->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4
+       };
+-      i2c->i2c_write_buffer[0] = (reg >> 8) & 0xff;
+-      i2c->i2c_write_buffer[1] = reg & 0xff;
+-      i2c->i2c_write_buffer[2] = (val >> 8) & 0xff;
+-      i2c->i2c_write_buffer[3] = val & 0xff;
+-
+       return i2c_transfer(i2c->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
+ }
+@@ -1038,8 +1015,8 @@ static int dib9000_fw_memmbx_sync(struct
+               return 0;
+       dib9000_risc_mem_write(state, FE_MM_RW_SYNC, &i);
+       do {
+-              dib9000_risc_mem_read(state, FE_MM_RW_SYNC, state->i2c_read_buffer, 1);
+-      } while (state->i2c_read_buffer[0] && index_loop--);
++              dib9000_risc_mem_read(state, FE_MM_RW_SYNC, &i, 1);
++      } while (i && index_loop--);
+       if (index_loop > 0)
+               return 0;
+@@ -1162,7 +1139,7 @@ static int dib9000_fw_get_channel(struct
+               s8 intlv_native;
+       };
+-      struct dibDVBTChannel *ch;
++      struct dibDVBTChannel ch;
+       int ret = 0;
+       DibAcquireLock(&state->platform.risc.mem_mbx_lock);
+@@ -1171,12 +1148,9 @@ static int dib9000_fw_get_channel(struct
+               ret = -EIO;
+       }
+-      dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_UNION,
+-                      state->i2c_read_buffer, sizeof(struct dibDVBTChannel));
+-      ch = (struct dibDVBTChannel *)state->i2c_read_buffer;
+-
++      dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_UNION, (u8 *) &ch, sizeof(struct dibDVBTChannel));
+-      switch (ch->spectrum_inversion & 0x7) {
++      switch (ch.spectrum_inversion & 0x7) {
+       case 1:
+               state->fe[0]->dtv_property_cache.inversion = INVERSION_ON;
+               break;
+@@ -1188,7 +1162,7 @@ static int dib9000_fw_get_channel(struct
+               state->fe[0]->dtv_property_cache.inversion = INVERSION_AUTO;
+               break;
+       }
+-      switch (ch->nfft) {
++      switch (ch.nfft) {
+       case 0:
+               state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_2K;
+               break;
+@@ -1203,7 +1177,7 @@ static int dib9000_fw_get_channel(struct
+               state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_AUTO;
+               break;
+       }
+-      switch (ch->guard) {
++      switch (ch.guard) {
+       case 0:
+               state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_32;
+               break;
+@@ -1221,7 +1195,7 @@ static int dib9000_fw_get_channel(struct
+               state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_AUTO;
+               break;
+       }
+-      switch (ch->constellation) {
++      switch (ch.constellation) {
+       case 2:
+               state->fe[0]->dtv_property_cache.modulation = QAM_64;
+               break;
+@@ -1236,7 +1210,7 @@ static int dib9000_fw_get_channel(struct
+               state->fe[0]->dtv_property_cache.modulation = QAM_AUTO;
+               break;
+       }
+-      switch (ch->hrch) {
++      switch (ch.hrch) {
+       case 0:
+               state->fe[0]->dtv_property_cache.hierarchy = HIERARCHY_NONE;
+               break;
+@@ -1248,7 +1222,7 @@ static int dib9000_fw_get_channel(struct
+               state->fe[0]->dtv_property_cache.hierarchy = HIERARCHY_AUTO;
+               break;
+       }
+-      switch (ch->code_rate_hp) {
++      switch (ch.code_rate_hp) {
+       case 1:
+               state->fe[0]->dtv_property_cache.code_rate_HP = FEC_1_2;
+               break;
+@@ -1269,7 +1243,7 @@ static int dib9000_fw_get_channel(struct
+               state->fe[0]->dtv_property_cache.code_rate_HP = FEC_AUTO;
+               break;
+       }
+-      switch (ch->code_rate_lp) {
++      switch (ch.code_rate_lp) {
+       case 1:
+               state->fe[0]->dtv_property_cache.code_rate_LP = FEC_1_2;
+               break;
+@@ -1465,10 +1439,9 @@ static int dib9000_fw_tune(struct dvb_fr
+               break;
+       case CT_DEMOD_STEP_1:
+               if (search)
+-                      dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_SEARCH_STATE, state->i2c_read_buffer, 1);
++                      dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_SEARCH_STATE, (u8 *) &i, 1);
+               else
+-                      dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_TUNE_STATE, state->i2c_read_buffer, 1);
+-              i = (s8)state->i2c_read_buffer[0];
++                      dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_TUNE_STATE, (u8 *) &i, 1);
+               switch (i) {    /* something happened */
+               case 0:
+                       break;
+@@ -2065,17 +2038,14 @@ static int dib9000_read_status(struct dv
+ static int dib9000_read_ber(struct dvb_frontend *fe, u32 * ber)
+ {
+       struct dib9000_state *state = fe->demodulator_priv;
+-      u16 *c;
++      u16 c[16];
+       DibAcquireLock(&state->platform.risc.mem_mbx_lock);
+       if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0)
+               return -EIO;
+-      dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR,
+-                      state->i2c_read_buffer, 16 * 2);
++      dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, sizeof(c));
+       DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+-      c = (u16 *)state->i2c_read_buffer;
+-
+       *ber = c[10] << 16 | c[11];
+       return 0;
+ }
+@@ -2084,7 +2054,7 @@ static int dib9000_read_signal_strength(
+ {
+       struct dib9000_state *state = fe->demodulator_priv;
+       u8 index_frontend;
+-      u16 *c = (u16 *)state->i2c_read_buffer;
++      u16 c[16];
+       u16 val;
+       *strength = 0;
+@@ -2099,7 +2069,7 @@ static int dib9000_read_signal_strength(
+       DibAcquireLock(&state->platform.risc.mem_mbx_lock);
+       if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0)
+               return -EIO;
+-      dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
++      dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, sizeof(c));
+       DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+       val = 65535 - c[4];
+@@ -2113,14 +2083,14 @@ static int dib9000_read_signal_strength(
+ static u32 dib9000_get_snr(struct dvb_frontend *fe)
+ {
+       struct dib9000_state *state = fe->demodulator_priv;
+-      u16 *c = (u16 *)state->i2c_read_buffer;
++      u16 c[16];
+       u32 n, s, exp;
+       u16 val;
+       DibAcquireLock(&state->platform.risc.mem_mbx_lock);
+       if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0)
+               return -EIO;
+-      dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
++      dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, sizeof(c));
+       DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+       val = c[7];
+@@ -2167,12 +2137,12 @@ static int dib9000_read_snr(struct dvb_f
+ static int dib9000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
+ {
+       struct dib9000_state *state = fe->demodulator_priv;
+-      u16 *c = (u16 *)state->i2c_read_buffer;
++      u16 c[16];
+       DibAcquireLock(&state->platform.risc.mem_mbx_lock);
+       if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0)
+               return -EIO;
+-      dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
++      dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, sizeof(c));
+       DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+       *unc = c[12];
+@@ -2181,22 +2151,10 @@ static int dib9000_read_unc_blocks(struc
+ int dib9000_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, u8 first_addr)
+ {
+-      int k = 0, ret = 0;
++      int k = 0;
+       u8 new_addr = 0;
+       struct i2c_device client = {.i2c_adap = i2c };
+-      client.i2c_write_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
+-      if (!client.i2c_write_buffer) {
+-              dprintk("%s: not enough memory", __func__);
+-              return -ENOMEM;
+-      }
+-      client.i2c_read_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
+-      if (!client.i2c_read_buffer) {
+-              dprintk("%s: not enough memory", __func__);
+-              ret = -ENOMEM;
+-              goto error_memory;
+-      }
+-
+       client.i2c_addr = default_addr + 16;
+       dib9000_i2c_write16(&client, 1796, 0x0);
+@@ -2220,8 +2178,7 @@ int dib9000_i2c_enumeration(struct i2c_a
+                       client.i2c_addr = default_addr;
+                       if (dib9000_identify(&client) == 0) {
+                               dprintk("DiB9000 #%d: not identified", k);
+-                              ret = -EIO;
+-                              goto error;
++                              return -EIO;
+                       }
+               }
+@@ -2239,12 +2196,7 @@ int dib9000_i2c_enumeration(struct i2c_a
+               dib9000_i2c_write16(&client, 1795, 0);
+       }
+-error:
+-      kfree(client.i2c_read_buffer);
+-error_memory:
+-      kfree(client.i2c_write_buffer);
+-
+-      return ret;
++      return 0;
+ }
+ EXPORT_SYMBOL(dib9000_i2c_enumeration);
+@@ -2309,8 +2261,6 @@ struct dvb_frontend *dib9000_attach(stru
+       memcpy(&st->chip.d9.cfg, cfg, sizeof(struct dib9000_config));
+       st->i2c.i2c_adap = i2c_adap;
+       st->i2c.i2c_addr = i2c_addr;
+-      st->i2c.i2c_write_buffer = st->i2c_write_buffer;
+-      st->i2c.i2c_read_buffer = st->i2c_read_buffer;
+       st->gpio_dir = DIB9000_GPIO_DEFAULT_DIRECTIONS;
+       st->gpio_val = DIB9000_GPIO_DEFAULT_VALUES;
+--- a/drivers/media/dvb/frontends/dibx000_common.c
++++ b/drivers/media/dvb/frontends/dibx000_common.c
+@@ -10,39 +10,30 @@ MODULE_PARM_DESC(debug, "turn on debuggi
+ static int dibx000_write_word(struct dibx000_i2c_master *mst, u16 reg, u16 val)
+ {
+-      mst->i2c_write_buffer[0] = (reg >> 8) & 0xff;
+-      mst->i2c_write_buffer[1] = reg & 0xff;
+-      mst->i2c_write_buffer[2] = (val >> 8) & 0xff;
+-      mst->i2c_write_buffer[3] = val & 0xff;
+-
+-      memset(mst->msg, 0, sizeof(struct i2c_msg));
+-      mst->msg[0].addr = mst->i2c_addr;
+-      mst->msg[0].flags = 0;
+-      mst->msg[0].buf = mst->i2c_write_buffer;
+-      mst->msg[0].len = 4;
++      u8 b[4] = {
++              (reg >> 8) & 0xff, reg & 0xff,
++              (val >> 8) & 0xff, val & 0xff,
++      };
++      struct i2c_msg msg = {
++              .addr = mst->i2c_addr,.flags = 0,.buf = b,.len = 4
++      };
+-      return i2c_transfer(mst->i2c_adap, mst->msg, 1) != 1 ? -EREMOTEIO : 0;
++      return i2c_transfer(mst->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
+ }
+ static u16 dibx000_read_word(struct dibx000_i2c_master *mst, u16 reg)
+ {
+-      mst->i2c_write_buffer[0] = reg >> 8;
+-      mst->i2c_write_buffer[1] = reg & 0xff;
++      u8 wb[2] = { reg >> 8, reg & 0xff };
++      u8 rb[2];
++      struct i2c_msg msg[2] = {
++              {.addr = mst->i2c_addr, .flags = 0, .buf = wb, .len = 2},
++              {.addr = mst->i2c_addr, .flags = I2C_M_RD, .buf = rb, .len = 2},
++      };
+-      memset(mst->msg, 0, 2 * sizeof(struct i2c_msg));
+-      mst->msg[0].addr = mst->i2c_addr;
+-      mst->msg[0].flags = 0;
+-      mst->msg[0].buf = mst->i2c_write_buffer;
+-      mst->msg[0].len = 2;
+-      mst->msg[1].addr = mst->i2c_addr;
+-      mst->msg[1].flags = I2C_M_RD;
+-      mst->msg[1].buf = mst->i2c_read_buffer;
+-      mst->msg[1].len = 2;
+-
+-      if (i2c_transfer(mst->i2c_adap, mst->msg, 2) != 2)
++      if (i2c_transfer(mst->i2c_adap, msg, 2) != 2)
+               dprintk("i2c read error on %d", reg);
+-      return (mst->i2c_read_buffer[0] << 8) | mst->i2c_read_buffer[1];
++      return (rb[0] << 8) | rb[1];
+ }
+ static int dibx000_is_i2c_done(struct dibx000_i2c_master *mst)
+@@ -257,32 +248,26 @@ static int dibx000_i2c_gated_gpio67_xfer
+                                       struct i2c_msg msg[], int num)
+ {
+       struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
++      struct i2c_msg m[2 + num];
++      u8 tx_open[4], tx_close[4];
+-      if (num > 32) {
+-              dprintk("%s: too much I2C message to be transmitted (%i).\
+-                              Maximum is 32", __func__, num);
+-              return -ENOMEM;
+-      }
+-
+-      memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num));
++      memset(m, 0, sizeof(struct i2c_msg) * (2 + num));
+       dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_6_7);
+-      /* open the gate */
+-      dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1);
+-      mst->msg[0].addr = mst->i2c_addr;
+-      mst->msg[0].buf = &mst->i2c_write_buffer[0];
+-      mst->msg[0].len = 4;
+-
+-      memcpy(&mst->msg[1], msg, sizeof(struct i2c_msg) * num);
+-
+-      /* close the gate */
+-      dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[4], 0, 0);
+-      mst->msg[num + 1].addr = mst->i2c_addr;
+-      mst->msg[num + 1].buf = &mst->i2c_write_buffer[4];
+-      mst->msg[num + 1].len = 4;
++      dibx000_i2c_gate_ctrl(mst, tx_open, msg[0].addr, 1);
++      m[0].addr = mst->i2c_addr;
++      m[0].buf = tx_open;
++      m[0].len = 4;
++
++      memcpy(&m[1], msg, sizeof(struct i2c_msg) * num);
++
++      dibx000_i2c_gate_ctrl(mst, tx_close, 0, 0);
++      m[num + 1].addr = mst->i2c_addr;
++      m[num + 1].buf = tx_close;
++      m[num + 1].len = 4;
+-      return i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ? num : -EIO;
++      return i2c_transfer(mst->i2c_adap, m, 2 + num) == 2 + num ? num : -EIO;
+ }
+ static struct i2c_algorithm dibx000_i2c_gated_gpio67_algo = {
+@@ -294,32 +279,26 @@ static int dibx000_i2c_gated_tuner_xfer(
+                                       struct i2c_msg msg[], int num)
+ {
+       struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
++      struct i2c_msg m[2 + num];
++      u8 tx_open[4], tx_close[4];
+-      if (num > 32) {
+-              dprintk("%s: too much I2C message to be transmitted (%i).\
+-                              Maximum is 32", __func__, num);
+-              return -ENOMEM;
+-      }
+-
+-      memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num));
++      memset(m, 0, sizeof(struct i2c_msg) * (2 + num));
+       dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_TUNER);
+-      /* open the gate */
+-      dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1);
+-      mst->msg[0].addr = mst->i2c_addr;
+-      mst->msg[0].buf = &mst->i2c_write_buffer[0];
+-      mst->msg[0].len = 4;
+-
+-      memcpy(&mst->msg[1], msg, sizeof(struct i2c_msg) * num);
+-
+-      /* close the gate */
+-      dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[4], 0, 0);
+-      mst->msg[num + 1].addr = mst->i2c_addr;
+-      mst->msg[num + 1].buf = &mst->i2c_write_buffer[4];
+-      mst->msg[num + 1].len = 4;
++      dibx000_i2c_gate_ctrl(mst, tx_open, msg[0].addr, 1);
++      m[0].addr = mst->i2c_addr;
++      m[0].buf = tx_open;
++      m[0].len = 4;
++
++      memcpy(&m[1], msg, sizeof(struct i2c_msg) * num);
++
++      dibx000_i2c_gate_ctrl(mst, tx_close, 0, 0);
++      m[num + 1].addr = mst->i2c_addr;
++      m[num + 1].buf = tx_close;
++      m[num + 1].len = 4;
+-      return i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ? num : -EIO;
++      return i2c_transfer(mst->i2c_adap, m, 2 + num) == 2 + num ? num : -EIO;
+ }
+ static struct i2c_algorithm dibx000_i2c_gated_tuner_algo = {
+--- a/drivers/media/dvb/frontends/dibx000_common.h
++++ b/drivers/media/dvb/frontends/dibx000_common.h
+@@ -28,11 +28,6 @@ struct dibx000_i2c_master {
+       u8 i2c_addr;
+       u16 base_reg;
+-
+-      /* for the I2C transfer */
+-      struct i2c_msg msg[34];
+-      u8 i2c_write_buffer[8];
+-      u8 i2c_read_buffer[2];
+ };
+ extern int dibx000_init_i2c_master(struct dibx000_i2c_master *mst,
index c715eef6d8f750cde51109a94798c94ad1aab813..9ebdd115fe7b895207c7167cc6a900fe11858aab 100644 (file)
@@ -50,3 +50,19 @@ hwmon-asus_atk0110-fix-memory-leak.patch
 hwmon-max1111-fix-race-condition-causing-null-pointer-exception.patch
 mmc-added-quirks-for-ricoh-1180-e823-lower-base-clock.patch
 mmc-sdhci-esdhc-imx-sdhci_card_present-does-not-get.patch
+x86-make-dell-latitude-e5420-use-reboot-pci.patch
+davinci-dm365-evm-fix-video-input-mux-bits.patch
+vmscan-fix-a-livelock-in-kswapd.patch
+libata-fix-unexpectedly-frozen-port-after-ata_eh_reset.patch
+ext4-fix-oops-in-ext4_quota_off.patch
+mm-compaction-ensure-that-the-compaction-free-scanner-does-not-move-to-the-next-zone.patch
+mm-vmscan-do-not-use-page_count-without-a-page-pin.patch
+mm-compaction-abort-compaction-if-too-many-pages-are-isolated-and-caller-is-asynchronous-v2.patch
+xfs-restart-busy-extent-search-after-node-removal.patch
+cifs-clean-up-wsize-negotiation-and-allow-for-larger-wsize.patch
+cifs-fix-wsize-negotiation-to-respect-max-buffer-size-and.patch
+cifs-lower-default-and-max-wsize-to-what-2.6.39-can-handle.patch
+mm-vmscan-do-not-apply-pressure-to-slab-if-we-are-not-applying-pressure-to-zone.patch
+mm-vmscan-only-read-new_classzone_idx-from-pgdat-when-reclaiming-successfully.patch
+revert-dibxxxx-get-rid-of-dma-buffer-on-stack.patch
+vfs-fix-race-in-rcu-lookup-of-pruned-dentry.patch
diff --git a/queue-2.6.39/vfs-fix-race-in-rcu-lookup-of-pruned-dentry.patch b/queue-2.6.39/vfs-fix-race-in-rcu-lookup-of-pruned-dentry.patch
new file mode 100644 (file)
index 0000000..59f46ec
--- /dev/null
@@ -0,0 +1,50 @@
+From hughd@google.com  Mon Aug  1 11:55:24 2011
+From: Hugh Dickins <hughd@google.com>
+Date: Tue, 26 Jul 2011 13:04:16 -0700 (PDT)
+Subject: vfs: fix race in rcu lookup of pruned dentry
+To: Stable Kernel <stable@kernel.org>
+Cc: Mike Waychison <mikew@google.com>, Linus Torvalds <torvalds@linux-foundation.org>, Al Viro <viro@zeniv.linux.org.uk>, Ian Kent <raven@themaw.net>
+Message-ID: <alpine.LSU.2.00.1107261239110.24976@sister.anvils>
+
+From: Linus Torvalds <torvalds@linux-foundation.org>
+
+Backport of commit 59430262401bec02d415179c43dbe5b8819c09ce
+done by Hugh Dickins <hughd@google.com>
+
+
+Don't update *inode in __follow_mount_rcu() until we'd verified that
+there is mountpoint there.  Kudos to Hugh Dickins for catching that
+one in the first place and eventually figuring out the solution (and
+catching a braino in the earlier version of patch).
+
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Hugh Dickins <hughd@google.com>
+Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
+
+---
+ fs/namei.c |    7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/fs/namei.c
++++ b/fs/namei.c
+@@ -1013,7 +1013,6 @@ static bool __follow_mount_rcu(struct na
+                * Don't forget we might have a non-mountpoint managed dentry
+                * that wants to block transit.
+                */
+-              *inode = path->dentry->d_inode;
+               if (!reverse_transit &&
+                    unlikely(managed_dentry_might_block(path->dentry)))
+                       return false;
+@@ -1027,6 +1026,12 @@ static bool __follow_mount_rcu(struct na
+               path->mnt = mounted;
+               path->dentry = mounted->mnt_root;
+               nd->seq = read_seqcount_begin(&path->dentry->d_seq);
++              /*
++               * Update the inode too. We don't need to re-check the
++               * dentry sequence number here after this d_inode read,
++               * because a mount-point is always pinned.
++               */
++              *inode = path->dentry->d_inode;
+       }
+       if (unlikely(path->dentry->d_flags & DCACHE_NEED_AUTOMOUNT))
diff --git a/queue-2.6.39/vmscan-fix-a-livelock-in-kswapd.patch b/queue-2.6.39/vmscan-fix-a-livelock-in-kswapd.patch
new file mode 100644 (file)
index 0000000..b1572e8
--- /dev/null
@@ -0,0 +1,49 @@
+From 4746efded84d7c5a9c8d64d4c6e814ff0cf9fb42 Mon Sep 17 00:00:00 2001
+From: Shaohua Li <shaohua.li@intel.com>
+Date: Tue, 19 Jul 2011 08:49:26 -0700
+Subject: vmscan: fix a livelock in kswapd
+
+From: Shaohua Li <shaohua.li@intel.com>
+
+commit 4746efded84d7c5a9c8d64d4c6e814ff0cf9fb42 upstream.
+
+I'm running a workload which triggers a lot of swap in a machine with 4
+nodes.  After I kill the workload, I found a kswapd livelock.  Sometimes
+kswapd3 or kswapd2 are keeping running and I can't access filesystem,
+but most memory is free.
+
+This looks like a regression since commit 08951e545918c159 ("mm: vmscan:
+correct check for kswapd sleeping in sleeping_prematurely").
+
+Node 2 and 3 have only ZONE_NORMAL, but balance_pgdat() will return 0
+for classzone_idx.  The reason is end_zone in balance_pgdat() is 0 by
+default, if all zones have watermark ok, end_zone will keep 0.
+
+Later sleeping_prematurely() always returns true.  Because this is an
+order 3 wakeup, and if classzone_idx is 0, both balanced_pages and
+present_pages in pgdat_balanced() are 0.  We add a special case here.
+If a zone has no page, we think it's balanced.  This fixes the livelock.
+
+Signed-off-by: Shaohua Li <shaohua.li@intel.com>
+Acked-by: Mel Gorman <mgorman@suse.de>
+Cc: Minchan Kim <minchan.kim@gmail.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/vmscan.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/mm/vmscan.c
++++ b/mm/vmscan.c
+@@ -2245,7 +2245,8 @@ static bool pgdat_balanced(pg_data_t *pg
+       for (i = 0; i <= classzone_idx; i++)
+               present_pages += pgdat->node_zones[i].present_pages;
+-      return balanced_pages > (present_pages >> 2);
++      /* A special case here: if zone has no page, we think it's balanced */
++      return balanced_pages >= (present_pages >> 2);
+ }
+ /* is kswapd sleeping prematurely? */
diff --git a/queue-2.6.39/x86-make-dell-latitude-e5420-use-reboot-pci.patch b/queue-2.6.39/x86-make-dell-latitude-e5420-use-reboot-pci.patch
new file mode 100644 (file)
index 0000000..6fc911c
--- /dev/null
@@ -0,0 +1,43 @@
+From b7798d28ec15d20fd34b70fa57eb13f0cf6d1ecd Mon Sep 17 00:00:00 2001
+From: Daniel J Blueman <daniel.blueman@gmail.com>
+Date: Fri, 13 May 2011 09:04:59 +0800
+Subject: x86: Make Dell Latitude E5420 use reboot=pci
+
+From: Daniel J Blueman <daniel.blueman@gmail.com>
+
+commit b7798d28ec15d20fd34b70fa57eb13f0cf6d1ecd upstream.
+
+Rebooting on the Dell E5420 often hangs with the keyboard or ACPI
+methods, but is reliable via the PCI method.
+
+[ hpa: this was deferred because we believed for a long time that the
+  recent reshuffling of the boot priorities in commit
+  660e34cebf0a11d54f2d5dd8838607452355f321 fixed this platform.
+  Unfortunately that turned out to be incorrect. ]
+
+Signed-off-by: Daniel J Blueman <daniel.blueman@gmail.com>
+Link: http://lkml.kernel.org/r/1305248699-2347-1-git-send-email-daniel.blueman@gmail.com
+Signed-off-by: H. Peter Anvin <hpa@zytor.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/x86/kernel/reboot.c |    8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/arch/x86/kernel/reboot.c
++++ b/arch/x86/kernel/reboot.c
+@@ -411,6 +411,14 @@ static struct dmi_system_id __initdata p
+                       DMI_MATCH(DMI_PRODUCT_NAME, "iMac9,1"),
+               },
+       },
++      {       /* Handle problems with rebooting on the Latitude E5420. */
++              .callback = set_pci_reboot,
++              .ident = "Dell Latitude E5420",
++              .matches = {
++                      DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
++                      DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E5420"),
++              },
++      },
+       { }
+ };
diff --git a/queue-2.6.39/xfs-restart-busy-extent-search-after-node-removal.patch b/queue-2.6.39/xfs-restart-busy-extent-search-after-node-removal.patch
new file mode 100644 (file)
index 0000000..8e5a61e
--- /dev/null
@@ -0,0 +1,65 @@
+From sandeen@sandeen.net  Mon Aug  1 11:47:45 2011
+From: Eric Sandeen <sandeen@sandeen.net>
+Date: Wed, 13 Jul 2011 10:48:46 -0500
+Subject: xfs [stable only]: restart busy extent search after node removal
+To: stable@kernel.org, xfs-oss <xfs@oss.sgi.com>
+Message-ID: <4E1DBE5E.3060308@sandeen.net>
+
+From: Eric Sandeen <sandeen@sandeen.net>
+
+A user on #xfs reported that a log replay was oopsing in
+__rb_rotate_left() with a null pointer deref, and provided
+an xfs_metadump image for reproduction and testing.
+
+I traced this down to the fact that in xfs_alloc_busy_insert(),
+we erased a node with rb_erase() when the new node overlapped,
+but left the erased node specified as the parent node for the
+new insertion.
+
+So when we try to insert a new node with an erased node as
+its parent, obviously things go very wrong.
+
+Upstream,
+97d3ac75e5e0ebf7ca38ae74cebd201c09b97ab2 xfs: exact busy extent tracking
+actually fixed this, but as part of a much larger change.  Here's
+the relevant code from that commit:
+
+                * We also need to restart the busy extent search from the
+                * tree root, because erasing the node can rearrange the
+                * tree topology.
+                */
+               rb_erase(&busyp->rb_node, &pag->pagb_tree);
+               busyp->length = 0;
+               return false;
+
+We can do essentially the same thing to older codebases by restarting
+the tree search after the erase.
+
+This should apply to .35.y through .39.y, and was tested on .39
+with the oopsing replay reproducer.
+
+Signed-off-by: Eric Sandeen <sandeen@redhat.com>
+Reviewed-by: Dave Chinner <dchinner@redhat.com>
+Reviewed-by: Alex Elder <aelder@sgi.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+
+---
+ fs/xfs/xfs_alloc.c |    6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/fs/xfs/xfs_alloc.c
++++ b/fs/xfs/xfs_alloc.c
+@@ -2610,6 +2610,12 @@ restart:
+                                       new->bno + new->length) -
+                               min(busyp->bno, new->bno);
+               new->bno = min(busyp->bno, new->bno);
++              /*
++               * Start the search over from the tree root, because
++               * erasing the node can rearrange the tree topology.
++               */
++              spin_unlock(&pag->pagb_lock);
++              goto restart;
+       } else
+               busyp = NULL;