]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 27 Sep 2016 14:27:55 +0000 (16:27 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 27 Sep 2016 14:27:55 +0000 (16:27 +0200)
added patches:
autofs-races.patch
autofs-use-dentry-flags-to-block-walks-during-expire.patch
hrtimer-add-support-for-clock_monotonic_raw.patch
xfs-prevent-dropping-ioend-completions-during-buftarg-wait.patch

queue-4.4/autofs-races.patch [new file with mode: 0644]
queue-4.4/autofs-use-dentry-flags-to-block-walks-during-expire.patch [new file with mode: 0644]
queue-4.4/hrtimer-add-support-for-clock_monotonic_raw.patch [new file with mode: 0644]
queue-4.4/series
queue-4.4/xfs-prevent-dropping-ioend-completions-during-buftarg-wait.patch [new file with mode: 0644]

diff --git a/queue-4.4/autofs-races.patch b/queue-4.4/autofs-races.patch
new file mode 100644 (file)
index 0000000..1cfada6
--- /dev/null
@@ -0,0 +1,154 @@
+From ea01a18494b3d7a91b2f1f2a6a5aaef4741bc294 Mon Sep 17 00:00:00 2001
+From: Al Viro <viro@zeniv.linux.org.uk>
+Date: Sun, 12 Jun 2016 11:24:46 -0400
+Subject: autofs races
+
+From: Al Viro <viro@zeniv.linux.org.uk>
+
+commit ea01a18494b3d7a91b2f1f2a6a5aaef4741bc294 upstream.
+
+* make autofs4_expire_indirect() skip the dentries being in process of
+expiry
+* do *not* mess with list_move(); making sure that dentry with
+AUTOFS_INF_EXPIRING are not picked for expiry is enough.
+* do not remove NO_RCU when we set EXPIRING, don't bother with smp_mb()
+there.  Clear it at the same time we clear EXPIRING.  Makes a bunch of
+tests simpler.
+* rename NO_RCU to WANT_EXPIRE, which is what it really is.
+
+Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
+Cc: Ian Kent <raven@themaw.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+
+---
+ fs/autofs4/autofs_i.h |    8 ++++++--
+ fs/autofs4/expire.c   |   27 ++++++++-------------------
+ fs/autofs4/root.c     |    2 +-
+ 3 files changed, 15 insertions(+), 22 deletions(-)
+
+--- a/fs/autofs4/autofs_i.h
++++ b/fs/autofs4/autofs_i.h
+@@ -79,9 +79,13 @@ struct autofs_info {
+ };
+ #define AUTOFS_INF_EXPIRING   (1<<0) /* dentry is in the process of expiring */
+-#define AUTOFS_INF_NO_RCU     (1<<1) /* the dentry is being considered
++#define AUTOFS_INF_WANT_EXPIRE        (1<<1) /* the dentry is being considered
+                                       * for expiry, so RCU_walk is
+-                                      * not permitted
++                                      * not permitted.  If it progresses to
++                                      * actual expiry attempt, the flag is
++                                      * not cleared when EXPIRING is set -
++                                      * in that case it gets cleared only
++                                      * when it comes to clearing EXPIRING.
+                                       */
+ #define AUTOFS_INF_PENDING    (1<<2) /* dentry pending mount */
+--- a/fs/autofs4/expire.c
++++ b/fs/autofs4/expire.c
+@@ -315,19 +315,17 @@ struct dentry *autofs4_expire_direct(str
+       if (ino->flags & AUTOFS_INF_PENDING)
+               goto out;
+       if (!autofs4_direct_busy(mnt, root, timeout, do_now)) {
+-              ino->flags |= AUTOFS_INF_NO_RCU;
++              ino->flags |= AUTOFS_INF_WANT_EXPIRE;
+               spin_unlock(&sbi->fs_lock);
+               synchronize_rcu();
+               spin_lock(&sbi->fs_lock);
+               if (!autofs4_direct_busy(mnt, root, timeout, do_now)) {
+                       ino->flags |= AUTOFS_INF_EXPIRING;
+-                      smp_mb();
+-                      ino->flags &= ~AUTOFS_INF_NO_RCU;
+                       init_completion(&ino->expire_complete);
+                       spin_unlock(&sbi->fs_lock);
+                       return root;
+               }
+-              ino->flags &= ~AUTOFS_INF_NO_RCU;
++              ino->flags &= ~AUTOFS_INF_WANT_EXPIRE;
+       }
+ out:
+       spin_unlock(&sbi->fs_lock);
+@@ -444,7 +442,7 @@ struct dentry *autofs4_expire_indirect(s
+       while ((dentry = get_next_positive_subdir(dentry, root))) {
+               spin_lock(&sbi->fs_lock);
+               ino = autofs4_dentry_ino(dentry);
+-              if (ino->flags & AUTOFS_INF_NO_RCU)
++              if (ino->flags & AUTOFS_INF_WANT_EXPIRE)
+                       expired = NULL;
+               else
+                       expired = should_expire(dentry, mnt, timeout, how);
+@@ -453,7 +451,7 @@ struct dentry *autofs4_expire_indirect(s
+                       continue;
+               }
+               ino = autofs4_dentry_ino(expired);
+-              ino->flags |= AUTOFS_INF_NO_RCU;
++              ino->flags |= AUTOFS_INF_WANT_EXPIRE;
+               spin_unlock(&sbi->fs_lock);
+               synchronize_rcu();
+               spin_lock(&sbi->fs_lock);
+@@ -463,7 +461,7 @@ struct dentry *autofs4_expire_indirect(s
+                       goto found;
+               }
+-              ino->flags &= ~AUTOFS_INF_NO_RCU;
++              ino->flags &= ~AUTOFS_INF_WANT_EXPIRE;
+               if (expired != dentry)
+                       dput(expired);
+               spin_unlock(&sbi->fs_lock);
+@@ -473,17 +471,8 @@ struct dentry *autofs4_expire_indirect(s
+ found:
+       DPRINTK("returning %p %pd", expired, expired);
+       ino->flags |= AUTOFS_INF_EXPIRING;
+-      smp_mb();
+-      ino->flags &= ~AUTOFS_INF_NO_RCU;
+       init_completion(&ino->expire_complete);
+       spin_unlock(&sbi->fs_lock);
+-      spin_lock(&sbi->lookup_lock);
+-      spin_lock(&expired->d_parent->d_lock);
+-      spin_lock_nested(&expired->d_lock, DENTRY_D_LOCK_NESTED);
+-      list_move(&expired->d_parent->d_subdirs, &expired->d_child);
+-      spin_unlock(&expired->d_lock);
+-      spin_unlock(&expired->d_parent->d_lock);
+-      spin_unlock(&sbi->lookup_lock);
+       return expired;
+ }
+@@ -494,7 +483,7 @@ int autofs4_expire_wait(struct dentry *d
+       int status;
+       /* Block on any pending expire */
+-      if (!(ino->flags & (AUTOFS_INF_EXPIRING | AUTOFS_INF_NO_RCU)))
++      if (!(ino->flags & AUTOFS_INF_WANT_EXPIRE))
+               return 0;
+       if (rcu_walk)
+               return -ECHILD;
+@@ -551,7 +540,7 @@ int autofs4_expire_run(struct super_bloc
+       ino = autofs4_dentry_ino(dentry);
+       /* avoid rapid-fire expire attempts if expiry fails */
+       ino->last_used = now;
+-      ino->flags &= ~AUTOFS_INF_EXPIRING;
++      ino->flags &= ~(AUTOFS_INF_EXPIRING|AUTOFS_INF_WANT_EXPIRE);
+       complete_all(&ino->expire_complete);
+       spin_unlock(&sbi->fs_lock);
+@@ -579,7 +568,7 @@ int autofs4_do_expire_multi(struct super
+               spin_lock(&sbi->fs_lock);
+               /* avoid rapid-fire expire attempts if expiry fails */
+               ino->last_used = now;
+-              ino->flags &= ~AUTOFS_INF_EXPIRING;
++              ino->flags &= ~(AUTOFS_INF_EXPIRING|AUTOFS_INF_WANT_EXPIRE);
+               complete_all(&ino->expire_complete);
+               spin_unlock(&sbi->fs_lock);
+               dput(dentry);
+--- a/fs/autofs4/root.c
++++ b/fs/autofs4/root.c
+@@ -455,7 +455,7 @@ static int autofs4_d_manage(struct dentr
+                * a mount-trap.
+                */
+               struct inode *inode;
+-              if (ino->flags & (AUTOFS_INF_EXPIRING | AUTOFS_INF_NO_RCU))
++              if (ino->flags & AUTOFS_INF_WANT_EXPIRE)
+                       return 0;
+               if (d_mountpoint(dentry))
+                       return 0;
diff --git a/queue-4.4/autofs-use-dentry-flags-to-block-walks-during-expire.patch b/queue-4.4/autofs-use-dentry-flags-to-block-walks-during-expire.patch
new file mode 100644 (file)
index 0000000..535a40f
--- /dev/null
@@ -0,0 +1,148 @@
+From 7cbdb4a286a60c5d519cb9223fe2134d26870d39 Mon Sep 17 00:00:00 2001
+From: Ian Kent <raven@themaw.net>
+Date: Mon, 19 Sep 2016 14:44:12 -0700
+Subject: autofs: use dentry flags to block walks during expire
+
+From: Ian Kent <raven@themaw.net>
+
+commit 7cbdb4a286a60c5d519cb9223fe2134d26870d39 upstream.
+
+Somewhere along the way the autofs expire operation has changed to hold
+a spin lock over expired dentry selection.  The autofs indirect mount
+expired dentry selection is complicated and quite lengthy so it isn't
+appropriate to hold a spin lock over the operation.
+
+Commit 47be61845c77 ("fs/dcache.c: avoid soft-lockup in dput()") added a
+might_sleep() to dput() causing a WARN_ONCE() about this usage to be
+issued.
+
+But the spin lock doesn't need to be held over this check, the autofs
+dentry info.  flags are enough to block walks into dentrys during the
+expire.
+
+I've left the direct mount expire as it is (for now) because it is much
+simpler and quicker than the indirect mount expire and adding spin lock
+release and re-aquires would do nothing more than add overhead.
+
+Fixes: 47be61845c77 ("fs/dcache.c: avoid soft-lockup in dput()")
+Link: http://lkml.kernel.org/r/20160912014017.1773.73060.stgit@pluto.themaw.net
+Signed-off-by: Ian Kent <raven@themaw.net>
+Reported-by: Takashi Iwai <tiwai@suse.de>
+Tested-by: Takashi Iwai <tiwai@suse.de>
+Cc: Takashi Iwai <tiwai@suse.de>
+Cc: NeilBrown <neilb@suse.com>
+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@linuxfoundation.org>
+
+---
+ fs/autofs4/expire.c |   55 +++++++++++++++++++++++++++++++++++++++-------------
+ 1 file changed, 42 insertions(+), 13 deletions(-)
+
+--- a/fs/autofs4/expire.c
++++ b/fs/autofs4/expire.c
+@@ -415,6 +415,7 @@ static struct dentry *should_expire(stru
+       }
+       return NULL;
+ }
++
+ /*
+  * Find an eligible tree to time-out
+  * A tree is eligible if :-
+@@ -430,6 +431,7 @@ struct dentry *autofs4_expire_indirect(s
+       struct dentry *root = sb->s_root;
+       struct dentry *dentry;
+       struct dentry *expired;
++      struct dentry *found;
+       struct autofs_info *ino;
+       if (!root)
+@@ -440,31 +442,46 @@ struct dentry *autofs4_expire_indirect(s
+       dentry = NULL;
+       while ((dentry = get_next_positive_subdir(dentry, root))) {
++              int flags = how;
++
+               spin_lock(&sbi->fs_lock);
+               ino = autofs4_dentry_ino(dentry);
+-              if (ino->flags & AUTOFS_INF_WANT_EXPIRE)
+-                      expired = NULL;
+-              else
+-                      expired = should_expire(dentry, mnt, timeout, how);
+-              if (!expired) {
++              if (ino->flags & AUTOFS_INF_WANT_EXPIRE) {
+                       spin_unlock(&sbi->fs_lock);
+                       continue;
+               }
++              spin_unlock(&sbi->fs_lock);
++
++              expired = should_expire(dentry, mnt, timeout, flags);
++              if (!expired)
++                      continue;
++
++              spin_lock(&sbi->fs_lock);
+               ino = autofs4_dentry_ino(expired);
+               ino->flags |= AUTOFS_INF_WANT_EXPIRE;
+               spin_unlock(&sbi->fs_lock);
+               synchronize_rcu();
+-              spin_lock(&sbi->fs_lock);
+-              if (should_expire(expired, mnt, timeout, how)) {
+-                      if (expired != dentry)
+-                              dput(dentry);
+-                      goto found;
+-              }
++              /* Make sure a reference is not taken on found if
++               * things have changed.
++               */
++              flags &= ~AUTOFS_EXP_LEAVES;
++              found = should_expire(expired, mnt, timeout, how);
++              if (!found || found != expired)
++                      /* Something has changed, continue */
++                      goto next;
++
++              if (expired != dentry)
++                      dput(dentry);
++
++              spin_lock(&sbi->fs_lock);
++              goto found;
++next:
++              spin_lock(&sbi->fs_lock);
+               ino->flags &= ~AUTOFS_INF_WANT_EXPIRE;
++              spin_unlock(&sbi->fs_lock);
+               if (expired != dentry)
+                       dput(expired);
+-              spin_unlock(&sbi->fs_lock);
+       }
+       return NULL;
+@@ -481,6 +498,7 @@ int autofs4_expire_wait(struct dentry *d
+       struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
+       struct autofs_info *ino = autofs4_dentry_ino(dentry);
+       int status;
++      int state;
+       /* Block on any pending expire */
+       if (!(ino->flags & AUTOFS_INF_WANT_EXPIRE))
+@@ -488,8 +506,19 @@ int autofs4_expire_wait(struct dentry *d
+       if (rcu_walk)
+               return -ECHILD;
++retry:
+       spin_lock(&sbi->fs_lock);
+-      if (ino->flags & AUTOFS_INF_EXPIRING) {
++      state = ino->flags & (AUTOFS_INF_WANT_EXPIRE | AUTOFS_INF_EXPIRING);
++      if (state == AUTOFS_INF_WANT_EXPIRE) {
++              spin_unlock(&sbi->fs_lock);
++              /*
++               * Possibly being selected for expire, wait until
++               * it's selected or not.
++               */
++              schedule_timeout_uninterruptible(HZ/10);
++              goto retry;
++      }
++      if (state & AUTOFS_INF_EXPIRING) {
+               spin_unlock(&sbi->fs_lock);
+               DPRINTK("waiting for expire %p name=%pd", dentry, dentry);
diff --git a/queue-4.4/hrtimer-add-support-for-clock_monotonic_raw.patch b/queue-4.4/hrtimer-add-support-for-clock_monotonic_raw.patch
new file mode 100644 (file)
index 0000000..cdc12e0
--- /dev/null
@@ -0,0 +1,81 @@
+From 9c808765e88efb6fa6af7e2206ef89512f1840a7 Mon Sep 17 00:00:00 2001
+From: Marc Zyngier <marc.zyngier@arm.com>
+Date: Fri, 15 Jan 2016 17:41:08 +0000
+Subject: hrtimer: Add support for CLOCK_MONOTONIC_RAW
+
+From: Marc Zyngier <marc.zyngier@arm.com>
+
+commit 9c808765e88efb6fa6af7e2206ef89512f1840a7 upstream.
+
+The KVM/ARM timer implementation arms a hrtimer when a vcpu is
+blocked (usually because it is waiting for an interrupt)
+while its timer is going to kick in the future.
+
+It is essential that this timer doesn't get adjusted, or the
+guest will end up being woken-up at the wrong time (NTP running
+on the host seems to confuse the hell out of some guests).
+
+In order to allow this, let's add CLOCK_MONOTONIC_RAW support
+to hrtimer (it is so far only supported for posix timers). It also
+has the (limited) benefit of fixing de0421d53bfb ("mac80211_hwsim:
+shuffle code to prepare for dynamic radios"), which already uses
+this functionnality without realizing wasn't implemented (just being
+lucky...).
+
+Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
+Cc: Tomasz Nowicki <tn@semihalf.com>
+Cc: Christoffer Dall <christoffer.dall@linaro.org>
+Link: http://lkml.kernel.org/r/1452879670-16133-2-git-send-email-marc.zyngier@arm.com
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Cc: Felix Fietkau <nbd@nbd.name>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ include/linux/hrtimer.h |    1 +
+ kernel/time/hrtimer.c   |   11 ++++++++++-
+ 2 files changed, 11 insertions(+), 1 deletion(-)
+
+--- a/include/linux/hrtimer.h
++++ b/include/linux/hrtimer.h
+@@ -153,6 +153,7 @@ enum  hrtimer_base_type {
+       HRTIMER_BASE_REALTIME,
+       HRTIMER_BASE_BOOTTIME,
+       HRTIMER_BASE_TAI,
++      HRTIMER_BASE_MONOTONIC_RAW,
+       HRTIMER_MAX_CLOCK_BASES,
+ };
+--- a/kernel/time/hrtimer.c
++++ b/kernel/time/hrtimer.c
+@@ -90,6 +90,11 @@ DEFINE_PER_CPU(struct hrtimer_cpu_base,
+                       .clockid = CLOCK_TAI,
+                       .get_time = &ktime_get_clocktai,
+               },
++              {
++                      .index = HRTIMER_BASE_MONOTONIC_RAW,
++                      .clockid = CLOCK_MONOTONIC_RAW,
++                      .get_time = &ktime_get_raw,
++              },
+       }
+ };
+@@ -99,6 +104,7 @@ static const int hrtimer_clock_to_base_t
+       [CLOCK_REALTIME]        = HRTIMER_BASE_REALTIME,
+       [CLOCK_MONOTONIC]       = HRTIMER_BASE_MONOTONIC,
++      [CLOCK_MONOTONIC_RAW]   = HRTIMER_BASE_MONOTONIC_RAW,
+       [CLOCK_BOOTTIME]        = HRTIMER_BASE_BOOTTIME,
+       [CLOCK_TAI]             = HRTIMER_BASE_TAI,
+ };
+@@ -1292,7 +1298,10 @@ static void __hrtimer_run_queues(struct
+               if (!(active & 0x01))
+                       continue;
+-              basenow = ktime_add(now, base->offset);
++              if (unlikely(base->index == HRTIMER_BASE_MONOTONIC_RAW))
++                      basenow = ktime_get_raw();
++              else
++                      basenow = ktime_add(now, base->offset);
+               while ((node = timerqueue_getnext(&base->active))) {
+                       struct hrtimer *timer;
index 6bd4c8c643389d7e54baff034cc08dee2b068770..b7581abf35cd9a0a21257b586818b9f27430c9ef 100644 (file)
@@ -41,3 +41,7 @@ revert-phy-irq-cannot-be-shared.patch
 net-smc91x-fix-smc-accesses.patch
 bridge-re-introduce-fix-parsing-of-mldv2-reports.patch
 pwm-mark-all-devices-as-might-sleep.patch
+hrtimer-add-support-for-clock_monotonic_raw.patch
+autofs-races.patch
+autofs-use-dentry-flags-to-block-walks-during-expire.patch
+xfs-prevent-dropping-ioend-completions-during-buftarg-wait.patch
diff --git a/queue-4.4/xfs-prevent-dropping-ioend-completions-during-buftarg-wait.patch b/queue-4.4/xfs-prevent-dropping-ioend-completions-during-buftarg-wait.patch
new file mode 100644 (file)
index 0000000..23cceca
--- /dev/null
@@ -0,0 +1,55 @@
+From 800b2694f890cc35a1bda63501fc71c94389d517 Mon Sep 17 00:00:00 2001
+From: Brian Foster <bfoster@redhat.com>
+Date: Fri, 26 Aug 2016 16:01:59 +1000
+Subject: xfs: prevent dropping ioend completions during buftarg wait
+
+From: Brian Foster <bfoster@redhat.com>
+
+commit 800b2694f890cc35a1bda63501fc71c94389d517 upstream.
+
+xfs_wait_buftarg() waits for all pending I/O, drains the ioend
+completion workqueue and walks the LRU until all buffers in the cache
+have been released. This is traditionally an unmount operation` but the
+mechanism is also reused during filesystem freeze.
+
+xfs_wait_buftarg() invokes drain_workqueue() as part of the quiesce,
+which is intended more for a shutdown sequence in that it indicates to
+the queue that new operations are not expected once the drain has begun.
+New work jobs after this point result in a WARN_ON_ONCE() and are
+otherwise dropped.
+
+With filesystem freeze, however, read operations are allowed and can
+proceed during or after the workqueue drain. If such a read occurs
+during the drain sequence, the workqueue infrastructure complains about
+the queued ioend completion work item and drops it on the floor. As a
+result, the buffer remains on the LRU and the freeze never completes.
+
+Despite the fact that the overall buffer cache cleanup is not necessary
+during freeze, fix up this operation such that it is safe to invoke
+during non-unmount quiesce operations. Replace the drain_workqueue()
+call with flush_workqueue(), which runs a similar serialization on
+pending workqueue jobs without causing new jobs to be dropped. This is
+safe for unmount as unmount independently locks out new operations by
+the time xfs_wait_buftarg() is invoked.
+
+cc: <stable@vger.kernel.org>
+Signed-off-by: Brian Foster <bfoster@redhat.com>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Dave Chinner <david@fromorbit.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/xfs/xfs_buf.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/fs/xfs/xfs_buf.c
++++ b/fs/xfs/xfs_buf.c
+@@ -1535,7 +1535,7 @@ xfs_wait_buftarg(
+        * ensure here that all reference counts have been dropped before we
+        * start walking the LRU list.
+        */
+-      drain_workqueue(btp->bt_mount->m_buf_workqueue);
++      flush_workqueue(btp->bt_mount->m_buf_workqueue);
+       /* loop until there is nothing left on the lru list. */
+       while (list_lru_count(&btp->bt_lru)) {