--- /dev/null
+From 5eb02c01bd1f3ef195989ab05e835e2b0711b5a9 Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Thu, 21 Feb 2013 16:44:04 -0800
+Subject: drivers/video/backlight/adp88?0_bl.c: fix resume
+
+From: Lars-Peter Clausen <lars@metafoo.de>
+
+commit 5eb02c01bd1f3ef195989ab05e835e2b0711b5a9 upstream.
+
+Clearing the NSTBY bit in the control register also automatically clears
+the BLEN bit. So we need to make sure to set it again during resume,
+otherwise the backlight will stay off.
+
+Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
+Acked-by: Michael Hennerich <michael.hennerich@analog.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@linuxfoundation.org>
+
+---
+ drivers/video/backlight/adp8860_bl.c | 2 +-
+ drivers/video/backlight/adp8870_bl.c | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/video/backlight/adp8860_bl.c
++++ b/drivers/video/backlight/adp8860_bl.c
+@@ -793,7 +793,7 @@ static int adp8860_i2c_suspend(struct i2
+
+ static int adp8860_i2c_resume(struct i2c_client *client)
+ {
+- adp8860_set_bits(client, ADP8860_MDCR, NSTBY);
++ adp8860_set_bits(client, ADP8860_MDCR, NSTBY | BLEN);
+
+ return 0;
+ }
+--- a/drivers/video/backlight/adp8870_bl.c
++++ b/drivers/video/backlight/adp8870_bl.c
+@@ -968,7 +968,7 @@ static int adp8870_i2c_suspend(struct i2
+
+ static int adp8870_i2c_resume(struct i2c_client *client)
+ {
+- adp8870_set_bits(client, ADP8870_MDCR, NSTBY);
++ adp8870_set_bits(client, ADP8870_MDCR, NSTBY | BLEN);
+
+ return 0;
+ }
--- /dev/null
+From 676a0675cf9200ac047fb50825f80867b3bb733b Mon Sep 17 00:00:00 2001
+From: Jim Somerville <Jim.Somerville@windriver.com>
+Date: Thu, 21 Feb 2013 16:41:59 -0800
+Subject: inotify: remove broken mask checks causing unmount to be EINVAL
+
+From: Jim Somerville <Jim.Somerville@windriver.com>
+
+commit 676a0675cf9200ac047fb50825f80867b3bb733b upstream.
+
+Running the command:
+
+ inotifywait -e unmount /mnt/disk
+
+immediately aborts with a -EINVAL return code. This is however a valid
+parameter. This abort occurs only if unmount is the sole event
+parameter. If other event parameters are supplied, then the unmount
+event wait will work.
+
+The problem was introduced by commit 44b350fc23e ("inotify: Fix mask
+checks"). In that commit, it states:
+
+ The mask checks in inotify_update_existing_watch() and
+ inotify_new_watch() are useless because inotify_arg_to_mask()
+ sets FS_IN_IGNORED and FS_EVENT_ON_CHILD bits anyway.
+
+But instead of removing the useless checks, it did this:
+
+ mask = inotify_arg_to_mask(arg);
+ - if (unlikely(!mask))
+ + if (unlikely(!(mask & IN_ALL_EVENTS)))
+ return -EINVAL;
+
+The problem is that IN_ALL_EVENTS doesn't include IN_UNMOUNT, and other
+parts of the code keep IN_UNMOUNT separate from IN_ALL_EVENTS. So the
+check should be:
+
+ if (unlikely(!(mask & (IN_ALL_EVENTS | IN_UNMOUNT))))
+
+But inotify_arg_to_mask(arg) always sets the IN_UNMOUNT bit in the mask
+anyway, so the check is always going to pass and thus should simply be
+removed. Also note that inotify_arg_to_mask completely controls what
+mask bits get set from arg, there's no way for invalid bits to get
+enabled there.
+
+Lets fix it by simply removing the useless broken checks.
+
+Signed-off-by: Jim Somerville <Jim.Somerville@windriver.com>
+Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
+Cc: Jerome Marchand <jmarchan@redhat.com>
+Cc: John McCutchan <john@johnmccutchan.com>
+Cc: Robert Love <rlove@rlove.org>
+Cc: Eric Paris <eparis@parisplace.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@linuxfoundation.org>
+
+---
+ fs/notify/inotify/inotify_user.c | 4 ----
+ 1 file changed, 4 deletions(-)
+
+--- a/fs/notify/inotify/inotify_user.c
++++ b/fs/notify/inotify/inotify_user.c
+@@ -579,8 +579,6 @@ static int inotify_update_existing_watch
+
+ /* don't allow invalid bits: we don't want flags set */
+ mask = inotify_arg_to_mask(arg);
+- if (unlikely(!(mask & IN_ALL_EVENTS)))
+- return -EINVAL;
+
+ fsn_mark = fsnotify_find_inode_mark(group, inode);
+ if (!fsn_mark)
+@@ -632,8 +630,6 @@ static int inotify_new_watch(struct fsno
+
+ /* don't allow invalid bits: we don't want flags set */
+ mask = inotify_arg_to_mask(arg);
+- if (unlikely(!(mask & IN_ALL_EVENTS)))
+- return -EINVAL;
+
+ tmp_i_mark = kmem_cache_alloc(inotify_inode_mark_cachep, GFP_KERNEL);
+ if (unlikely(!tmp_i_mark))
--- /dev/null
+From 55c171a6d90dc0574021f9c836127cfd1a7d2e30 Mon Sep 17 00:00:00 2001
+From: Cornelia Huck <cornelia.huck@de.ibm.com>
+Date: Fri, 14 Dec 2012 17:02:16 +0100
+Subject: KVM: s390: Handle hosts not supporting s390-virtio.
+
+From: Cornelia Huck <cornelia.huck@de.ibm.com>
+
+commit 55c171a6d90dc0574021f9c836127cfd1a7d2e30 upstream.
+
+Running under a kvm host does not necessarily imply the presence of
+a page mapped above the main memory with the virtio information;
+however, the code includes a hard coded access to that page.
+
+Instead, check for the presence of the page and exit gracefully
+before we hit an addressing exception if it does not exist.
+
+Reviewed-by: Marcelo Tosatti <mtosatti@redhat.com>
+Reviewed-by: Alexander Graf <agraf@suse.de>
+Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
+Signed-off-by: Gleb Natapov <gleb@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/s390/kvm/kvm_virtio.c | 38 ++++++++++++++++++++++++++++++--------
+ 1 file changed, 30 insertions(+), 8 deletions(-)
+
+--- a/drivers/s390/kvm/kvm_virtio.c
++++ b/drivers/s390/kvm/kvm_virtio.c
+@@ -413,6 +413,26 @@ static void kvm_extint_handler(unsigned
+ }
+
+ /*
++ * For s390-virtio, we expect a page above main storage containing
++ * the virtio configuration. Try to actually load from this area
++ * in order to figure out if the host provides this page.
++ */
++static int __init test_devices_support(unsigned long addr)
++{
++ int ret = -EIO;
++
++ asm volatile(
++ "0: lura 0,%1\n"
++ "1: xgr %0,%0\n"
++ "2:\n"
++ EX_TABLE(0b,2b)
++ EX_TABLE(1b,2b)
++ : "+d" (ret)
++ : "a" (addr)
++ : "0", "cc");
++ return ret;
++}
++/*
+ * Init function for virtio
+ * devices are in a single page above top of "normal" mem
+ */
+@@ -423,21 +443,23 @@ static int __init kvm_devices_init(void)
+ if (!MACHINE_IS_KVM)
+ return -ENODEV;
+
++ if (test_devices_support(real_memory_size) < 0)
++ return -ENODEV;
++
++ rc = vmem_add_mapping(real_memory_size, PAGE_SIZE);
++ if (rc)
++ return rc;
++
++ kvm_devices = (void *) real_memory_size;
++
+ kvm_root = root_device_register("kvm_s390");
+ if (IS_ERR(kvm_root)) {
+ rc = PTR_ERR(kvm_root);
+ printk(KERN_ERR "Could not register kvm_s390 root device");
++ vmem_remove_mapping(real_memory_size, PAGE_SIZE);
+ return rc;
+ }
+
+- rc = vmem_add_mapping(real_memory_size, PAGE_SIZE);
+- if (rc) {
+- root_device_unregister(kvm_root);
+- return rc;
+- }
+-
+- kvm_devices = (void *) real_memory_size;
+-
+ INIT_WORK(&hotplug_work, hotplug_devices);
+
+ service_subclass_irq_register();
--- /dev/null
+From 67d46b296a1ba1477c0df8ff3bc5e0167a0b0732 Mon Sep 17 00:00:00 2001
+From: Mel Gorman <mgorman@suse.de>
+Date: Fri, 22 Feb 2013 16:35:59 -0800
+Subject: mm/fadvise.c: drain all pagevecs if POSIX_FADV_DONTNEED fails to discard all pages
+
+From: Mel Gorman <mgorman@suse.de>
+
+commit 67d46b296a1ba1477c0df8ff3bc5e0167a0b0732 upstream.
+
+Rob van der Heij reported the following (paraphrased) on private mail.
+
+ The scenario is that I want to avoid backups to fill up the page
+ cache and purge stuff that is more likely to be used again (this is
+ with s390x Linux on z/VM, so I don't give it as much memory that
+ we don't care anymore). So I have something with LD_PRELOAD that
+ intercepts the close() call (from tar, in this case) and issues
+ a posix_fadvise() just before closing the file.
+
+ This mostly works, except for small files (less than 14 pages)
+ that remains in page cache after the face.
+
+Unfortunately Rob has not had a chance to test this exact patch but the
+test program below should be reproducing the problem he described.
+
+The issue is the per-cpu pagevecs for LRU additions. If the pages are
+added by one CPU but fadvise() is called on another then the pages
+remain resident as the invalidate_mapping_pages() only drains the local
+pagevecs via its call to pagevec_release(). The user-visible effect is
+that a program that uses fadvise() properly is not obeyed.
+
+A possible fix for this is to put the necessary smarts into
+invalidate_mapping_pages() to globally drain the LRU pagevecs if a
+pagevec page could not be discarded. The downside with this is that an
+inode cache shrink would send a global IPI and memory pressure
+potentially causing global IPI storms is very undesirable.
+
+Instead, this patch adds a check during fadvise(POSIX_FADV_DONTNEED) to
+check if invalidate_mapping_pages() discarded all the requested pages.
+If a subset of pages are discarded it drains the LRU pagevecs and tries
+again. If the second attempt fails, it assumes it is due to the pages
+being mapped, locked or dirty and does not care. With this patch, an
+application using fadvise() correctly will be obeyed but there is a
+downside that a malicious application can force the kernel to send
+global IPIs and increase overhead.
+
+If accepted, I would like this to be considered as a -stable candidate.
+It's not an urgent issue but it's a system call that is not working as
+advertised which is weak.
+
+The following test program demonstrates the problem. It should never
+report that pages are still resident but will without this patch. It
+assumes that CPU 0 and 1 exist.
+
+int main() {
+ int fd;
+ int pagesize = getpagesize();
+ ssize_t written = 0, expected;
+ char *buf;
+ unsigned char *vec;
+ int resident, i;
+ cpu_set_t set;
+
+ /* Prepare a buffer for writing */
+ expected = FILESIZE_PAGES * pagesize;
+ buf = malloc(expected + 1);
+ if (buf == NULL) {
+ printf("ENOMEM\n");
+ exit(EXIT_FAILURE);
+ }
+ buf[expected] = 0;
+ memset(buf, 'a', expected);
+
+ /* Prepare the mincore vec */
+ vec = malloc(FILESIZE_PAGES);
+ if (vec == NULL) {
+ printf("ENOMEM\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Bind ourselves to CPU 0 */
+ CPU_ZERO(&set);
+ CPU_SET(0, &set);
+ if (sched_setaffinity(getpid(), sizeof(set), &set) == -1) {
+ perror("sched_setaffinity");
+ exit(EXIT_FAILURE);
+ }
+
+ /* open file, unlink and write buffer */
+ fd = open("fadvise-test-file", O_CREAT|O_EXCL|O_RDWR);
+ if (fd == -1) {
+ perror("open");
+ exit(EXIT_FAILURE);
+ }
+ unlink("fadvise-test-file");
+ while (written < expected) {
+ ssize_t this_write;
+ this_write = write(fd, buf + written, expected - written);
+
+ if (this_write == -1) {
+ perror("write");
+ exit(EXIT_FAILURE);
+ }
+
+ written += this_write;
+ }
+ free(buf);
+
+ /*
+ * Force ourselves to another CPU. If fadvise only flushes the local
+ * CPUs pagevecs then the fadvise will fail to discard all file pages
+ */
+ CPU_ZERO(&set);
+ CPU_SET(1, &set);
+ if (sched_setaffinity(getpid(), sizeof(set), &set) == -1) {
+ perror("sched_setaffinity");
+ exit(EXIT_FAILURE);
+ }
+
+ /* sync and fadvise to discard the page cache */
+ fsync(fd);
+ if (posix_fadvise(fd, 0, expected, POSIX_FADV_DONTNEED) == -1) {
+ perror("posix_fadvise");
+ exit(EXIT_FAILURE);
+ }
+
+ /* map the file and use mincore to see which parts of it are resident */
+ buf = mmap(NULL, expected, PROT_READ, MAP_SHARED, fd, 0);
+ if (buf == NULL) {
+ perror("mmap");
+ exit(EXIT_FAILURE);
+ }
+ if (mincore(buf, expected, vec) == -1) {
+ perror("mincore");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Check residency */
+ for (i = 0, resident = 0; i < FILESIZE_PAGES; i++) {
+ if (vec[i])
+ resident++;
+ }
+ if (resident != 0) {
+ printf("Nr unexpected pages resident: %d\n", resident);
+ exit(EXIT_FAILURE);
+ }
+
+ munmap(buf, expected);
+ close(fd);
+ free(vec);
+ exit(EXIT_SUCCESS);
+}
+
+Signed-off-by: Mel Gorman <mgorman@suse.de>
+Reported-by: Rob van der Heij <rvdheij@gmail.com>
+Tested-by: Rob van der Heij <rvdheij@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@linuxfoundation.org>
+
+---
+ mm/fadvise.c | 18 ++++++++++++++++--
+ 1 file changed, 16 insertions(+), 2 deletions(-)
+
+--- a/mm/fadvise.c
++++ b/mm/fadvise.c
+@@ -17,6 +17,7 @@
+ #include <linux/fadvise.h>
+ #include <linux/writeback.h>
+ #include <linux/syscalls.h>
++#include <linux/swap.h>
+
+ #include <asm/unistd.h>
+
+@@ -123,9 +124,22 @@ SYSCALL_DEFINE(fadvise64_64)(int fd, lof
+ start_index = (offset+(PAGE_CACHE_SIZE-1)) >> PAGE_CACHE_SHIFT;
+ end_index = (endbyte >> PAGE_CACHE_SHIFT);
+
+- if (end_index >= start_index)
+- invalidate_mapping_pages(mapping, start_index,
++ if (end_index >= start_index) {
++ unsigned long count = invalidate_mapping_pages(mapping,
++ start_index, end_index);
++
++ /*
++ * If fewer pages were invalidated than expected then
++ * it is possible that some of the pages were on
++ * a per-cpu pagevec for a remote CPU. Drain all
++ * pagevecs and try again.
++ */
++ if (count < (end_index - start_index + 1)) {
++ lru_add_drain_all();
++ invalidate_mapping_pages(mapping, start_index,
+ end_index);
++ }
++ }
+ break;
+ default:
+ ret = -EINVAL;
--- /dev/null
+From 666b3d803a511fbc9bc5e5ea8ce66010cf03ea13 Mon Sep 17 00:00:00 2001
+From: Trond Myklebust <Trond.Myklebust@netapp.com>
+Date: Tue, 19 Feb 2013 12:04:42 -0500
+Subject: NLM: Ensure that we resend all pending blocking locks after a reclaim
+
+From: Trond Myklebust <Trond.Myklebust@netapp.com>
+
+commit 666b3d803a511fbc9bc5e5ea8ce66010cf03ea13 upstream.
+
+Currently, nlmclnt_lock will break out of the for(;;) loop when
+the reclaimer wakes up the blocking lock thread by setting
+nlm_lck_denied_grace_period. This causes the lock request to fail
+with an ENOLCK error.
+The intention was always to ensure that we resend the lock request
+after the grace period has expired.
+
+Reported-by: Wangyuan Zhang <Wangyuan.Zhang@netapp.com>
+Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/lockd/clntproc.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/fs/lockd/clntproc.c
++++ b/fs/lockd/clntproc.c
+@@ -550,6 +550,9 @@ again:
+ status = nlmclnt_block(block, req, NLMCLNT_POLL_TIMEOUT);
+ if (status < 0)
+ break;
++ /* Resend the blocking lock request after a server reboot */
++ if (resp->status == nlm_lck_denied_grace_period)
++ continue;
+ if (resp->status != nlm_lck_blocked)
+ break;
+ }
--- /dev/null
+From 3278bb748d2437eb1464765f36429e5d6aa91c38 Mon Sep 17 00:00:00 2001
+From: Junxiao Bi <junxiao.bi@oracle.com>
+Date: Thu, 21 Feb 2013 16:42:45 -0800
+Subject: ocfs2: unlock super lock if lockres refresh failed
+
+From: Junxiao Bi <junxiao.bi@oracle.com>
+
+commit 3278bb748d2437eb1464765f36429e5d6aa91c38 upstream.
+
+If lockres refresh failed, the super lock will never be released which
+will cause some processes on other cluster nodes hung forever.
+
+Signed-off-by: Junxiao Bi <junxiao.bi@oracle.com>
+Cc: Joel Becker <jlbec@evilplan.org>
+Cc: Mark Fasheh <mfasheh@suse.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@linuxfoundation.org>
+
+---
+ fs/ocfs2/dlmglue.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/fs/ocfs2/dlmglue.c
++++ b/fs/ocfs2/dlmglue.c
+@@ -2539,6 +2539,7 @@ int ocfs2_super_lock(struct ocfs2_super
+ * everything is up to the caller :) */
+ status = ocfs2_should_refresh_lock_res(lockres);
+ if (status < 0) {
++ ocfs2_cluster_unlock(osb, lockres, level);
+ mlog_errno(status);
+ goto bail;
+ }
+@@ -2547,8 +2548,10 @@ int ocfs2_super_lock(struct ocfs2_super
+
+ ocfs2_complete_lock_res_refresh(lockres, status);
+
+- if (status < 0)
++ if (status < 0) {
++ ocfs2_cluster_unlock(osb, lockres, level);
+ mlog_errno(status);
++ }
+ ocfs2_track_lock_refresh(lockres);
+ }
+ bail:
--- /dev/null
+From 15bc8d8457875f495c59d933b05770ba88d1eacb Mon Sep 17 00:00:00 2001
+From: Christian Borntraeger <borntraeger@de.ibm.com>
+Date: Fri, 25 Jan 2013 15:34:15 +0100
+Subject: s390/kvm: Fix store status for ACRS/FPRS
+
+From: Christian Borntraeger <borntraeger@de.ibm.com>
+
+commit 15bc8d8457875f495c59d933b05770ba88d1eacb upstream.
+
+On store status we need to copy the current state of registers
+into a save area. Currently we might save stale versions:
+The sie state descriptor doesnt have fields for guest ACRS,FPRS,
+those registers are simply stored in the host registers. The host
+program must copy these away if needed. We do that in vcpu_put/load.
+
+If we now do a store status in KVM code between vcpu_put/load, the
+saved values are not up-to-date. Lets collect the ACRS/FPRS before
+saving them.
+
+This also fixes some strange problems with hotplug and virtio-ccw,
+since the low level machine check handler (on hotplug a machine check
+will happen) will revalidate all registers with the content of the
+save area.
+
+Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
+Signed-off-by: Gleb Natapov <gleb@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/s390/kvm/kvm-s390.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/arch/s390/kvm/kvm-s390.c
++++ b/arch/s390/kvm/kvm-s390.c
+@@ -584,6 +584,14 @@ int kvm_s390_vcpu_store_status(struct kv
+ } else
+ prefix = 0;
+
++ /*
++ * The guest FPRS and ACRS are in the host FPRS/ACRS due to the lazy
++ * copying in vcpu load/put. Lets update our copies before we save
++ * it into the save area
++ */
++ save_fp_regs(&vcpu->arch.guest_fpregs);
++ save_access_regs(vcpu->run->s.regs.acrs);
++
+ if (__guestcopy(vcpu, addr + offsetof(struct save_area, fp_regs),
+ vcpu->arch.guest_fpregs.fprs, 128, prefix))
+ return -EFAULT;
mm-mmu_notifier-have-mmu_notifiers-use-a-global-srcu-so-they-may-safely-schedule.patch
mm-mmu_notifier-make-the-mmu_notifier-srcu-static.patch
mmu_notifier_unregister-null-pointer-deref-and-multiple-release-callouts.patch
+kvm-s390-handle-hosts-not-supporting-s390-virtio.patch
+s390-kvm-fix-store-status-for-acrs-fprs.patch
+inotify-remove-broken-mask-checks-causing-unmount-to-be-einval.patch
+ocfs2-unlock-super-lock-if-lockres-refresh-failed.patch
+drivers-video-backlight-adp88-0_bl.c-fix-resume.patch
+tmpfs-fix-use-after-free-of-mempolicy-object.patch
+mm-fadvise.c-drain-all-pagevecs-if-posix_fadv_dontneed-fails-to-discard-all-pages.patch
+nlm-ensure-that-we-resend-all-pending-blocking-locks-after-a-reclaim.patch
--- /dev/null
+From 5f00110f7273f9ff04ac69a5f85bb535a4fd0987 Mon Sep 17 00:00:00 2001
+From: Greg Thelen <gthelen@google.com>
+Date: Fri, 22 Feb 2013 16:36:01 -0800
+Subject: tmpfs: fix use-after-free of mempolicy object
+
+From: Greg Thelen <gthelen@google.com>
+
+commit 5f00110f7273f9ff04ac69a5f85bb535a4fd0987 upstream.
+
+The tmpfs remount logic preserves filesystem mempolicy if the mpol=M
+option is not specified in the remount request. A new policy can be
+specified if mpol=M is given.
+
+Before this patch remounting an mpol bound tmpfs without specifying
+mpol= mount option in the remount request would set the filesystem's
+mempolicy object to a freed mempolicy object.
+
+To reproduce the problem boot a DEBUG_PAGEALLOC kernel and run:
+ # mkdir /tmp/x
+
+ # mount -t tmpfs -o size=100M,mpol=interleave nodev /tmp/x
+
+ # grep /tmp/x /proc/mounts
+ nodev /tmp/x tmpfs rw,relatime,size=102400k,mpol=interleave:0-3 0 0
+
+ # mount -o remount,size=200M nodev /tmp/x
+
+ # grep /tmp/x /proc/mounts
+ nodev /tmp/x tmpfs rw,relatime,size=204800k,mpol=??? 0 0
+ # note ? garbage in mpol=... output above
+
+ # dd if=/dev/zero of=/tmp/x/f count=1
+ # panic here
+
+Panic:
+ BUG: unable to handle kernel NULL pointer dereference at (null)
+ IP: [< (null)>] (null)
+ [...]
+ Oops: 0010 [#1] SMP DEBUG_PAGEALLOC
+ Call Trace:
+ mpol_shared_policy_init+0xa5/0x160
+ shmem_get_inode+0x209/0x270
+ shmem_mknod+0x3e/0xf0
+ shmem_create+0x18/0x20
+ vfs_create+0xb5/0x130
+ do_last+0x9a1/0xea0
+ path_openat+0xb3/0x4d0
+ do_filp_open+0x42/0xa0
+ do_sys_open+0xfe/0x1e0
+ compat_sys_open+0x1b/0x20
+ cstar_dispatch+0x7/0x1f
+
+Non-debug kernels will not crash immediately because referencing the
+dangling mpol will not cause a fault. Instead the filesystem will
+reference a freed mempolicy object, which will cause unpredictable
+behavior.
+
+The problem boils down to a dropped mpol reference below if
+shmem_parse_options() does not allocate a new mpol:
+
+ config = *sbinfo
+ shmem_parse_options(data, &config, true)
+ mpol_put(sbinfo->mpol)
+ sbinfo->mpol = config.mpol /* BUG: saves unreferenced mpol */
+
+This patch avoids the crash by not releasing the mempolicy if
+shmem_parse_options() doesn't create a new mpol.
+
+How far back does this issue go? I see it in both 2.6.36 and 3.3. I did
+not look back further.
+
+Signed-off-by: Greg Thelen <gthelen@google.com>
+Acked-by: Hugh Dickins <hughd@google.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ mm/shmem.c | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+--- a/mm/shmem.c
++++ b/mm/shmem.c
+@@ -2505,6 +2505,7 @@ static int shmem_remount_fs(struct super
+ unsigned long inodes;
+ int error = -EINVAL;
+
++ config.mpol = NULL;
+ if (shmem_parse_options(data, &config, true))
+ return error;
+
+@@ -2530,8 +2531,13 @@ static int shmem_remount_fs(struct super
+ sbinfo->max_inodes = config.max_inodes;
+ sbinfo->free_inodes = config.max_inodes - inodes;
+
+- mpol_put(sbinfo->mpol);
+- sbinfo->mpol = config.mpol; /* transfers initial ref */
++ /*
++ * Preserve previous mempolicy unless mpol remount option was specified.
++ */
++ if (config.mpol) {
++ mpol_put(sbinfo->mpol);
++ sbinfo->mpol = config.mpol; /* transfers initial ref */
++ }
+ out:
+ spin_unlock(&sbinfo->stat_lock);
+ return error;