From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
To: linux-kernel@vger.kernel.org, stable@vger.kernel.org
Cc: Greg KH <gregkh@linuxfoundation.org>,
torvalds@linux-foundation.org, akpm@linux-foundation.org,
alan@lxorguk.ukuu.org.uk, Peter Zijlstra <a.p.zijlstra@chello.nl>,
Ingo Molnar <mingo@kernel.org>
Subject: [ 11/37] sched/nohz: Rewrite and fix load-avg computation -- again
Date: Tue, 17 Jul 2012 17:02:48 -0700 [thread overview]
Message-ID: <20120717232432.250519502@linuxfoundation.org> (raw)
In-Reply-To: <20120717232431.399005532@linuxfoundation.org>
From: Greg KH <gregkh@linuxfoundation.org>
3.4-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peter Zijlstra <a.p.zijlstra@chello.nl>
commit 5167e8d5417bf5c322a703d2927daec727ea40dd upstream.
Thanks to Charles Wang for spotting the defects in the current code:
- If we go idle during the sample window -- after sampling, we get a
negative bias because we can negate our own sample.
- If we wake up during the sample window we get a positive bias
because we push the sample to a known active period.
So rewrite the entire nohz load-avg muck once again, now adding
copious documentation to the code.
Reported-and-tested-by: Doug Smythies <dsmythies@telus.net>
Reported-and-tested-by: Charles Wang <muming.wq@gmail.com>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Link: http://lkml.kernel.org/r/1340373782.18025.74.camel@twins
[ minor edits ]
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
include/linux/sched.h | 8 +
kernel/sched/core.c | 275 ++++++++++++++++++++++++++++++++++-------------
kernel/sched/idle_task.c | 1
kernel/sched/sched.h | 2
kernel/time/tick-sched.c | 2
5 files changed, 213 insertions(+), 75 deletions(-)
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1933,6 +1933,14 @@ static inline int set_cpus_allowed_ptr(s
}
#endif
+#ifdef CONFIG_NO_HZ
+void calc_load_enter_idle(void);
+void calc_load_exit_idle(void);
+#else
+static inline void calc_load_enter_idle(void) { }
+static inline void calc_load_exit_idle(void) { }
+#endif /* CONFIG_NO_HZ */
+
#ifndef CONFIG_CPUMASK_OFFSTACK
static inline int set_cpus_allowed(struct task_struct *p, cpumask_t new_mask)
{
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -2162,11 +2162,73 @@ unsigned long this_cpu_load(void)
}
+/*
+ * Global load-average calculations
+ *
+ * We take a distributed and async approach to calculating the global load-avg
+ * in order to minimize overhead.
+ *
+ * The global load average is an exponentially decaying average of nr_running +
+ * nr_uninterruptible.
+ *
+ * Once every LOAD_FREQ:
+ *
+ * nr_active = 0;
+ * for_each_possible_cpu(cpu)
+ * nr_active += cpu_of(cpu)->nr_running + cpu_of(cpu)->nr_uninterruptible;
+ *
+ * avenrun[n] = avenrun[0] * exp_n + nr_active * (1 - exp_n)
+ *
+ * Due to a number of reasons the above turns in the mess below:
+ *
+ * - for_each_possible_cpu() is prohibitively expensive on machines with
+ * serious number of cpus, therefore we need to take a distributed approach
+ * to calculating nr_active.
+ *
+ * \Sum_i x_i(t) = \Sum_i x_i(t) - x_i(t_0) | x_i(t_0) := 0
+ * = \Sum_i { \Sum_j=1 x_i(t_j) - x_i(t_j-1) }
+ *
+ * So assuming nr_active := 0 when we start out -- true per definition, we
+ * can simply take per-cpu deltas and fold those into a global accumulate
+ * to obtain the same result. See calc_load_fold_active().
+ *
+ * Furthermore, in order to avoid synchronizing all per-cpu delta folding
+ * across the machine, we assume 10 ticks is sufficient time for every
+ * cpu to have completed this task.
+ *
+ * This places an upper-bound on the IRQ-off latency of the machine. Then
+ * again, being late doesn't loose the delta, just wrecks the sample.
+ *
+ * - cpu_rq()->nr_uninterruptible isn't accurately tracked per-cpu because
+ * this would add another cross-cpu cacheline miss and atomic operation
+ * to the wakeup path. Instead we increment on whatever cpu the task ran
+ * when it went into uninterruptible state and decrement on whatever cpu
+ * did the wakeup. This means that only the sum of nr_uninterruptible over
+ * all cpus yields the correct result.
+ *
+ * This covers the NO_HZ=n code, for extra head-aches, see the comment below.
+ */
+
/* Variables and functions for calc_load */
static atomic_long_t calc_load_tasks;
static unsigned long calc_load_update;
unsigned long avenrun[3];
-EXPORT_SYMBOL(avenrun);
+EXPORT_SYMBOL(avenrun); /* should be removed */
+
+/**
+ * get_avenrun - get the load average array
+ * @loads: pointer to dest load array
+ * @offset: offset to add
+ * @shift: shift count to shift the result left
+ *
+ * These values are estimates at best, so no need for locking.
+ */
+void get_avenrun(unsigned long *loads, unsigned long offset, int shift)
+{
+ loads[0] = (avenrun[0] + offset) << shift;
+ loads[1] = (avenrun[1] + offset) << shift;
+ loads[2] = (avenrun[2] + offset) << shift;
+}
static long calc_load_fold_active(struct rq *this_rq)
{
@@ -2183,6 +2245,9 @@ static long calc_load_fold_active(struct
return delta;
}
+/*
+ * a1 = a0 * e + a * (1 - e)
+ */
static unsigned long
calc_load(unsigned long load, unsigned long exp, unsigned long active)
{
@@ -2194,30 +2259,118 @@ calc_load(unsigned long load, unsigned l
#ifdef CONFIG_NO_HZ
/*
- * For NO_HZ we delay the active fold to the next LOAD_FREQ update.
+ * Handle NO_HZ for the global load-average.
+ *
+ * Since the above described distributed algorithm to compute the global
+ * load-average relies on per-cpu sampling from the tick, it is affected by
+ * NO_HZ.
+ *
+ * The basic idea is to fold the nr_active delta into a global idle-delta upon
+ * entering NO_HZ state such that we can include this as an 'extra' cpu delta
+ * when we read the global state.
+ *
+ * Obviously reality has to ruin such a delightfully simple scheme:
+ *
+ * - When we go NO_HZ idle during the window, we can negate our sample
+ * contribution, causing under-accounting.
+ *
+ * We avoid this by keeping two idle-delta counters and flipping them
+ * when the window starts, thus separating old and new NO_HZ load.
+ *
+ * The only trick is the slight shift in index flip for read vs write.
+ *
+ * 0s 5s 10s 15s
+ * +10 +10 +10 +10
+ * |-|-----------|-|-----------|-|-----------|-|
+ * r:0 0 1 1 0 0 1 1 0
+ * w:0 1 1 0 0 1 1 0 0
+ *
+ * This ensures we'll fold the old idle contribution in this window while
+ * accumlating the new one.
+ *
+ * - When we wake up from NO_HZ idle during the window, we push up our
+ * contribution, since we effectively move our sample point to a known
+ * busy state.
+ *
+ * This is solved by pushing the window forward, and thus skipping the
+ * sample, for this cpu (effectively using the idle-delta for this cpu which
+ * was in effect at the time the window opened). This also solves the issue
+ * of having to deal with a cpu having been in NOHZ idle for multiple
+ * LOAD_FREQ intervals.
*
* When making the ILB scale, we should try to pull this in as well.
*/
-static atomic_long_t calc_load_tasks_idle;
+static atomic_long_t calc_load_idle[2];
+static int calc_load_idx;
+
+static inline int calc_load_write_idx(void)
+{
+ int idx = calc_load_idx;
-void calc_load_account_idle(struct rq *this_rq)
+ /*
+ * See calc_global_nohz(), if we observe the new index, we also
+ * need to observe the new update time.
+ */
+ smp_rmb();
+
+ /*
+ * If the folding window started, make sure we start writing in the
+ * next idle-delta.
+ */
+ if (!time_before(jiffies, calc_load_update))
+ idx++;
+
+ return idx & 1;
+}
+
+static inline int calc_load_read_idx(void)
{
+ return calc_load_idx & 1;
+}
+
+void calc_load_enter_idle(void)
+{
+ struct rq *this_rq = this_rq();
long delta;
+ /*
+ * We're going into NOHZ mode, if there's any pending delta, fold it
+ * into the pending idle delta.
+ */
delta = calc_load_fold_active(this_rq);
- if (delta)
- atomic_long_add(delta, &calc_load_tasks_idle);
+ if (delta) {
+ int idx = calc_load_write_idx();
+ atomic_long_add(delta, &calc_load_idle[idx]);
+ }
}
-static long calc_load_fold_idle(void)
+void calc_load_exit_idle(void)
{
- long delta = 0;
+ struct rq *this_rq = this_rq();
+
+ /*
+ * If we're still before the sample window, we're done.
+ */
+ if (time_before(jiffies, this_rq->calc_load_update))
+ return;
/*
- * Its got a race, we don't care...
+ * We woke inside or after the sample window, this means we're already
+ * accounted through the nohz accounting, so skip the entire deal and
+ * sync up for the next window.
*/
- if (atomic_long_read(&calc_load_tasks_idle))
- delta = atomic_long_xchg(&calc_load_tasks_idle, 0);
+ this_rq->calc_load_update = calc_load_update;
+ if (time_before(jiffies, this_rq->calc_load_update + 10))
+ this_rq->calc_load_update += LOAD_FREQ;
+}
+
+static long calc_load_fold_idle(void)
+{
+ int idx = calc_load_read_idx();
+ long delta = 0;
+
+ if (atomic_long_read(&calc_load_idle[idx]))
+ delta = atomic_long_xchg(&calc_load_idle[idx], 0);
return delta;
}
@@ -2303,66 +2456,39 @@ static void calc_global_nohz(void)
{
long delta, active, n;
- /*
- * If we crossed a calc_load_update boundary, make sure to fold
- * any pending idle changes, the respective CPUs might have
- * missed the tick driven calc_load_account_active() update
- * due to NO_HZ.
- */
- delta = calc_load_fold_idle();
- if (delta)
- atomic_long_add(delta, &calc_load_tasks);
+ if (!time_before(jiffies, calc_load_update + 10)) {
+ /*
+ * Catch-up, fold however many we are behind still
+ */
+ delta = jiffies - calc_load_update - 10;
+ n = 1 + (delta / LOAD_FREQ);
+
+ active = atomic_long_read(&calc_load_tasks);
+ active = active > 0 ? active * FIXED_1 : 0;
+
+ avenrun[0] = calc_load_n(avenrun[0], EXP_1, active, n);
+ avenrun[1] = calc_load_n(avenrun[1], EXP_5, active, n);
+ avenrun[2] = calc_load_n(avenrun[2], EXP_15, active, n);
- /*
- * It could be the one fold was all it took, we done!
- */
- if (time_before(jiffies, calc_load_update + 10))
- return;
+ calc_load_update += n * LOAD_FREQ;
+ }
/*
- * Catch-up, fold however many we are behind still
+ * Flip the idle index...
+ *
+ * Make sure we first write the new time then flip the index, so that
+ * calc_load_write_idx() will see the new time when it reads the new
+ * index, this avoids a double flip messing things up.
*/
- delta = jiffies - calc_load_update - 10;
- n = 1 + (delta / LOAD_FREQ);
-
- active = atomic_long_read(&calc_load_tasks);
- active = active > 0 ? active * FIXED_1 : 0;
-
- avenrun[0] = calc_load_n(avenrun[0], EXP_1, active, n);
- avenrun[1] = calc_load_n(avenrun[1], EXP_5, active, n);
- avenrun[2] = calc_load_n(avenrun[2], EXP_15, active, n);
-
- calc_load_update += n * LOAD_FREQ;
-}
-#else
-void calc_load_account_idle(struct rq *this_rq)
-{
+ smp_wmb();
+ calc_load_idx++;
}
+#else /* !CONFIG_NO_HZ */
-static inline long calc_load_fold_idle(void)
-{
- return 0;
-}
-
-static void calc_global_nohz(void)
-{
-}
-#endif
+static inline long calc_load_fold_idle(void) { return 0; }
+static inline void calc_global_nohz(void) { }
-/**
- * get_avenrun - get the load average array
- * @loads: pointer to dest load array
- * @offset: offset to add
- * @shift: shift count to shift the result left
- *
- * These values are estimates at best, so no need for locking.
- */
-void get_avenrun(unsigned long *loads, unsigned long offset, int shift)
-{
- loads[0] = (avenrun[0] + offset) << shift;
- loads[1] = (avenrun[1] + offset) << shift;
- loads[2] = (avenrun[2] + offset) << shift;
-}
+#endif /* CONFIG_NO_HZ */
/*
* calc_load - update the avenrun load estimates 10 ticks after the
@@ -2370,11 +2496,18 @@ void get_avenrun(unsigned long *loads, u
*/
void calc_global_load(unsigned long ticks)
{
- long active;
+ long active, delta;
if (time_before(jiffies, calc_load_update + 10))
return;
+ /*
+ * Fold the 'old' idle-delta to include all NO_HZ cpus.
+ */
+ delta = calc_load_fold_idle();
+ if (delta)
+ atomic_long_add(delta, &calc_load_tasks);
+
active = atomic_long_read(&calc_load_tasks);
active = active > 0 ? active * FIXED_1 : 0;
@@ -2385,12 +2518,7 @@ void calc_global_load(unsigned long tick
calc_load_update += LOAD_FREQ;
/*
- * Account one period with whatever state we found before
- * folding in the nohz state and ageing the entire idle period.
- *
- * This avoids loosing a sample when we go idle between
- * calc_load_account_active() (10 ticks ago) and now and thus
- * under-accounting.
+ * In case we idled for multiple LOAD_FREQ intervals, catch up in bulk.
*/
calc_global_nohz();
}
@@ -2407,7 +2535,6 @@ static void calc_load_account_active(str
return;
delta = calc_load_fold_active(this_rq);
- delta += calc_load_fold_idle();
if (delta)
atomic_long_add(delta, &calc_load_tasks);
@@ -2415,6 +2542,10 @@ static void calc_load_account_active(str
}
/*
+ * End of global load-average stuff
+ */
+
+/*
* The exact cpuload at various idx values, calculated at every tick would be
* load = (2^idx - 1) / 2^idx * load + 1 / 2^idx * cur_load
*
--- a/kernel/sched/idle_task.c
+++ b/kernel/sched/idle_task.c
@@ -25,7 +25,6 @@ static void check_preempt_curr_idle(stru
static struct task_struct *pick_next_task_idle(struct rq *rq)
{
schedstat_inc(rq, sched_goidle);
- calc_load_account_idle(rq);
return rq->idle;
}
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -940,8 +940,6 @@ static inline u64 sched_avg_period(void)
return (u64)sysctl_sched_time_avg * NSEC_PER_MSEC / 2;
}
-void calc_load_account_idle(struct rq *this_rq);
-
#ifdef CONFIG_SCHED_HRTICK
/*
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -401,6 +401,7 @@ static void tick_nohz_stop_sched_tick(st
*/
if (!ts->tick_stopped) {
select_nohz_load_balancer(1);
+ calc_load_enter_idle();
ts->idle_tick = hrtimer_get_expires(&ts->sched_timer);
ts->tick_stopped = 1;
@@ -591,6 +592,7 @@ void tick_nohz_idle_exit(void)
account_idle_ticks(ticks);
#endif
+ calc_load_exit_idle();
touch_softlockup_watchdog();
/*
* Cancel the scheduled timer and restore the tick
next prev parent reply other threads:[~2012-07-18 0:11 UTC|newest]
Thread overview: 67+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-07-17 23:24 [ 00/23] 3.0.38-stable review Greg KH
2012-07-18 0:02 ` [ 01/37] Remove easily user-triggerable BUG from generic_setlease Greg Kroah-Hartman
2012-07-18 0:02 ` [ 02/37] media: cx231xx: dont DMA to random addresses Greg Kroah-Hartman
2012-07-18 0:02 ` [ 03/37] hwmon: (it87) Preserve configuration register bits on init Greg Kroah-Hartman
2012-07-18 0:02 ` [ 04/37] block: fix infinite loop in __getblk_slow Greg Kroah-Hartman
2012-07-18 0:02 ` [ 05/37] media: dvb-core: Release semaphore on error path dvb_register_device() Greg Kroah-Hartman
2012-07-18 0:02 ` [ 06/37] mtd: nandsim: dont open code a do_div helper Greg Kroah-Hartman
2012-07-18 0:02 ` [ 07/37] md/raid1: fix use-after-free bug in RAID1 data-check code Greg Kroah-Hartman
2012-07-18 0:02 ` [ 08/37] ARM: SAMSUNG: fix race in s3c_adc_start for ADC Greg Kroah-Hartman
2012-07-18 0:02 ` [ 09/37] ACPICA: Fix possible fault in return package object repair code Greg Kroah-Hartman
2012-07-18 0:02 ` [ 10/37] cpufreq / ACPI: Fix not loading acpi-cpufreq driver regression Greg Kroah-Hartman
2012-07-18 0:02 ` Greg Kroah-Hartman [this message]
2012-07-18 0:16 ` [ 11/37] sched/nohz: Rewrite and fix load-avg computation -- again Jonathan Nieder
2012-07-20 17:04 ` Peter Zijlstra
2012-07-20 17:13 ` Jonathan Nieder
2012-07-20 17:25 ` Peter Zijlstra
2012-07-21 16:02 ` Doug Smythies
2012-07-18 0:02 ` [ 12/37] intel_ips: blacklist HP ProBook laptops Greg Kroah-Hartman
2012-07-18 0:02 ` [ 13/37] fifo: Do not restart open() if it already found a partner Greg Kroah-Hartman
2012-07-18 0:02 ` [ 14/37] rt2x00usb: fix indexes ordering on RX queue kick Greg Kroah-Hartman
2012-07-18 0:02 ` [ 15/37] e1000e: Correct link check logic for 82571 serdes Greg Kroah-Hartman
2012-07-18 0:02 ` [ 16/37] iwlegacy: always monitor for stuck queues Greg Kroah-Hartman
2012-07-18 0:02 ` [ 17/37] iwlegacy: dont mess up the SCD when removing a key Greg Kroah-Hartman
2012-07-18 0:02 ` [ 18/37] rpmsg: fix dependency on initialization order Greg Kroah-Hartman
2012-07-18 0:02 ` [ 19/37] mac80211: destroy assoc_data correctly if assoc fails Greg Kroah-Hartman
2012-07-18 0:02 ` [ 20/37] stmmac: Fix for nfs hang on multiple reboot Greg Kroah-Hartman
2012-07-18 0:02 ` [ 21/37] bonding: debugfs and network namespaces are incompatible Greg Kroah-Hartman
2012-07-18 0:02 ` [ 22/37] bonding: Manage /proc/net/bonding/ entries from the netdev events Greg Kroah-Hartman
2012-07-18 0:03 ` [ 23/37] Input: bcm5974 - Add support for 2012 MacBook Pro Retina Greg Kroah-Hartman
2012-07-18 0:03 ` [ 24/37] Input: xpad - handle all variations of Mad Catz Beat Pad Greg Kroah-Hartman
2012-07-18 0:03 ` [ 25/37] Input: xpad - add signature for Razer Onza Tournament Edition Greg Kroah-Hartman
2012-07-18 0:03 ` [ 26/37] Input: xpad - add Andamiro Pump It Up pad Greg Kroah-Hartman
2012-07-18 0:03 ` [ 27/37] HID: add support for 2012 MacBook Pro Retina Greg Kroah-Hartman
2012-07-18 0:03 ` [ 28/37] clk: Check parent for NULL in clk_change_rate Greg Kroah-Hartman
2012-07-18 0:03 ` [ 29/37] cfg80211: check iface combinations only when iface is running Greg Kroah-Hartman
2012-07-18 0:03 ` [ 30/37] hrtimer: Provide clock_was_set_delayed() Greg Kroah-Hartman
2012-07-18 0:03 ` [ 31/37] timekeeping: Fix leapsecond triggered load spike issue Greg Kroah-Hartman
2012-07-18 0:03 ` [ 32/37] timekeeping: Maintain ktime_t based offsets for hrtimers Greg Kroah-Hartman
2012-07-18 0:03 ` [ 33/37] hrtimers: Move lock held region in hrtimer_interrupt() Greg Kroah-Hartman
2012-07-18 0:03 ` [ 34/37] timekeeping: Provide hrtimer update function Greg Kroah-Hartman
2012-07-18 0:03 ` [ 35/37] hrtimer: Update hrtimer base offsets each hrtimer_interrupt Greg Kroah-Hartman
2012-07-18 0:03 ` [ 37/37] NFC: Export nfc.h to userland Greg Kroah-Hartman
2012-07-18 0:14 ` [ 01/37] Remove easily user-triggerable BUG from generic_setlease Greg KH
2012-07-18 13:36 ` Nick Bowler
2012-07-18 17:58 ` formail doing weird things (was: [ 01/37] Remove easily user-triggerable BUG from generic_setlease) Roland Eggner
2012-07-18 0:11 ` [ 01/23] hwmon: (it87) Preserve configuration register bits on init Greg Kroah-Hartman
2012-07-18 0:11 ` [ 02/23] block: fix infinite loop in __getblk_slow Greg Kroah-Hartman
2012-07-18 0:11 ` [ 03/23] media: dvb-core: Release semaphore on error path dvb_register_device() Greg Kroah-Hartman
2012-07-18 0:11 ` [ 04/23] mtd: nandsim: dont open code a do_div helper Greg Kroah-Hartman
2012-07-18 0:11 ` [ 05/23] ARM: SAMSUNG: fix race in s3c_adc_start for ADC Greg Kroah-Hartman
2012-07-18 0:11 ` [ 06/23] intel_ips: blacklist HP ProBook laptops Greg Kroah-Hartman
2012-07-18 0:12 ` [ 07/23] fifo: Do not restart open() if it already found a partner Greg Kroah-Hartman
2012-07-18 0:12 ` [ 08/23] rt2x00usb: fix indexes ordering on RX queue kick Greg Kroah-Hartman
2012-07-18 0:12 ` [ 09/23] e1000e: Correct link check logic for 82571 serdes Greg Kroah-Hartman
2012-07-18 0:12 ` [ 10/23] Input: xpad - add Andamiro Pump It Up pad Greg Kroah-Hartman
2012-07-18 0:12 ` [ 11/23] tcp: drop SYN+FIN messages Greg Kroah-Hartman
2012-07-18 0:12 ` [ 12/23] cfg80211: check iface combinations only when iface is running Greg Kroah-Hartman
2012-07-18 0:12 ` [ 13/23] ntp: Fix leap-second hrtimer livelock Greg Kroah-Hartman
2012-07-18 0:12 ` [ 14/23] ntp: Correct TAI offset during leap second Greg Kroah-Hartman
2012-07-18 0:12 ` [ 15/23] timekeeping: Fix CLOCK_MONOTONIC inconsistency during leapsecond Greg Kroah-Hartman
2012-07-18 0:12 ` [ 16/23] time: Move common updates to a function Greg Kroah-Hartman
2012-07-18 0:12 ` [ 17/23] hrtimer: Provide clock_was_set_delayed() Greg Kroah-Hartman
2012-07-18 0:12 ` [ 18/23] timekeeping: Fix leapsecond triggered load spike issue Greg Kroah-Hartman
2012-07-18 0:12 ` [ 19/23] timekeeping: Maintain ktime_t based offsets for hrtimers Greg Kroah-Hartman
2012-07-18 0:12 ` [ 20/23] hrtimers: Move lock held region in hrtimer_interrupt() Greg Kroah-Hartman
2012-07-18 0:12 ` [ 21/23] timekeeping: Provide hrtimer update function Greg Kroah-Hartman
2012-07-18 0:12 ` [ 22/23] hrtimer: Update hrtimer base offsets each hrtimer_interrupt Greg Kroah-Hartman
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20120717232432.250519502@linuxfoundation.org \
--to=gregkh@linuxfoundation.org \
--cc=a.p.zijlstra@chello.nl \
--cc=akpm@linux-foundation.org \
--cc=alan@lxorguk.ukuu.org.uk \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@kernel.org \
--cc=stable@vger.kernel.org \
--cc=torvalds@linux-foundation.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.