summaryrefslogtreecommitdiffstats
path: root/meta/recipes-core
diff options
context:
space:
mode:
authorSunil Dora <sunilkumar.dora@windriver.com>2025-06-17 03:08:48 -0700
committerSteve Sakoman <steve@sakoman.com>2025-06-20 08:06:30 -0700
commit218c9ec684cf13229d7d9ef6cf4bc4f7be564faf (patch)
tree592e02686862660cf804655095d7df2310b97d33 /meta/recipes-core
parentd2ca3a347ed775b584029d58f531ccc88fd7757a (diff)
downloadpoky-218c9ec684cf13229d7d9ef6cf4bc4f7be564faf.tar.gz
glibc: pthreads NPTL lost wakeup fix 2
The following commits have been cherry-picked from Glibc master branch: Bug : https://sourceware.org/bugzilla/show_bug.cgi?id=25847 Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=commit;h=1db84775f831a1494993ce9c118deaf9537cc50a] (From OE-Core rev: c05290e51d0faf661bac587066a79626919609e8) Signed-off-by: Sunil Dora <sunilkumar.dora@windriver.com> Signed-off-by: Steve Sakoman <steve@sakoman.com>
Diffstat (limited to 'meta/recipes-core')
-rw-r--r--meta/recipes-core/glibc/glibc/0026-PR25847-1.patch455
-rw-r--r--meta/recipes-core/glibc/glibc_2.35.bb1
2 files changed, 456 insertions, 0 deletions
diff --git a/meta/recipes-core/glibc/glibc/0026-PR25847-1.patch b/meta/recipes-core/glibc/glibc/0026-PR25847-1.patch
new file mode 100644
index 0000000000..44a2b6772c
--- /dev/null
+++ b/meta/recipes-core/glibc/glibc/0026-PR25847-1.patch
@@ -0,0 +1,455 @@
1From 31d9848830e496f57d4182b518467c4c63bfd4bd Mon Sep 17 00:00:00 2001
2From: Frank Barrus <frankbarrus_sw@shaggy.cc>
3Date: Mon, 16 Jun 2025 22:37:54 -0700
4Subject: [PATCH] pthreads NPTL: lost wakeup fix 2
5
6This fixes the lost wakeup (from a bug in signal stealing) with a change
7in the usage of g_signals[] in the condition variable internal state.
8It also completely eliminates the concept and handling of signal stealing,
9as well as the need for signalers to block to wait for waiters to wake
10up every time there is a G1/G2 switch. This greatly reduces the average
11and maximum latency for pthread_cond_signal.
12
13The g_signals[] field now contains a signal count that is relative to
14the current g1_start value. Since it is a 32-bit field, and the LSB is
15still reserved (though not currently used anymore), it has a 31-bit value
16that corresponds to the low 31 bits of the sequence number in g1_start.
17(since g1_start also has an LSB flag, this means bits 31:1 in g_signals
18correspond to bits 31:1 in g1_start, plus the current signal count)
19
20By making the signal count relative to g1_start, there is no longer
21any ambiguity or A/B/A issue, and thus any checks before blocking,
22including the futex call itself, are guaranteed not to block if the G1/G2
23switch occurs, even if the signal count remains the same. This allows
24initially safely blocking in G2 until the switch to G1 occurs, and
25then transitioning from G1 to a new G1 or G2, and always being able to
26distinguish the state change. This removes the race condition and A/B/A
27problems that otherwise ocurred if a late (pre-empted) waiter were to
28resume just as the futex call attempted to block on g_signal since
29otherwise there was no last opportunity to re-check things like whether
30the current G1 group was already closed.
31
32By fixing these issues, the signal stealing code can be eliminated,
33since there is no concept of signal stealing anymore. The code to block
34for all waiters to exit g_refs can also be removed, since any waiters
35that are still in the g_refs region can be guaranteed to safely wake
36up and exit. If there are still any left at this time, they are all
37sent one final futex wakeup to ensure that they are not blocked any
38longer, but there is no need for the signaller to block and wait for
39them to wake up and exit the g_refs region.
40
41The signal count is then effectively "zeroed" but since it is now
42relative to g1_start, this is done by advancing it to a new value that
43can be observed by any pending blocking waiters. Any late waiters can
44always tell the difference, and can thus just cleanly exit if they are
45in a stale G1 or G2. They can never steal a signal from the current
46G1 if they are not in the current G1, since the signal value that has
47to match in the cmpxchg has the low 31 bits of the g1_start value
48contained in it, and that's first checked, and then it won't match if
49there's a G1/G2 change.
50
51Note: the 31-bit sequence number used in g_signals is designed to
52handle wrap-around when checking the signal count, but if the entire
5331-bit wraparound (2 billion signals) occurs while there is still a
54late waiter that has not yet resumed, and it happens to then match
55the current g1_start low bits, and the pre-emption occurs after the
56normal "closed group" checks (which are 64-bit) but then hits the
57futex syscall and signal consuming code, then an A/B/A issue could
58still result and cause an incorrect assumption about whether it
59should block. This particular scenario seems unlikely in practice.
60Note that once awake from the futex, the waiter would notice the
61closed group before consuming the signal (since that's still a 64-bit
62check that would not be aliased in the wrap-around in g_signals),
63so the biggest impact would be blocking on the futex until the next
64full wakeup from a G1/G2 switch.
65
66The following commits have been cherry-picked from Glibc master branch:
67Bug : https://sourceware.org/bugzilla/show_bug.cgi?id=25847
68
69Upstream-Status: Backport
70[https://sourceware.org/git/?p=glibc.git;a=commit;h=1db84775f831a1494993ce9c118deaf9537cc50a]
71
72Signed-off-by: Sunil Dora <sunilkumar.dora@windriver.com>
73---
74 nptl/pthread_cond_common.c | 106 +++++++++------------------
75 nptl/pthread_cond_wait.c | 144 ++++++++++++-------------------------
76 2 files changed, 81 insertions(+), 169 deletions(-)
77
78diff --git a/nptl/pthread_cond_common.c b/nptl/pthread_cond_common.c
79index fb035f72c3..8dd7037923 100644
80--- a/nptl/pthread_cond_common.c
81+++ b/nptl/pthread_cond_common.c
82@@ -201,7 +201,6 @@ static bool __attribute__ ((unused))
83 __condvar_quiesce_and_switch_g1 (pthread_cond_t *cond, uint64_t wseq,
84 unsigned int *g1index, int private)
85 {
86- const unsigned int maxspin = 0;
87 unsigned int g1 = *g1index;
88
89 /* If there is no waiter in G2, we don't do anything. The expression may
90@@ -222,85 +221,46 @@ __condvar_quiesce_and_switch_g1 (pthread_cond_t *cond, uint64_t wseq,
91 * New waiters arriving concurrently with the group switching will all go
92 into G2 until we atomically make the switch. Waiters existing in G2
93 are not affected.
94- * Waiters in G1 will be closed out immediately by setting a flag in
95- __g_signals, which will prevent waiters from blocking using a futex on
96- __g_signals and also notifies them that the group is closed. As a
97- result, they will eventually remove their group reference, allowing us
98- to close switch group roles. */
99-
100- /* First, set the closed flag on __g_signals. This tells waiters that are
101- about to wait that they shouldn't do that anymore. This basically
102- serves as an advance notificaton of the upcoming change to __g1_start;
103- waiters interpret it as if __g1_start was larger than their waiter
104- sequence position. This allows us to change __g1_start after waiting
105- for all existing waiters with group references to leave, which in turn
106- makes recovery after stealing a signal simpler because it then can be
107- skipped if __g1_start indicates that the group is closed (otherwise,
108- we would have to recover always because waiters don't know how big their
109- groups are). Relaxed MO is fine. */
110- atomic_fetch_or_relaxed (cond->__data.__g_signals + g1, 1);
111-
112- /* Wait until there are no group references anymore. The fetch-or operation
113- injects us into the modification order of __g_refs; release MO ensures
114- that waiters incrementing __g_refs after our fetch-or see the previous
115- changes to __g_signals and to __g1_start that had to happen before we can
116- switch this G1 and alias with an older group (we have two groups, so
117- aliasing requires switching group roles twice). Note that nobody else
118- can have set the wake-request flag, so we do not have to act upon it.
119-
120- Also note that it is harmless if older waiters or waiters from this G1
121- get a group reference after we have quiesced the group because it will
122- remain closed for them either because of the closed flag in __g_signals
123- or the later update to __g1_start. New waiters will never arrive here
124- but instead continue to go into the still current G2. */
125- unsigned r = atomic_fetch_or_release (cond->__data.__g_refs + g1, 0);
126- while ((r >> 1) > 0)
127- {
128- for (unsigned int spin = maxspin; ((r >> 1) > 0) && (spin > 0); spin--)
129- {
130- /* TODO Back off. */
131- r = atomic_load_relaxed (cond->__data.__g_refs + g1);
132- }
133- if ((r >> 1) > 0)
134- {
135- /* There is still a waiter after spinning. Set the wake-request
136- flag and block. Relaxed MO is fine because this is just about
137- this futex word.
138-
139- Update r to include the set wake-request flag so that the upcoming
140- futex_wait only blocks if the flag is still set (otherwise, we'd
141- violate the basic client-side futex protocol). */
142- r = atomic_fetch_or_relaxed (cond->__data.__g_refs + g1, 1) | 1;
143-
144- if ((r >> 1) > 0)
145- futex_wait_simple (cond->__data.__g_refs + g1, r, private);
146- /* Reload here so we eventually see the most recent value even if we
147- do not spin. */
148- r = atomic_load_relaxed (cond->__data.__g_refs + g1);
149- }
150- }
151- /* Acquire MO so that we synchronize with the release operation that waiters
152- use to decrement __g_refs and thus happen after the waiters we waited
153- for. */
154- atomic_thread_fence_acquire ();
155+ * Waiters in G1 will be closed out immediately by the advancing of
156+ __g_signals to the next "lowseq" (low 31 bits of the new g1_start),
157+ which will prevent waiters from blocking using a futex on
158+ __g_signals since it provides enough signals for all possible
159+ remaining waiters. As a result, they can each consume a signal
160+ and they will eventually remove their group reference. */
161
162 /* Update __g1_start, which finishes closing this group. The value we add
163 will never be negative because old_orig_size can only be zero when we
164 switch groups the first time after a condvar was initialized, in which
165- case G1 will be at index 1 and we will add a value of 1. See above for
166- why this takes place after waiting for quiescence of the group.
167+ case G1 will be at index 1 and we will add a value of 1.
168 Relaxed MO is fine because the change comes with no additional
169 constraints that others would have to observe. */
170 __condvar_add_g1_start_relaxed (cond,
171 (old_orig_size << 1) + (g1 == 1 ? 1 : - 1));
172
173- /* Now reopen the group, thus enabling waiters to again block using the
174- futex controlled by __g_signals. Release MO so that observers that see
175- no signals (and thus can block) also see the write __g1_start and thus
176- that this is now a new group (see __pthread_cond_wait_common for the
177- matching acquire MO loads). */
178- atomic_store_release (cond->__data.__g_signals + g1, 0);
179-
180+ unsigned int lowseq = ((old_g1_start + old_orig_size) << 1) & ~1U;
181+
182+ /* If any waiters still hold group references (and thus could be blocked),
183+ then wake them all up now and prevent any running ones from blocking.
184+ This is effectively a catch-all for any possible current or future
185+ bugs that can allow the group size to reach 0 before all G1 waiters
186+ have been awakened or at least given signals to consume, or any
187+ other case that can leave blocked (or about to block) older waiters.. */
188+ if ((atomic_fetch_or_release (cond->__data.__g_refs + g1, 0) >> 1) > 0)
189+ {
190+ /* First advance signals to the end of the group (i.e. enough signals
191+ for the entire G1 group) to ensure that waiters which have not
192+ yet blocked in the futex will not block.
193+ Note that in the vast majority of cases, this should never
194+ actually be necessary, since __g_signals will have enough
195+ signals for the remaining g_refs waiters. As an optimization,
196+ we could check this first before proceeding, although that
197+ could still leave the potential for futex lost wakeup bugs
198+ if the signal count was non-zero but the futex wakeup
199+ was somehow lost. */
200+ atomic_store_release (cond->__data.__g_signals + g1, lowseq);
201+
202+ futex_wake (cond->__data.__g_signals + g1, INT_MAX, private);
203+ }
204 /* At this point, the old G1 is now a valid new G2 (but not in use yet).
205 No old waiter can neither grab a signal nor acquire a reference without
206 noticing that __g1_start is larger.
207@@ -311,6 +271,10 @@ __condvar_quiesce_and_switch_g1 (pthread_cond_t *cond, uint64_t wseq,
208 g1 ^= 1;
209 *g1index ^= 1;
210
211+ /* Now advance the new G1 g_signals to the new lowseq, giving it
212+ an effective signal count of 0 to start. */
213+ atomic_store_release (cond->__data.__g_signals + g1, lowseq);
214+
215 /* These values are just observed by signalers, and thus protected by the
216 lock. */
217 unsigned int orig_size = wseq - (old_g1_start + old_orig_size);
218diff --git a/nptl/pthread_cond_wait.c b/nptl/pthread_cond_wait.c
219index 20c348a503..1cb3dbf7b0 100644
220--- a/nptl/pthread_cond_wait.c
221+++ b/nptl/pthread_cond_wait.c
222@@ -238,9 +238,7 @@ __condvar_cleanup_waiting (void *arg)
223 signaled), and a reference count.
224
225 The group reference count is used to maintain the number of waiters that
226- are using the group's futex. Before a group can change its role, the
227- reference count must show that no waiters are using the futex anymore; this
228- prevents ABA issues on the futex word.
229+ are using the group's futex.
230
231 To represent which intervals in the waiter sequence the groups cover (and
232 thus also which group slot contains G1 or G2), we use a 64b counter to
233@@ -300,11 +298,12 @@ __condvar_cleanup_waiting (void *arg)
234 last reference.
235 * Reference count used by waiters concurrently with signalers that have
236 acquired the condvar-internal lock.
237- __g_signals: The number of signals that can still be consumed.
238+ __g_signals: The number of signals that can still be consumed, relative to
239+ the current g1_start. (i.e. bits 31 to 1 of __g_signals are bits
240+ 31 to 1 of g1_start with the signal count added)
241 * Used as a futex word by waiters. Used concurrently by waiters and
242 signalers.
243- * LSB is true iff this group has been completely signaled (i.e., it is
244- closed).
245+ * LSB is currently reserved and 0.
246 __g_size: Waiters remaining in this group (i.e., which have not been
247 signaled yet.
248 * Accessed by signalers and waiters that cancel waiting (both do so only
249@@ -328,18 +327,6 @@ __condvar_cleanup_waiting (void *arg)
250 sufficient because if a waiter can see a sufficiently large value, it could
251 have also consume a signal in the waiters group.
252
253- Waiters try to grab a signal from __g_signals without holding a reference
254- count, which can lead to stealing a signal from a more recent group after
255- their own group was already closed. They cannot always detect whether they
256- in fact did because they do not know when they stole, but they can
257- conservatively add a signal back to the group they stole from; if they
258- did so unnecessarily, all that happens is a spurious wake-up. To make this
259- even less likely, __g1_start contains the index of the current g2 too,
260- which allows waiters to check if there aliasing on the group slots; if
261- there wasn't, they didn't steal from the current G1, which means that the
262- G1 they stole from must have been already closed and they do not need to
263- fix anything.
264-
265 It is essential that the last field in pthread_cond_t is __g_signals[1]:
266 The previous condvar used a pointer-sized field in pthread_cond_t, so a
267 PTHREAD_COND_INITIALIZER from that condvar implementation might only
268@@ -435,6 +422,9 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex,
269 {
270 while (1)
271 {
272+ uint64_t g1_start = __condvar_load_g1_start_relaxed (cond);
273+ unsigned int lowseq = (g1_start & 1) == g ? signals : g1_start & ~1U;
274+
275 /* Spin-wait first.
276 Note that spinning first without checking whether a timeout
277 passed might lead to what looks like a spurious wake-up even
278@@ -446,35 +436,45 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex,
279 having to compare against the current time seems to be the right
280 choice from a performance perspective for most use cases. */
281 unsigned int spin = maxspin;
282- while (signals == 0 && spin > 0)
283+ while (spin > 0 && ((int)(signals - lowseq) < 2))
284 {
285 /* Check that we are not spinning on a group that's already
286 closed. */
287- if (seq < (__condvar_load_g1_start_relaxed (cond) >> 1))
288- goto done;
289+ if (seq < (g1_start >> 1))
290+ break;
291
292 /* TODO Back off. */
293
294 /* Reload signals. See above for MO. */
295 signals = atomic_load_acquire (cond->__data.__g_signals + g);
296+ g1_start = __condvar_load_g1_start_relaxed (cond);
297+ lowseq = (g1_start & 1) == g ? signals : g1_start & ~1U;
298 spin--;
299 }
300
301- /* If our group will be closed as indicated by the flag on signals,
302- don't bother grabbing a signal. */
303- if (signals & 1)
304- goto done;
305-
306- /* If there is an available signal, don't block. */
307- if (signals != 0)
308+ if (seq < (g1_start >> 1))
309+ {
310+ /* If the group is closed already,
311+ then this waiter originally had enough extra signals to
312+ consume, up until the time its group was closed. */
313+ goto done;
314+ }
315+
316+ /* If there is an available signal, don't block.
317+ If __g1_start has advanced at all, then we must be in G1
318+ by now, perhaps in the process of switching back to an older
319+ G2, but in either case we're allowed to consume the available
320+ signal and should not block anymore. */
321+ if ((int)(signals - lowseq) >= 2)
322 break;
323
324 /* No signals available after spinning, so prepare to block.
325 We first acquire a group reference and use acquire MO for that so
326 that we synchronize with the dummy read-modify-write in
327 __condvar_quiesce_and_switch_g1 if we read from that. In turn,
328- in this case this will make us see the closed flag on __g_signals
329- that designates a concurrent attempt to reuse the group's slot.
330+ in this case this will make us see the advancement of __g_signals
331+ to the upcoming new g1_start that occurs with a concurrent
332+ attempt to reuse the group's slot.
333 We use acquire MO for the __g_signals check to make the
334 __g1_start check work (see spinning above).
335 Note that the group reference acquisition will not mask the
336@@ -482,15 +482,24 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex,
337 an atomic read-modify-write operation and thus extend the release
338 sequence. */
339 atomic_fetch_add_acquire (cond->__data.__g_refs + g, 2);
340- if (((atomic_load_acquire (cond->__data.__g_signals + g) & 1) != 0)
341- || (seq < (__condvar_load_g1_start_relaxed (cond) >> 1)))
342+ signals = atomic_load_acquire (cond->__data.__g_signals + g);
343+ g1_start = __condvar_load_g1_start_relaxed (cond);
344+ lowseq = (g1_start & 1) == g ? signals : g1_start & ~1U;
345+
346+ if (seq < (g1_start >> 1))
347 {
348- /* Our group is closed. Wake up any signalers that might be
349- waiting. */
350+ /* group is closed already, so don't block */
351 __condvar_dec_grefs (cond, g, private);
352 goto done;
353 }
354
355+ if ((int)(signals - lowseq) >= 2)
356+ {
357+ /* a signal showed up or G1/G2 switched after we grabbed the refcount */
358+ __condvar_dec_grefs (cond, g, private);
359+ break;
360+ }
361+
362 // Now block.
363 struct _pthread_cleanup_buffer buffer;
364 struct _condvar_cleanup_buffer cbuffer;
365@@ -501,7 +510,7 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex,
366 __pthread_cleanup_push (&buffer, __condvar_cleanup_waiting, &cbuffer);
367
368 err = __futex_abstimed_wait_cancelable64 (
369- cond->__data.__g_signals + g, 0, clockid, abstime, private);
370+ cond->__data.__g_signals + g, signals, clockid, abstime, private);
371
372 __pthread_cleanup_pop (&buffer, 0);
373
374@@ -524,6 +533,8 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex,
375 signals = atomic_load_acquire (cond->__data.__g_signals + g);
376 }
377
378+ if (seq < (__condvar_load_g1_start_relaxed (cond) >> 1))
379+ goto done;
380 }
381 /* Try to grab a signal. Use acquire MO so that we see an up-to-date value
382 of __g1_start below (see spinning above for a similar case). In
383@@ -532,69 +543,6 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex,
384 while (!atomic_compare_exchange_weak_acquire (cond->__data.__g_signals + g,
385 &signals, signals - 2));
386
387- /* We consumed a signal but we could have consumed from a more recent group
388- that aliased with ours due to being in the same group slot. If this
389- might be the case our group must be closed as visible through
390- __g1_start. */
391- uint64_t g1_start = __condvar_load_g1_start_relaxed (cond);
392- if (seq < (g1_start >> 1))
393- {
394- /* We potentially stole a signal from a more recent group but we do not
395- know which group we really consumed from.
396- We do not care about groups older than current G1 because they are
397- closed; we could have stolen from these, but then we just add a
398- spurious wake-up for the current groups.
399- We will never steal a signal from current G2 that was really intended
400- for G2 because G2 never receives signals (until it becomes G1). We
401- could have stolen a signal from G2 that was conservatively added by a
402- previous waiter that also thought it stole a signal -- but given that
403- that signal was added unnecessarily, it's not a problem if we steal
404- it.
405- Thus, the remaining case is that we could have stolen from the current
406- G1, where "current" means the __g1_start value we observed. However,
407- if the current G1 does not have the same slot index as we do, we did
408- not steal from it and do not need to undo that. This is the reason
409- for putting a bit with G2's index into__g1_start as well. */
410- if (((g1_start & 1) ^ 1) == g)
411- {
412- /* We have to conservatively undo our potential mistake of stealing
413- a signal. We can stop trying to do that when the current G1
414- changes because other spinning waiters will notice this too and
415- __condvar_quiesce_and_switch_g1 has checked that there are no
416- futex waiters anymore before switching G1.
417- Relaxed MO is fine for the __g1_start load because we need to
418- merely be able to observe this fact and not have to observe
419- something else as well.
420- ??? Would it help to spin for a little while to see whether the
421- current G1 gets closed? This might be worthwhile if the group is
422- small or close to being closed. */
423- unsigned int s = atomic_load_relaxed (cond->__data.__g_signals + g);
424- while (__condvar_load_g1_start_relaxed (cond) == g1_start)
425- {
426- /* Try to add a signal. We don't need to acquire the lock
427- because at worst we can cause a spurious wake-up. If the
428- group is in the process of being closed (LSB is true), this
429- has an effect similar to us adding a signal. */
430- if (((s & 1) != 0)
431- || atomic_compare_exchange_weak_relaxed
432- (cond->__data.__g_signals + g, &s, s + 2))
433- {
434- /* If we added a signal, we also need to add a wake-up on
435- the futex. We also need to do that if we skipped adding
436- a signal because the group is being closed because
437- while __condvar_quiesce_and_switch_g1 could have closed
438- the group, it might stil be waiting for futex waiters to
439- leave (and one of those waiters might be the one we stole
440- the signal from, which cause it to block using the
441- futex). */
442- futex_wake (cond->__data.__g_signals + g, 1, private);
443- break;
444- }
445- /* TODO Back off. */
446- }
447- }
448- }
449-
450 done:
451
452 /* Confirm that we have been woken. We do that before acquiring the mutex
453--
4542.49.0
455
diff --git a/meta/recipes-core/glibc/glibc_2.35.bb b/meta/recipes-core/glibc/glibc_2.35.bb
index 1ea4d5a252..f15e031971 100644
--- a/meta/recipes-core/glibc/glibc_2.35.bb
+++ b/meta/recipes-core/glibc/glibc_2.35.bb
@@ -62,6 +62,7 @@ SRC_URI = "${GLIBC_GIT_URI};branch=${SRCBRANCH};name=glibc \
62 file://0023-timezone-Make-shell-interpreter-overridable-in-tzsel.patch \ 62 file://0023-timezone-Make-shell-interpreter-overridable-in-tzsel.patch \
63 file://0024-fix-create-thread-failed-in-unprivileged-process-BZ-.patch \ 63 file://0024-fix-create-thread-failed-in-unprivileged-process-BZ-.patch \
64 file://0025-CVE-2025-4802.patch \ 64 file://0025-CVE-2025-4802.patch \
65 file://0026-PR25847-1.patch \
65 \ 66 \
66 file://0001-Revert-Linux-Implement-a-useful-version-of-_startup_.patch \ 67 file://0001-Revert-Linux-Implement-a-useful-version-of-_startup_.patch \
67 file://0002-get_nscd_addresses-Fix-subscript-typos-BZ-29605.patch \ 68 file://0002-get_nscd_addresses-Fix-subscript-typos-BZ-29605.patch \