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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Powered by JetHome