--- /dev/null
+From a12006354213203bf7fc2114286df9cbe848e234 Mon Sep 17 00:00:00 2001
+From: Vlad Yasevich <vladislav.yasevich@hp.com>
+Date: Wed, 27 Aug 2008 22:41:00 -0700
+Subject: sctp: fix potential panics in the SCTP-AUTH API.
+
+From: Vlad Yasevich <vladislav.yasevich@hp.com>
+
+[ Upstream commit 5e739d1752aca4e8f3e794d431503bfca3162df4 ]
+
+All of the SCTP-AUTH socket options could cause a panic
+if the extension is disabled and the API is envoked.
+
+Additionally, there were some additional assumptions that
+certain pointers would always be valid which may not
+always be the case.
+
+This patch hardens the API and address all of the crash
+scenarios.
+
+Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ net/sctp/endpointola.c | 4 +-
+ net/sctp/socket.c | 85 +++++++++++++++++++++++++++++++++++++------------
+ 2 files changed, 67 insertions(+), 22 deletions(-)
+
+--- a/net/sctp/endpointola.c
++++ b/net/sctp/endpointola.c
+@@ -103,6 +103,7 @@ static struct sctp_endpoint *sctp_endpoi
+
+ /* Initialize the CHUNKS parameter */
+ auth_chunks->param_hdr.type = SCTP_PARAM_CHUNKS;
++ auth_chunks->param_hdr.length = htons(sizeof(sctp_paramhdr_t));
+
+ /* If the Add-IP functionality is enabled, we must
+ * authenticate, ASCONF and ASCONF-ACK chunks
+@@ -110,8 +111,7 @@ static struct sctp_endpoint *sctp_endpoi
+ if (sctp_addip_enable) {
+ auth_chunks->chunks[0] = SCTP_CID_ASCONF;
+ auth_chunks->chunks[1] = SCTP_CID_ASCONF_ACK;
+- auth_chunks->param_hdr.length =
+- htons(sizeof(sctp_paramhdr_t) + 2);
++ auth_chunks->param_hdr.length += htons(2);
+ }
+ }
+
+--- a/net/sctp/socket.c
++++ b/net/sctp/socket.c
+@@ -2983,6 +2983,9 @@ static int sctp_setsockopt_auth_chunk(st
+ {
+ struct sctp_authchunk val;
+
++ if (!sctp_auth_enable)
++ return -EACCES;
++
+ if (optlen != sizeof(struct sctp_authchunk))
+ return -EINVAL;
+ if (copy_from_user(&val, optval, optlen))
+@@ -3013,6 +3016,9 @@ static int sctp_setsockopt_hmac_ident(st
+ struct sctp_hmacalgo *hmacs;
+ int err;
+
++ if (!sctp_auth_enable)
++ return -EACCES;
++
+ if (optlen < sizeof(struct sctp_hmacalgo))
+ return -EINVAL;
+
+@@ -3051,6 +3057,9 @@ static int sctp_setsockopt_auth_key(stru
+ struct sctp_association *asoc;
+ int ret;
+
++ if (!sctp_auth_enable)
++ return -EACCES;
++
+ if (optlen <= sizeof(struct sctp_authkey))
+ return -EINVAL;
+
+@@ -3088,6 +3097,9 @@ static int sctp_setsockopt_active_key(st
+ struct sctp_authkeyid val;
+ struct sctp_association *asoc;
+
++ if (!sctp_auth_enable)
++ return -EACCES;
++
+ if (optlen != sizeof(struct sctp_authkeyid))
+ return -EINVAL;
+ if (copy_from_user(&val, optval, optlen))
+@@ -3113,6 +3125,9 @@ static int sctp_setsockopt_del_key(struc
+ struct sctp_authkeyid val;
+ struct sctp_association *asoc;
+
++ if (!sctp_auth_enable)
++ return -EACCES;
++
+ if (optlen != sizeof(struct sctp_authkeyid))
+ return -EINVAL;
+ if (copy_from_user(&val, optval, optlen))
+@@ -5073,19 +5088,29 @@ static int sctp_getsockopt_maxburst(stru
+ static int sctp_getsockopt_hmac_ident(struct sock *sk, int len,
+ char __user *optval, int __user *optlen)
+ {
++ struct sctp_hmacalgo __user *p = (void __user *)optval;
+ struct sctp_hmac_algo_param *hmacs;
+- __u16 param_len;
++ __u16 data_len = 0;
++ u32 num_idents;
++
++ if (!sctp_auth_enable)
++ return -EACCES;
+
+ hmacs = sctp_sk(sk)->ep->auth_hmacs_list;
+- param_len = ntohs(hmacs->param_hdr.length);
++ data_len = ntohs(hmacs->param_hdr.length) - sizeof(sctp_paramhdr_t);
+
+- if (len < param_len)
++ if (len < sizeof(struct sctp_hmacalgo) + data_len)
+ return -EINVAL;
++
++ len = sizeof(struct sctp_hmacalgo) + data_len;
++ num_idents = data_len / sizeof(u16);
++
+ if (put_user(len, optlen))
+ return -EFAULT;
+- if (copy_to_user(optval, hmacs->hmac_ids, len))
++ if (put_user(num_idents, &p->shmac_num_idents))
++ return -EFAULT;
++ if (copy_to_user(p->shmac_idents, hmacs->hmac_ids, data_len))
+ return -EFAULT;
+-
+ return 0;
+ }
+
+@@ -5095,6 +5120,9 @@ static int sctp_getsockopt_active_key(st
+ struct sctp_authkeyid val;
+ struct sctp_association *asoc;
+
++ if (!sctp_auth_enable)
++ return -EACCES;
++
+ if (len < sizeof(struct sctp_authkeyid))
+ return -EINVAL;
+ if (copy_from_user(&val, optval, sizeof(struct sctp_authkeyid)))
+@@ -5109,6 +5137,12 @@ static int sctp_getsockopt_active_key(st
+ else
+ val.scact_keynumber = sctp_sk(sk)->ep->active_key_id;
+
++ len = sizeof(struct sctp_authkeyid);
++ if (put_user(len, optlen))
++ return -EFAULT;
++ if (copy_to_user(optval, &val, len))
++ return -EFAULT;
++
+ return 0;
+ }
+
+@@ -5119,13 +5153,16 @@ static int sctp_getsockopt_peer_auth_chu
+ struct sctp_authchunks val;
+ struct sctp_association *asoc;
+ struct sctp_chunks_param *ch;
+- u32 num_chunks;
++ u32 num_chunks = 0;
+ char __user *to;
+
+- if (len <= sizeof(struct sctp_authchunks))
++ if (!sctp_auth_enable)
++ return -EACCES;
++
++ if (len < sizeof(struct sctp_authchunks))
+ return -EINVAL;
+
+- if (copy_from_user(&val, p, sizeof(struct sctp_authchunks)))
++ if (copy_from_user(&val, optval, sizeof(struct sctp_authchunks)))
+ return -EFAULT;
+
+ to = p->gauth_chunks;
+@@ -5134,20 +5171,21 @@ static int sctp_getsockopt_peer_auth_chu
+ return -EINVAL;
+
+ ch = asoc->peer.peer_chunks;
++ if (!ch)
++ goto num;
+
+ /* See if the user provided enough room for all the data */
+ num_chunks = ntohs(ch->param_hdr.length) - sizeof(sctp_paramhdr_t);
+ if (len < num_chunks)
+ return -EINVAL;
+
+- len = num_chunks;
+- if (put_user(len, optlen))
++ if (copy_to_user(to, ch->chunks, num_chunks))
+ return -EFAULT;
++num:
++ len = sizeof(struct sctp_authchunks) + num_chunks;
++ if (put_user(len, optlen)) return -EFAULT;
+ if (put_user(num_chunks, &p->gauth_number_of_chunks))
+ return -EFAULT;
+- if (copy_to_user(to, ch->chunks, len))
+- return -EFAULT;
+-
+ return 0;
+ }
+
+@@ -5158,13 +5196,16 @@ static int sctp_getsockopt_local_auth_ch
+ struct sctp_authchunks val;
+ struct sctp_association *asoc;
+ struct sctp_chunks_param *ch;
+- u32 num_chunks;
++ u32 num_chunks = 0;
+ char __user *to;
+
+- if (len <= sizeof(struct sctp_authchunks))
++ if (!sctp_auth_enable)
++ return -EACCES;
++
++ if (len < sizeof(struct sctp_authchunks))
+ return -EINVAL;
+
+- if (copy_from_user(&val, p, sizeof(struct sctp_authchunks)))
++ if (copy_from_user(&val, optval, sizeof(struct sctp_authchunks)))
+ return -EFAULT;
+
+ to = p->gauth_chunks;
+@@ -5177,17 +5218,21 @@ static int sctp_getsockopt_local_auth_ch
+ else
+ ch = sctp_sk(sk)->ep->auth_chunk_list;
+
++ if (!ch)
++ goto num;
++
+ num_chunks = ntohs(ch->param_hdr.length) - sizeof(sctp_paramhdr_t);
+- if (len < num_chunks)
++ if (len < sizeof(struct sctp_authchunks) + num_chunks)
+ return -EINVAL;
+
+- len = num_chunks;
++ if (copy_to_user(to, ch->chunks, num_chunks))
++ return -EFAULT;
++num:
++ len = sizeof(struct sctp_authchunks) + num_chunks;
+ if (put_user(len, optlen))
+ return -EFAULT;
+ if (put_user(num_chunks, &p->gauth_number_of_chunks))
+ return -EFAULT;
+- if (copy_to_user(to, ch->chunks, len))
+- return -EFAULT;
+
+ return 0;
+ }
--- /dev/null
+From c7064b2bd573a5bd2364e076878c753c5da50ee5 Mon Sep 17 00:00:00 2001
+From: Vlad Yasevich <vladislav.yasevich@hp.com>
+Date: Wed, 27 Aug 2008 22:41:52 -0700
+Subject: sctp: add verification checks to SCTP_AUTH_KEY option
+
+From: Vlad Yasevich <vladislav.yasevich@hp.com>
+
+[ Upstream commit 30c2235cbc477d4629983d440cdc4f496fec9246 ]
+
+The structure used for SCTP_AUTH_KEY option contains a
+length that needs to be verfied to prevent buffer overflow
+conditions. Spoted by Eugene Teo <eteo@redhat.com>.
+
+Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ net/sctp/auth.c | 4 ++++
+ net/sctp/socket.c | 5 +++++
+ 2 files changed, 9 insertions(+)
+
+--- a/net/sctp/auth.c
++++ b/net/sctp/auth.c
+@@ -80,6 +80,10 @@ static struct sctp_auth_bytes *sctp_auth
+ {
+ struct sctp_auth_bytes *key;
+
++ /* Verify that we are not going to overflow INT_MAX */
++ if ((INT_MAX - key_len) < sizeof(struct sctp_auth_bytes))
++ return NULL;
++
+ /* Allocate the shared key */
+ key = kmalloc(sizeof(struct sctp_auth_bytes) + key_len, gfp);
+ if (!key)
+--- a/net/sctp/socket.c
++++ b/net/sctp/socket.c
+@@ -3072,6 +3072,11 @@ static int sctp_setsockopt_auth_key(stru
+ goto out;
+ }
+
++ if (authkey->sca_keylength > optlen) {
++ ret = -EINVAL;
++ goto out;
++ }
++
+ asoc = sctp_id2assoc(sk, authkey->sca_assoc_id);
+ if (!asoc && authkey->sca_assoc_id && sctp_style(sk, UDP)) {
+ ret = -EINVAL;
--- /dev/null
+From 7bcd9afb203f780afb7fddaf7604166912129c4e Mon Sep 17 00:00:00 2001
+From: Vlad Yasevich <vladislav.yasevich@hp.com>
+Date: Wed, 3 Sep 2008 01:02:19 -0700
+Subject: sctp: correct bounds check in sctp_setsockopt_auth_key
+
+From: Vlad Yasevich <vladislav.yasevich@hp.com>
+
+[ Upstream commit 328fc47ea0bcc27d9afa69c3ad6e52431cadd76c ]
+
+The bonds check to prevent buffer overlflow was not exactly
+right. It still allowed overflow of up to 8 bytes which is
+sizeof(struct sctp_authkey).
+
+Since optlen is already checked against the size of that struct,
+we are guaranteed not to cause interger overflow either.
+
+Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ net/sctp/socket.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/net/sctp/socket.c
++++ b/net/sctp/socket.c
+@@ -3072,7 +3072,7 @@ static int sctp_setsockopt_auth_key(stru
+ goto out;
+ }
+
+- if (authkey->sca_keylength > optlen) {
++ if (authkey->sca_keylength > optlen - sizeof(struct sctp_authkey)) {
+ ret = -EINVAL;
+ goto out;
+ }
--- /dev/null
+From ddfe8ddeda4fc1fa7cd39462af39d2d7b3423c3c Mon Sep 17 00:00:00 2001
+From: Vlad Yasevich <vladislav.yasevich@hp.com>
+Date: Wed, 3 Sep 2008 01:02:37 -0700
+Subject: sctp: fix random memory dereference with SCTP_HMAC_IDENT option.
+
+From: Vlad Yasevich <vladislav.yasevich@hp.com>
+
+[ Upstream commit d97240552cd98c4b07322f30f66fd9c3ba4171de ]
+
+The number of identifiers needs to be checked against the option
+length. Also, the identifier index provided needs to be verified
+to make sure that it doesn't exceed the bounds of the array.
+
+Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ net/sctp/auth.c | 3 +++
+ net/sctp/socket.c | 6 ++++--
+ 2 files changed, 7 insertions(+), 2 deletions(-)
+
+--- a/net/sctp/auth.c
++++ b/net/sctp/auth.c
+@@ -786,6 +786,9 @@ int sctp_auth_ep_set_hmacs(struct sctp_e
+ for (i = 0; i < hmacs->shmac_num_idents; i++) {
+ id = hmacs->shmac_idents[i];
+
++ if (id > SCTP_AUTH_HMAC_ID_MAX)
++ return -EOPNOTSUPP;
++
+ if (SCTP_AUTH_HMAC_ID_SHA1 == id)
+ has_sha1 = 1;
+
+--- a/net/sctp/socket.c
++++ b/net/sctp/socket.c
+@@ -3014,6 +3014,7 @@ static int sctp_setsockopt_hmac_ident(st
+ int optlen)
+ {
+ struct sctp_hmacalgo *hmacs;
++ u32 idents;
+ int err;
+
+ if (!sctp_auth_enable)
+@@ -3031,8 +3032,9 @@ static int sctp_setsockopt_hmac_ident(st
+ goto out;
+ }
+
+- if (hmacs->shmac_num_idents == 0 ||
+- hmacs->shmac_num_idents > SCTP_AUTH_NUM_HMACS) {
++ idents = hmacs->shmac_num_idents;
++ if (idents == 0 || idents > SCTP_AUTH_NUM_HMACS ||
++ (idents * sizeof(u16)) > (optlen - sizeof(struct sctp_hmacalgo))) {
+ err = -EINVAL;
+ goto out;
+ }
--- /dev/null
+From jejb@kernel.org Wed Sep 3 08:10:42 2008
+From: Jeff Layton <jlayton@redhat.com>
+Date: Tue, 2 Sep 2008 19:25:05 GMT
+Subject: cifs: fix O_APPEND on directio mounts
+To: jejb@kernel.org, stable@kernel.org
+Message-ID: <200809021925.m82JP5Xb008422@hera.kernel.org>
+
+From: Jeff Layton <jlayton@redhat.com>
+
+commit 838726c4756813576078203eb7e1e219db0da870 upstream
+
+The direct I/O write codepath for CIFS is done through
+cifs_user_write(). That function does not currently call
+generic_write_checks() so the file position isn't being properly set
+when the file is opened with O_APPEND. It's also not doing the other
+"normal" checks that should be done for a write call.
+
+The problem is currently that when you open a file with O_APPEND on a
+mount with the directio mount option, the file position is set to the
+beginning of the file. This makes any subsequent writes clobber the data
+in the file starting at the beginning.
+
+This seems to fix the problem in cursory testing. It is, however
+important to note that NFS disallows the combination of
+(O_DIRECT|O_APPEND). If my understanding is correct, the concern is
+races with multiple clients appending to a file clobbering each others'
+data. Since the write model for CIFS and NFS is pretty similar in this
+regard, CIFS is probably subject to the same sort of races. What's
+unclear to me is why this is a particular problem with O_DIRECT and not
+with buffered writes...
+
+Regardless, disallowing O_APPEND on an entire mount is probably not
+reasonable, so we'll probably just have to deal with it and reevaluate
+this flag combination when we get proper support for O_DIRECT. In the
+meantime this patch at least fixes the existing problem.
+
+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/file.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/fs/cifs/file.c
++++ b/fs/cifs/file.c
+@@ -835,6 +835,10 @@ ssize_t cifs_user_write(struct file *fil
+ return -EBADF;
+ open_file = (struct cifsFileInfo *) file->private_data;
+
++ rc = generic_write_checks(file, poffset, &write_size, 0);
++ if (rc)
++ return rc;
++
+ xid = GetXid();
+
+ if (*poffset > file->f_path.dentry->d_inode->i_size)
--- /dev/null
+From jejb@kernel.org Tue Sep 2 17:06:27 2008
+From: Al Viro <viro@ZenIV.linux.org.uk>
+Date: Wed, 20 Aug 2008 22:50:04 GMT
+Subject: cramfs: fix named-pipe handling
+To: jejb@kernel.org, stable@kernel.org
+Message-ID: <200808202250.m7KMo468016214@hera.kernel.org>
+
+From: Al Viro <viro@ZenIV.linux.org.uk>
+
+commit 82d63fc9e30687c055b97928942b8893ea65b0bb upstream
+
+After commit a97c9bf33f4612e2aed6f000f6b1d268b6814f3c (fix cramfs
+making duplicate entries in inode cache) in kernel 2.6.14, named-pipe
+on cramfs does not work properly.
+
+It seems the commit make all named-pipe on cramfs share their inode
+(and named-pipe buffer).
+
+Make ..._test() refuse to merge inodes with ->i_ino == 1, take inode setup
+back to get_cramfs_inode() and make ->drop_inode() evict ones with ->i_ino
+== 1 immediately.
+
+Reported-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
+Cc: Al Viro <viro@zeniv.linux.org.uk>
+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>
+
+---
+ fs/cramfs/inode.c | 84 ++++++++++++++++++++++++------------------------------
+ 1 file changed, 38 insertions(+), 46 deletions(-)
+
+--- a/fs/cramfs/inode.c
++++ b/fs/cramfs/inode.c
+@@ -44,58 +44,13 @@ static DEFINE_MUTEX(read_mutex);
+ static int cramfs_iget5_test(struct inode *inode, void *opaque)
+ {
+ struct cramfs_inode *cramfs_inode = opaque;
+-
+- if (inode->i_ino != CRAMINO(cramfs_inode))
+- return 0; /* does not match */
+-
+- if (inode->i_ino != 1)
+- return 1;
+-
+- /* all empty directories, char, block, pipe, and sock, share inode #1 */
+-
+- if ((inode->i_mode != cramfs_inode->mode) ||
+- (inode->i_gid != cramfs_inode->gid) ||
+- (inode->i_uid != cramfs_inode->uid))
+- return 0; /* does not match */
+-
+- if ((S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) &&
+- (inode->i_rdev != old_decode_dev(cramfs_inode->size)))
+- return 0; /* does not match */
+-
+- return 1; /* matches */
++ return inode->i_ino == CRAMINO(cramfs_inode) && inode->i_ino != 1;
+ }
+
+ static int cramfs_iget5_set(struct inode *inode, void *opaque)
+ {
+- static struct timespec zerotime;
+ struct cramfs_inode *cramfs_inode = opaque;
+- inode->i_mode = cramfs_inode->mode;
+- inode->i_uid = cramfs_inode->uid;
+- inode->i_size = cramfs_inode->size;
+- inode->i_blocks = (cramfs_inode->size - 1) / 512 + 1;
+- inode->i_gid = cramfs_inode->gid;
+- /* Struct copy intentional */
+- inode->i_mtime = inode->i_atime = inode->i_ctime = zerotime;
+ inode->i_ino = CRAMINO(cramfs_inode);
+- /* inode->i_nlink is left 1 - arguably wrong for directories,
+- but it's the best we can do without reading the directory
+- contents. 1 yields the right result in GNU find, even
+- without -noleaf option. */
+- if (S_ISREG(inode->i_mode)) {
+- inode->i_fop = &generic_ro_fops;
+- inode->i_data.a_ops = &cramfs_aops;
+- } else if (S_ISDIR(inode->i_mode)) {
+- inode->i_op = &cramfs_dir_inode_operations;
+- inode->i_fop = &cramfs_directory_operations;
+- } else if (S_ISLNK(inode->i_mode)) {
+- inode->i_op = &page_symlink_inode_operations;
+- inode->i_data.a_ops = &cramfs_aops;
+- } else {
+- inode->i_size = 0;
+- inode->i_blocks = 0;
+- init_special_inode(inode, inode->i_mode,
+- old_decode_dev(cramfs_inode->size));
+- }
+ return 0;
+ }
+
+@@ -105,12 +60,48 @@ static struct inode *get_cramfs_inode(st
+ struct inode *inode = iget5_locked(sb, CRAMINO(cramfs_inode),
+ cramfs_iget5_test, cramfs_iget5_set,
+ cramfs_inode);
++ static struct timespec zerotime;
++
+ if (inode && (inode->i_state & I_NEW)) {
++ inode->i_mode = cramfs_inode->mode;
++ inode->i_uid = cramfs_inode->uid;
++ inode->i_size = cramfs_inode->size;
++ inode->i_blocks = (cramfs_inode->size - 1) / 512 + 1;
++ inode->i_gid = cramfs_inode->gid;
++ /* Struct copy intentional */
++ inode->i_mtime = inode->i_atime = inode->i_ctime = zerotime;
++ /* inode->i_nlink is left 1 - arguably wrong for directories,
++ but it's the best we can do without reading the directory
++ contents. 1 yields the right result in GNU find, even
++ without -noleaf option. */
++ if (S_ISREG(inode->i_mode)) {
++ inode->i_fop = &generic_ro_fops;
++ inode->i_data.a_ops = &cramfs_aops;
++ } else if (S_ISDIR(inode->i_mode)) {
++ inode->i_op = &cramfs_dir_inode_operations;
++ inode->i_fop = &cramfs_directory_operations;
++ } else if (S_ISLNK(inode->i_mode)) {
++ inode->i_op = &page_symlink_inode_operations;
++ inode->i_data.a_ops = &cramfs_aops;
++ } else {
++ inode->i_size = 0;
++ inode->i_blocks = 0;
++ init_special_inode(inode, inode->i_mode,
++ old_decode_dev(cramfs_inode->size));
++ }
+ unlock_new_inode(inode);
+ }
+ return inode;
+ }
+
++static void cramfs_drop_inode(struct inode *inode)
++{
++ if (inode->i_ino == 1)
++ generic_delete_inode(inode);
++ else
++ generic_drop_inode(inode);
++}
++
+ /*
+ * We have our own block cache: don't fill up the buffer cache
+ * with the rom-image, because the way the filesystem is set
+@@ -535,6 +526,7 @@ static const struct super_operations cra
+ .put_super = cramfs_put_super,
+ .remount_fs = cramfs_remount,
+ .statfs = cramfs_statfs,
++ .drop_inode = cramfs_drop_inode,
+ };
+
+ static int cramfs_get_sb(struct file_system_type *fs_type,
--- /dev/null
+From herbert@gondor.apana.org.au Wed Sep 3 08:39:23 2008
+From: Herbert Xu <herbert@gondor.apana.org.au>
+Date: Sat, 23 Aug 2008 09:36:17 +1000
+Subject: crypto: authenc - Avoid using clobbered request pointer
+To: stable@kernel.org
+Message-ID: <20080822233617.GA5309@gondor.apana.org.au>
+Content-Disposition: inline
+
+From: Herbert Xu <herbert@gondor.apana.org.au>
+
+crypto: authenc - Avoid using clobbered request pointer
+
+[ Upstream commit: a697690bece75d4ba424c1318eb25c37d41d5829 ]
+
+Authenc works in two stages for encryption, it first encrypts and
+then computes an ICV. The context memory of the request is used
+by both operations. The problem is that when an asynchronous
+encryption completes, we will compute the ICV and then reread the
+context memory of the encryption to get the original request.
+
+It just happens that we have a buffer of 16 bytes in front of the
+request pointer, so ICVs of 16 bytes (such as SHA1) do not trigger
+the bug. However, any attempt to uses a larger ICV instantly kills
+the machine when the first asynchronous encryption is completed.
+
+This patch fixes this by saving the request pointer before we start
+the ICV computation.
+
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ crypto/authenc.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+--- a/crypto/authenc.c
++++ b/crypto/authenc.c
+@@ -174,8 +174,9 @@ static int crypto_authenc_genicv(struct
+ static void crypto_authenc_encrypt_done(struct crypto_async_request *req,
+ int err)
+ {
++ struct aead_request *areq = req->data;
++
+ if (!err) {
+- struct aead_request *areq = req->data;
+ struct crypto_aead *authenc = crypto_aead_reqtfm(areq);
+ struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
+ struct ablkcipher_request *abreq = aead_request_ctx(areq);
+@@ -185,7 +186,7 @@ static void crypto_authenc_encrypt_done(
+ err = crypto_authenc_genicv(areq, iv, 0);
+ }
+
+- aead_request_complete(req->data, err);
++ aead_request_complete(areq, err);
+ }
+
+ static int crypto_authenc_encrypt(struct aead_request *req)
+@@ -216,14 +217,15 @@ static int crypto_authenc_encrypt(struct
+ static void crypto_authenc_givencrypt_done(struct crypto_async_request *req,
+ int err)
+ {
++ struct aead_request *areq = req->data;
++
+ if (!err) {
+- struct aead_request *areq = req->data;
+ struct skcipher_givcrypt_request *greq = aead_request_ctx(areq);
+
+ err = crypto_authenc_genicv(areq, greq->giv, 0);
+ }
+
+- aead_request_complete(req->data, err);
++ aead_request_complete(areq, err);
+ }
+
+ static int crypto_authenc_givencrypt(struct aead_givcrypt_request *req)
--- /dev/null
+From jejb@kernel.org Tue Sep 2 17:09:21 2008
+From: Ian Campbell <ijc@hellion.org.uk>
+Date: Wed, 20 Aug 2008 22:50:11 GMT
+Subject: fbdefio: add set_page_dirty handler to deferred IO FB
+To: jejb@kernel.org, stable@kernel.org
+Message-ID: <200808202250.m7KMoAHT016246@hera.kernel.org>
+
+From: Ian Campbell <ijc@hellion.org.uk>
+
+commit d847471d063663b9f36927d265c66a270c0cfaab upstream
+
+Fixes kernel BUG at lib/radix-tree.c:473.
+
+Previously the handler was incidentally provided by tmpfs but this was
+removed with:
+
+ commit 14fcc23fdc78e9d32372553ccf21758a9bd56fa1
+ Author: Hugh Dickins <hugh@veritas.com>
+ Date: Mon Jul 28 15:46:19 2008 -0700
+
+ tmpfs: fix kernel BUG in shmem_delete_inode
+
+relying on this behaviour was incorrect in any case and the BUG also
+appeared when the device node was on an ext3 filesystem.
+
+v2: override a_ops at open() time rather than mmap() time to minimise
+races per AKPM's concerns.
+
+Signed-off-by: Ian Campbell <ijc@hellion.org.uk>
+Cc: Jaya Kumar <jayakumar.lkml@gmail.com>
+Cc: Nick Piggin <npiggin@suse.de>
+Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
+Cc: Hugh Dickins <hugh@veritas.com>
+Cc: Johannes Weiner <hannes@saeurebad.de>
+Cc: Jeremy Fitzhardinge <jeremy@goop.org>
+Cc: Kel Modderman <kel@otaku42.de>
+Cc: Markus Armbruster <armbru@redhat.com>
+Cc: Krzysztof Helt <krzysztof.h1@poczta.fm>
+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>
+
+---
+ drivers/video/fb_defio.c | 19 +++++++++++++++++++
+ drivers/video/fbmem.c | 4 ++++
+ include/linux/fb.h | 3 +++
+ 3 files changed, 26 insertions(+)
+
+--- a/drivers/video/fb_defio.c
++++ b/drivers/video/fb_defio.c
+@@ -114,6 +114,17 @@ static struct vm_operations_struct fb_de
+ .page_mkwrite = fb_deferred_io_mkwrite,
+ };
+
++static int fb_deferred_io_set_page_dirty(struct page *page)
++{
++ if (!PageDirty(page))
++ SetPageDirty(page);
++ return 0;
++}
++
++static const struct address_space_operations fb_deferred_io_aops = {
++ .set_page_dirty = fb_deferred_io_set_page_dirty,
++};
++
+ static int fb_deferred_io_mmap(struct fb_info *info, struct vm_area_struct *vma)
+ {
+ vma->vm_ops = &fb_deferred_io_vm_ops;
+@@ -163,6 +174,14 @@ void fb_deferred_io_init(struct fb_info
+ }
+ EXPORT_SYMBOL_GPL(fb_deferred_io_init);
+
++void fb_deferred_io_open(struct fb_info *info,
++ struct inode *inode,
++ struct file *file)
++{
++ file->f_mapping->a_ops = &fb_deferred_io_aops;
++}
++EXPORT_SYMBOL_GPL(fb_deferred_io_open);
++
+ void fb_deferred_io_cleanup(struct fb_info *info)
+ {
+ void *screen_base = (void __force *) info->screen_base;
+--- a/drivers/video/fbmem.c
++++ b/drivers/video/fbmem.c
+@@ -1315,6 +1315,10 @@ fb_open(struct inode *inode, struct file
+ if (res)
+ module_put(info->fbops->owner);
+ }
++#ifdef CONFIG_FB_DEFERRED_IO
++ if (info->fbdefio)
++ fb_deferred_io_open(info, inode, file);
++#endif
+ return res;
+ }
+
+--- a/include/linux/fb.h
++++ b/include/linux/fb.h
+@@ -966,6 +966,9 @@ static inline void __fb_pad_aligned_buff
+
+ /* drivers/video/fb_defio.c */
+ extern void fb_deferred_io_init(struct fb_info *info);
++extern void fb_deferred_io_open(struct fb_info *info,
++ struct inode *inode,
++ struct file *file);
+ extern void fb_deferred_io_cleanup(struct fb_info *info);
+ extern int fb_deferred_io_fsync(struct file *file, struct dentry *dentry,
+ int datasync);
--- /dev/null
+From jejb@kernel.org Wed Sep 3 08:08:26 2008
+From: Ayaz Abdulla <aabdulla@nvidia.com>
+Date: Thu, 28 Aug 2008 19:40:03 GMT
+Subject: forcedeth: fix checksum flag
+To: jejb@kernel.org, stable@kernel.org
+Message-ID: <200808281940.m7SJe3SO029532@hera.kernel.org>
+
+From: Ayaz Abdulla <aabdulla@nvidia.com>
+
+commit edcfe5f7e307846e578fb88d69fa27051fded0ab upstream
+
+Fix the checksum feature advertised in device flags. The hardware support
+TCP/UDP over IPv4 and TCP/UDP over IPv6 (without IPv6 extension headers).
+However, the kernel feature flags do not distinguish IPv6 with/without
+extension headers.
+
+Therefore, the driver needs to use NETIF_F_IP_CSUM instead of
+NETIF_F_HW_CSUM since the latter includes all IPv6 packets.
+
+A future patch can be created to check for extension headers and perform
+software checksum calculation.
+
+Signed-off-by: Ayaz Abdulla <aabdulla@nvidia.com>
+Cc: Jeff Garzik <jgarzik@pobox.com>
+Cc: Manfred Spraul <manfred@colorfullife.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/net/forcedeth.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/forcedeth.c
++++ b/drivers/net/forcedeth.c
+@@ -5249,7 +5249,7 @@ static int __devinit nv_probe(struct pci
+ if (id->driver_data & DEV_HAS_CHECKSUM) {
+ np->rx_csum = 1;
+ np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK;
+- dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
++ dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
+ dev->features |= NETIF_F_TSO;
+ }
+
+@@ -5548,7 +5548,7 @@ static int __devinit nv_probe(struct pci
+
+ dev_printk(KERN_INFO, &pci_dev->dev, "%s%s%s%s%s%s%s%s%s%sdesc-v%u\n",
+ dev->features & NETIF_F_HIGHDMA ? "highdma " : "",
+- dev->features & (NETIF_F_HW_CSUM | NETIF_F_SG) ?
++ dev->features & (NETIF_F_IP_CSUM | NETIF_F_SG) ?
+ "csum " : "",
+ dev->features & (NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX) ?
+ "vlan " : "",
--- /dev/null
+From jejb@kernel.org Wed Sep 3 08:25:42 2008
+From: Adam Litke <agl@us.ibm.com>
+Date: Wed, 3 Sep 2008 02:35:08 GMT
+Subject: mm: make setup_zone_migrate_reserve() aware of overlapping nodes
+To: jejb@kernel.org, stable@kernel.org
+Message-ID: <200809030235.m832Z8Wn015432@hera.kernel.org>
+
+From: Adam Litke <agl@us.ibm.com>
+
+commit 344c790e3821dac37eb742ddd0b611a300f78b9a upstream
+
+I have gotten to the root cause of the hugetlb badness I reported back on
+August 15th. My system has the following memory topology (note the
+overlapping node):
+
+ Node 0 Memory: 0x8000000-0x44000000
+ Node 1 Memory: 0x0-0x8000000 0x44000000-0x80000000
+
+setup_zone_migrate_reserve() scans the address range 0x0-0x8000000 looking
+for a pageblock to move onto the MIGRATE_RESERVE list. Finding no
+candidates, it happily continues the scan into 0x8000000-0x44000000. When
+a pageblock is found, the pages are moved to the MIGRATE_RESERVE list on
+the wrong zone. Oops.
+
+setup_zone_migrate_reserve() should skip pageblocks in overlapping nodes.
+
+Signed-off-by: Adam Litke <agl@us.ibm.com>
+Acked-by: Mel Gorman <mel@csn.ul.ie>
+Cc: Dave Hansen <dave@linux.vnet.ibm.com>
+Cc: Nishanth Aravamudan <nacc@us.ibm.com>
+Cc: Andy Whitcroft <apw@shadowen.org>
+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/page_alloc.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/mm/page_alloc.c
++++ b/mm/page_alloc.c
+@@ -717,6 +717,9 @@ int move_freepages(struct zone *zone,
+ #endif
+
+ for (page = start_page; page <= end_page;) {
++ /* Make sure we are not inadvertently changing nodes */
++ VM_BUG_ON(page_to_nid(page) != zone_to_nid(zone));
++
+ if (!pfn_valid_within(page_to_pfn(page))) {
+ page++;
+ continue;
+@@ -2476,6 +2479,10 @@ static void setup_zone_migrate_reserve(s
+ continue;
+ page = pfn_to_page(pfn);
+
++ /* Watch out for overlapping nodes */
++ if (page_to_nid(page) != zone_to_nid(zone))
++ continue;
++
+ /* Blocks with reserved pages will never free, skip them. */
+ if (PageReserved(page))
+ continue;
--- /dev/null
+From bfields@citi.umich.edu Wed Sep 3 09:39:51 2008
+From: "J. Bruce Fields" <bfields@citi.umich.edu>
+Date: Mon, 1 Sep 2008 14:51:02 -0400
+Subject: nfsd: fix buffer overrun decoding NFSv4 acl
+To: stable@kernel.org
+Cc: linux-nfs@vger.kernel.org, "J. Bruce Fields" <bfields@citi.umich.edu>, linux-kernel@vger.kernel.org, David Richter <richterd@citi.umich.edu>
+Message-ID: <1220295062-10957-2-git-send-email-bfields@citi.umich.edu>
+
+From: J. Bruce Fields <bfields@citi.umich.edu>
+
+commit 91b80969ba466ba4b915a4a1d03add8c297add3f upstream
+
+The array we kmalloc() here is not large enough.
+
+Thanks to Johann Dahm and David Richter for bug report and testing.
+
+Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
+Cc: David Richter <richterd@citi.umich.edu>
+Tested-by: Johann Dahm <jdahm@umich.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ fs/nfsd/nfs4acl.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/fs/nfsd/nfs4acl.c
++++ b/fs/nfsd/nfs4acl.c
+@@ -443,7 +443,7 @@ init_state(struct posix_acl_state *state
+ * enough space for either:
+ */
+ alloc = sizeof(struct posix_ace_state_array)
+- + cnt*sizeof(struct posix_ace_state);
++ + cnt*sizeof(struct posix_user_ace_state);
+ state->users = kzalloc(alloc, GFP_KERNEL);
+ if (!state->users)
+ return -ENOMEM;
--- /dev/null
+From romieu@fr.zoreil.com Wed Sep 3 09:37:25 2008
+From: Francois Romieu <romieu@fr.zoreil.com>
+Date: Thu, 28 Aug 2008 22:55:33 +0200
+Subject: r8169: balance pci_map / pci_unmap pair
+To: stable@kernel.org
+Cc: Andrew Morton <akpm@linux-foundation.org>, Marcus Sundberg <marcus@ingate.com>, Jeff Garzik <jgarzik@redhat.com>
+Message-ID: <20080828205533.GA599@electric-eye.fr.zoreil.com>
+
+From: Francois Romieu <romieu@fr.zoreil.com>
+
+commit a866bbf6aacf95f849810079442a20be118ce905 upstream
+
+The leak hurts with swiotlb and jumbo frames.
+
+Fix http://bugzilla.kernel.org/show_bug.cgi?id=9468.
+
+Heavily hinted by Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>.
+
+Signed-off-by: Francois Romieu <romieu@fr.zoreil.com>
+Tested-by: Alistair John Strachan <alistair@devzero.co.uk>
+Tested-by: Timothy J Fontaine <tjfontaine@atxconsulting.com>
+Cc: Edward Hsu <edward_hsu@realtek.com.tw>
+Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/net/r8169.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/r8169.c
++++ b/drivers/net/r8169.c
+@@ -2822,7 +2822,7 @@ static int rtl8169_rx_interrupt(struct n
+ pkt_size, PCI_DMA_FROMDEVICE);
+ rtl8169_mark_to_asic(desc, tp->rx_buf_sz);
+ } else {
+- pci_unmap_single(pdev, addr, pkt_size,
++ pci_unmap_single(pdev, addr, tp->rx_buf_sz,
+ PCI_DMA_FROMDEVICE);
+ tp->Rx_skbuff[entry] = NULL;
+ }
--- /dev/null
+x86-work-around-mtrr-mask-setting.patch
+usb-cdc-acm-don-t-unlock-acm-mutex-on-error-path.patch
+sunrpc-fix-possible-overrun-on-read-of-proc-sys-sunrpc-transports.patch
+r8169-balance-pci_map-pci_unmap-pair.patch
+nfsd-fix-buffer-overrun-decoding-nfsv4-acl.patch
+mm-make-setup_zone_migrate_reserve-aware-of-overlapping-nodes.patch
+forcedeth-fix-checksum-flag.patch
+fbdefio-add-set_page_dirty-handler-to-deferred-io-fb.patch
+crypto-authenc-avoid-using-clobbered-request-pointer.patch
+cramfs-fix-named-pipe-handling.patch
+cifs-fix-o_append-on-directio-mounts.patch
+0007-sctp-fix-potential-panics-in-the-SCTP-AUTH-API.patch
+0008-sctp-add-verification-checks-to-SCTP_AUTH_KEY-optio.patch
+0011-sctp-correct-bounds-check-in-sctp_setsockopt_auth_k.patch
+0012-sctp-fix-random-memory-dereference-with-SCTP_HMAC_I.patch
--- /dev/null
+From bfields@citi.umich.edu Wed Sep 3 09:39:03 2008
+From: Cyrill Gorcunov <gorcunov@gmail.com>
+Date: Mon, 1 Sep 2008 14:51:01 -0400
+Subject: sunrpc: fix possible overrun on read of /proc/sys/sunrpc/transports
+To: stable@kernel.org
+Cc: linux-nfs@vger.kernel.org, Greg Banks <gnb@sgi.com>, Neil Brown <neilb@suse.de>, "J. Bruce Fields" <bfields@citi.umich.edu>, linux-kernel@vger.kernel.org, Tom Tucker <tom@opengridcomputing.com>, Ingo Oeser <ioe-lkml@rameria.de>, Cyrill Gorcunov <gorcunov@gmail.com>, Chuck Lever <chuck.lever@oracle.com>
+Message-ID: <1220295062-10957-1-git-send-email-bfields@citi.umich.edu>
+
+
+From: Cyrill Gorcunov <gorcunov@gmail.com>
+
+commit 27df6f25ff218072e0e879a96beeb398a79cdbc8 upstream
+
+Vegard Nossum reported
+----------------------
+> I noticed that something weird is going on with /proc/sys/sunrpc/transports.
+> This file is generated in net/sunrpc/sysctl.c, function proc_do_xprt(). When
+> I "cat" this file, I get the expected output:
+> $ cat /proc/sys/sunrpc/transports
+> tcp 1048576
+> udp 32768
+
+> But I think that it does not check the length of the buffer supplied by
+> userspace to read(). With my original program, I found that the stack was
+> being overwritten by the characters above, even when the length given to
+> read() was just 1.
+
+David Wagner added (among other things) that copy_to_user could be
+probably used here.
+
+Ingo Oeser suggested to use simple_read_from_buffer() here.
+
+The conclusion is that proc_do_xprt doesn't check for userside buffer
+size indeed so fix this by using Ingo's suggestion.
+
+Reported-by: Vegard Nossum <vegard.nossum@gmail.com>
+Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com>
+CC: Ingo Oeser <ioe-lkml@rameria.de>
+Cc: Neil Brown <neilb@suse.de>
+Cc: Chuck Lever <chuck.lever@oracle.com>
+Cc: Greg Banks <gnb@sgi.com>
+Cc: Tom Tucker <tom@opengridcomputing.com>
+Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ net/sunrpc/sysctl.c | 18 ++++--------------
+ 1 file changed, 4 insertions(+), 14 deletions(-)
+
+--- a/net/sunrpc/sysctl.c
++++ b/net/sunrpc/sysctl.c
+@@ -60,24 +60,14 @@ static int proc_do_xprt(ctl_table *table
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+ {
+ char tmpbuf[256];
+- int len;
++ size_t len;
++
+ if ((*ppos && !write) || !*lenp) {
+ *lenp = 0;
+ return 0;
+ }
+- if (write)
+- return -EINVAL;
+- else {
+- len = svc_print_xprts(tmpbuf, sizeof(tmpbuf));
+- if (!access_ok(VERIFY_WRITE, buffer, len))
+- return -EFAULT;
+-
+- if (__copy_to_user(buffer, tmpbuf, len))
+- return -EFAULT;
+- }
+- *lenp -= len;
+- *ppos += len;
+- return 0;
++ len = svc_print_xprts(tmpbuf, sizeof(tmpbuf));
++ return simple_read_from_buffer(buffer, *lenp, ppos, tmpbuf, len);
+ }
+
+ static int
--- /dev/null
+From jejb@kernel.org Tue Sep 2 17:13:12 2008
+From: Alexey Dobriyan <adobriyan@gmail.com>
+Date: Fri, 22 Aug 2008 17:40:10 GMT
+Subject: USB: cdc-acm: don't unlock acm->mutex on error path
+To: jejb@kernel.org, stable@kernel.org
+Message-ID: <200808221740.m7MHeAea013780@hera.kernel.org>
+
+From: Alexey Dobriyan <adobriyan@gmail.com>
+
+commit 74573ee7096a4ffc2f098108d21c85801b9c7434 upstream
+
+On Wed, Jul 23, 2008 at 03:52:36PM +0300, Andrei Popa wrote:
+> I installed gnokii-0.6.22-r2 and gave the command "gnokii --identify"
+> and the kernel oopsed:
+>
+> BUG: unable to handle kernel NULL pointer dereference at 00000458
+> IP: [<c0444b52>] mutex_unlock+0x0/0xb
+> [<c03830ae>] acm_tty_open+0x4c/0x214
+
+Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
+Tested-by: Andrei Popa <andrei.popa@i-neo.ro>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/class/cdc-acm.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/usb/class/cdc-acm.c
++++ b/drivers/usb/class/cdc-acm.c
+@@ -531,8 +531,8 @@ static int acm_tty_open(struct tty_struc
+ tasklet_schedule(&acm->urb_task);
+
+ done:
+-err_out:
+ mutex_unlock(&acm->mutex);
++err_out:
+ mutex_unlock(&open_mutex);
+ return rv;
+
--- /dev/null
+From jejb@kernel.org Tue Sep 2 17:14:12 2008
+From: Yinghai Lu <yhlu.kernel@gmail.com>
+Date: Fri, 22 Aug 2008 17:40:05 GMT
+Subject: x86: work around MTRR mask setting
+To: jejb@kernel.org, stable@kernel.org
+Message-ID: <200808221740.m7MHe5ud013727@hera.kernel.org>
+
+From: Yinghai Lu <yhlu.kernel@gmail.com>
+
+commit 38cc1c3df77c1bb739a4766788eb9fa49f16ffdf upstream
+
+Joshua Hoblitt reported that only 3 GB of his 16 GB of RAM is
+usable. Booting with mtrr_show showed us the BIOS-initialized
+MTRR settings - which are all wrong.
+
+So the root cause is that the BIOS has not set the mask correctly:
+
+> [ 0.429971] MSR00000200: 00000000d0000000
+> [ 0.433305] MSR00000201: 0000000ff0000800
+> should be ==> [ 0.433305] MSR00000201: 0000003ff0000800
+>
+> [ 0.436638] MSR00000202: 00000000e0000000
+> [ 0.439971] MSR00000203: 0000000fe0000800
+> should be ==> [ 0.439971] MSR00000203: 0000003fe0000800
+>
+> [ 0.443304] MSR00000204: 0000000000000006
+> [ 0.446637] MSR00000205: 0000000c00000800
+> should be ==> [ 0.446637] MSR00000205: 0000003c00000800
+>
+> [ 0.449970] MSR00000206: 0000000400000006
+> [ 0.453303] MSR00000207: 0000000fe0000800
+> should be ==> [ 0.453303] MSR00000207: 0000003fe0000800
+>
+> [ 0.456636] MSR00000208: 0000000420000006
+> [ 0.459970] MSR00000209: 0000000ff0000800
+> should be ==> [ 0.459970] MSR00000209: 0000003ff0000800
+
+So detect this borkage and add the prefix 111.
+
+Signed-off-by: Yinghai Lu <yhlu.kernel@gmail.com>
+Signed-off-by: Ingo Molnar <mingo@elte.hu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/x86/kernel/cpu/mtrr/generic.c | 15 +++++++++++++--
+ 1 file changed, 13 insertions(+), 2 deletions(-)
+
+--- a/arch/x86/kernel/cpu/mtrr/generic.c
++++ b/arch/x86/kernel/cpu/mtrr/generic.c
+@@ -229,6 +229,7 @@ static void generic_get_mtrr(unsigned in
+ unsigned long *size, mtrr_type *type)
+ {
+ unsigned int mask_lo, mask_hi, base_lo, base_hi;
++ unsigned int tmp, hi;
+
+ rdmsr(MTRRphysMask_MSR(reg), mask_lo, mask_hi);
+ if ((mask_lo & 0x800) == 0) {
+@@ -242,8 +243,18 @@ static void generic_get_mtrr(unsigned in
+ rdmsr(MTRRphysBase_MSR(reg), base_lo, base_hi);
+
+ /* Work out the shifted address mask. */
+- mask_lo = size_or_mask | mask_hi << (32 - PAGE_SHIFT)
+- | mask_lo >> PAGE_SHIFT;
++ tmp = mask_hi << (32 - PAGE_SHIFT) | mask_lo >> PAGE_SHIFT;
++ mask_lo = size_or_mask | tmp;
++ /* Expand tmp with high bits to all 1s*/
++ hi = fls(tmp);
++ if (hi > 0) {
++ tmp |= ~((1<<(hi - 1)) - 1);
++
++ if (tmp != mask_lo) {
++ WARN_ON("mtrr: your BIOS has set up an incorrect mask, fixing it up.\n");
++ mask_lo = tmp;
++ }
++ }
+
+ /* This works correctly if size is a power of two, i.e. a
+ contiguous range. */