From: Greg Kroah-Hartman Date: Tue, 27 Sep 2016 14:27:55 +0000 (+0200) Subject: 4.4-stable patches X-Git-Tag: v4.7.6~7 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=f72fe12968407bd9959f6e9d1b39af966f67fba6;p=thirdparty%2Fkernel%2Fstable-queue.git 4.4-stable patches 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 --- diff --git a/queue-4.4/autofs-races.patch b/queue-4.4/autofs-races.patch new file mode 100644 index 00000000000..1cfada69df2 --- /dev/null +++ b/queue-4.4/autofs-races.patch @@ -0,0 +1,154 @@ +From ea01a18494b3d7a91b2f1f2a6a5aaef4741bc294 Mon Sep 17 00:00:00 2001 +From: Al Viro +Date: Sun, 12 Jun 2016 11:24:46 -0400 +Subject: autofs races + +From: Al Viro + +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 +Cc: Ian Kent +Signed-off-by: Greg Kroah-Hartman + + +--- + 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 index 00000000000..535a40fe348 --- /dev/null +++ b/queue-4.4/autofs-use-dentry-flags-to-block-walks-during-expire.patch @@ -0,0 +1,148 @@ +From 7cbdb4a286a60c5d519cb9223fe2134d26870d39 Mon Sep 17 00:00:00 2001 +From: Ian Kent +Date: Mon, 19 Sep 2016 14:44:12 -0700 +Subject: autofs: use dentry flags to block walks during expire + +From: Ian Kent + +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 +Reported-by: Takashi Iwai +Tested-by: Takashi Iwai +Cc: Takashi Iwai +Cc: NeilBrown +Cc: Al Viro +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..cdc12e0b9ac --- /dev/null +++ b/queue-4.4/hrtimer-add-support-for-clock_monotonic_raw.patch @@ -0,0 +1,81 @@ +From 9c808765e88efb6fa6af7e2206ef89512f1840a7 Mon Sep 17 00:00:00 2001 +From: Marc Zyngier +Date: Fri, 15 Jan 2016 17:41:08 +0000 +Subject: hrtimer: Add support for CLOCK_MONOTONIC_RAW + +From: Marc Zyngier + +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 +Cc: Tomasz Nowicki +Cc: Christoffer Dall +Link: http://lkml.kernel.org/r/1452879670-16133-2-git-send-email-marc.zyngier@arm.com +Signed-off-by: Thomas Gleixner +Cc: Felix Fietkau +Signed-off-by: Greg Kroah-Hartman + +--- + 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; diff --git a/queue-4.4/series b/queue-4.4/series index 6bd4c8c6433..b7581abf35c 100644 --- a/queue-4.4/series +++ b/queue-4.4/series @@ -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 index 00000000000..23ccecac1cd --- /dev/null +++ b/queue-4.4/xfs-prevent-dropping-ioend-completions-during-buftarg-wait.patch @@ -0,0 +1,55 @@ +From 800b2694f890cc35a1bda63501fc71c94389d517 Mon Sep 17 00:00:00 2001 +From: Brian Foster +Date: Fri, 26 Aug 2016 16:01:59 +1000 +Subject: xfs: prevent dropping ioend completions during buftarg wait + +From: Brian Foster + +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: +Signed-off-by: Brian Foster +Reviewed-by: Christoph Hellwig +Signed-off-by: Dave Chinner +Signed-off-by: Greg Kroah-Hartman + +--- + 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)) {