aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-04-25 15:47:56 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-25 15:47:56 -0400
commit0b79dada976198cb1a4c043068e3b44d5cab2a5a (patch)
treefde938c698545a7c8764a2eac4304dee002bb281
parent50be4917ee70218f59e04dec029121b97fb9cb3d (diff)
parent3f5087a2bae5d1ce10a3d698dec8f879a96f5419 (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mingo/linux-2.6-sched-fixes
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mingo/linux-2.6-sched-fixes: sched: fix share (re)distribution softlockup: fix NOHZ wakeup seqlock: livelock fix
-rw-r--r--include/linux/seqlock.h46
-rw-r--r--kernel/sched.c47
-rw-r--r--kernel/time/tick-sched.c1
3 files changed, 32 insertions, 62 deletions
diff --git a/include/linux/seqlock.h b/include/linux/seqlock.h
index 26e4925bc35b..632205ccc25d 100644
--- a/include/linux/seqlock.h
+++ b/include/linux/seqlock.h
@@ -85,23 +85,29 @@ static inline int write_tryseqlock(seqlock_t *sl)
85/* Start of read calculation -- fetch last complete writer token */ 85/* Start of read calculation -- fetch last complete writer token */
86static __always_inline unsigned read_seqbegin(const seqlock_t *sl) 86static __always_inline unsigned read_seqbegin(const seqlock_t *sl)
87{ 87{
88 unsigned ret = sl->sequence; 88 unsigned ret;
89
90repeat:
91 ret = sl->sequence;
89 smp_rmb(); 92 smp_rmb();
93 if (unlikely(ret & 1)) {
94 cpu_relax();
95 goto repeat;
96 }
97
90 return ret; 98 return ret;
91} 99}
92 100
93/* Test if reader processed invalid data. 101/*
94 * If initial values is odd, 102 * Test if reader processed invalid data.
95 * then writer had already started when section was entered 103 *
96 * If sequence value changed 104 * If sequence value changed then writer changed data while in section.
97 * then writer changed data while in section
98 *
99 * Using xor saves one conditional branch.
100 */ 105 */
101static __always_inline int read_seqretry(const seqlock_t *sl, unsigned iv) 106static __always_inline int read_seqretry(const seqlock_t *sl, unsigned start)
102{ 107{
103 smp_rmb(); 108 smp_rmb();
104 return (iv & 1) | (sl->sequence ^ iv); 109
110 return (sl->sequence != start);
105} 111}
106 112
107 113
@@ -122,20 +128,26 @@ typedef struct seqcount {
122/* Start of read using pointer to a sequence counter only. */ 128/* Start of read using pointer to a sequence counter only. */
123static inline unsigned read_seqcount_begin(const seqcount_t *s) 129static inline unsigned read_seqcount_begin(const seqcount_t *s)
124{ 130{
125 unsigned ret = s->sequence; 131 unsigned ret;
132
133repeat:
134 ret = s->sequence;
126 smp_rmb(); 135 smp_rmb();
136 if (unlikely(ret & 1)) {
137 cpu_relax();
138 goto repeat;
139 }
127 return ret; 140 return ret;
128} 141}
129 142
130/* Test if reader processed invalid data. 143/*
131 * Equivalent to: iv is odd or sequence number has changed. 144 * Test if reader processed invalid data because sequence number has changed.
132 * (iv & 1) || (*s != iv)
133 * Using xor saves one conditional branch.
134 */ 145 */
135static inline int read_seqcount_retry(const seqcount_t *s, unsigned iv) 146static inline int read_seqcount_retry(const seqcount_t *s, unsigned start)
136{ 147{
137 smp_rmb(); 148 smp_rmb();
138 return (iv & 1) | (s->sequence ^ iv); 149
150 return s->sequence != start;
139} 151}
140 152
141 153
diff --git a/kernel/sched.c b/kernel/sched.c
index 09ca69b2c17d..9e19287f3359 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -1657,42 +1657,6 @@ void aggregate_group_weight(struct task_group *tg, struct sched_domain *sd)
1657} 1657}
1658 1658
1659/* 1659/*
1660 * Redistribute tg->shares amongst all tg->cfs_rq[]s.
1661 */
1662static void __aggregate_redistribute_shares(struct task_group *tg)
1663{
1664 int i, max_cpu = smp_processor_id();
1665 unsigned long rq_weight = 0;
1666 unsigned long shares, max_shares = 0, shares_rem = tg->shares;
1667
1668 for_each_possible_cpu(i)
1669 rq_weight += tg->cfs_rq[i]->load.weight;
1670
1671 for_each_possible_cpu(i) {
1672 /*
1673 * divide shares proportional to the rq_weights.
1674 */
1675 shares = tg->shares * tg->cfs_rq[i]->load.weight;
1676 shares /= rq_weight + 1;
1677
1678 tg->cfs_rq[i]->shares = shares;
1679
1680 if (shares > max_shares) {
1681 max_shares = shares;
1682 max_cpu = i;
1683 }
1684 shares_rem -= shares;
1685 }
1686
1687 /*
1688 * Ensure it all adds up to tg->shares; we can loose a few
1689 * due to rounding down when computing the per-cpu shares.
1690 */
1691 if (shares_rem)
1692 tg->cfs_rq[max_cpu]->shares += shares_rem;
1693}
1694
1695/*
1696 * Compute the weight of this group on the given cpus. 1660 * Compute the weight of this group on the given cpus.
1697 */ 1661 */
1698static 1662static
@@ -1701,18 +1665,11 @@ void aggregate_group_shares(struct task_group *tg, struct sched_domain *sd)
1701 unsigned long shares = 0; 1665 unsigned long shares = 0;
1702 int i; 1666 int i;
1703 1667
1704again:
1705 for_each_cpu_mask(i, sd->span) 1668 for_each_cpu_mask(i, sd->span)
1706 shares += tg->cfs_rq[i]->shares; 1669 shares += tg->cfs_rq[i]->shares;
1707 1670
1708 /* 1671 if ((!shares && aggregate(tg, sd)->rq_weight) || shares > tg->shares)
1709 * When the span doesn't have any shares assigned, but does have 1672 shares = tg->shares;
1710 * tasks to run do a machine wide rebalance (should be rare).
1711 */
1712 if (unlikely(!shares && aggregate(tg, sd)->rq_weight)) {
1713 __aggregate_redistribute_shares(tg);
1714 goto again;
1715 }
1716 1673
1717 aggregate(tg, sd)->shares = shares; 1674 aggregate(tg, sd)->shares = shares;
1718} 1675}
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index d358d4e3a958..b854a895591e 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -393,6 +393,7 @@ void tick_nohz_restart_sched_tick(void)
393 sub_preempt_count(HARDIRQ_OFFSET); 393 sub_preempt_count(HARDIRQ_OFFSET);
394 } 394 }
395 395
396 touch_softlockup_watchdog();
396 /* 397 /*
397 * Cancel the scheduled timer and restore the tick 398 * Cancel the scheduled timer and restore the tick
398 */ 399 */