~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/kernel/printk/nbcon.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 // Copyright (C) 2022 Linutronix GmbH, John Ogness
  3 // Copyright (C) 2022 Intel, Thomas Gleixner
  4 
  5 #include <linux/kernel.h>
  6 #include <linux/console.h>
  7 #include <linux/delay.h>
  8 #include <linux/slab.h>
  9 #include "internal.h"
 10 /*
 11  * Printk console printing implementation for consoles which does not depend
 12  * on the legacy style console_lock mechanism.
 13  *
 14  * The state of the console is maintained in the "nbcon_state" atomic
 15  * variable.
 16  *
 17  * The console is locked when:
 18  *
 19  *   - The 'prio' field contains the priority of the context that owns the
 20  *     console. Only higher priority contexts are allowed to take over the
 21  *     lock. A value of 0 (NBCON_PRIO_NONE) means the console is not locked.
 22  *
 23  *   - The 'cpu' field denotes on which CPU the console is locked. It is used
 24  *     to prevent busy waiting on the same CPU. Also it informs the lock owner
 25  *     that it has lost the lock in a more complex scenario when the lock was
 26  *     taken over by a higher priority context, released, and taken on another
 27  *     CPU with the same priority as the interrupted owner.
 28  *
 29  * The acquire mechanism uses a few more fields:
 30  *
 31  *   - The 'req_prio' field is used by the handover approach to make the
 32  *     current owner aware that there is a context with a higher priority
 33  *     waiting for the friendly handover.
 34  *
 35  *   - The 'unsafe' field allows to take over the console in a safe way in the
 36  *     middle of emitting a message. The field is set only when accessing some
 37  *     shared resources or when the console device is manipulated. It can be
 38  *     cleared, for example, after emitting one character when the console
 39  *     device is in a consistent state.
 40  *
 41  *   - The 'unsafe_takeover' field is set when a hostile takeover took the
 42  *     console in an unsafe state. The console will stay in the unsafe state
 43  *     until re-initialized.
 44  *
 45  * The acquire mechanism uses three approaches:
 46  *
 47  *   1) Direct acquire when the console is not owned or is owned by a lower
 48  *      priority context and is in a safe state.
 49  *
 50  *   2) Friendly handover mechanism uses a request/grant handshake. It is used
 51  *      when the current owner has lower priority and the console is in an
 52  *      unsafe state.
 53  *
 54  *      The requesting context:
 55  *
 56  *        a) Sets its priority into the 'req_prio' field.
 57  *
 58  *        b) Waits (with a timeout) for the owning context to unlock the
 59  *           console.
 60  *
 61  *        c) Takes the lock and clears the 'req_prio' field.
 62  *
 63  *      The owning context:
 64  *
 65  *        a) Observes the 'req_prio' field set on exit from the unsafe
 66  *           console state.
 67  *
 68  *        b) Gives up console ownership by clearing the 'prio' field.
 69  *
 70  *   3) Unsafe hostile takeover allows to take over the lock even when the
 71  *      console is an unsafe state. It is used only in panic() by the final
 72  *      attempt to flush consoles in a try and hope mode.
 73  *
 74  *      Note that separate record buffers are used in panic(). As a result,
 75  *      the messages can be read and formatted without any risk even after
 76  *      using the hostile takeover in unsafe state.
 77  *
 78  * The release function simply clears the 'prio' field.
 79  *
 80  * All operations on @console::nbcon_state are atomic cmpxchg based to
 81  * handle concurrency.
 82  *
 83  * The acquire/release functions implement only minimal policies:
 84  *
 85  *   - Preference for higher priority contexts.
 86  *   - Protection of the panic CPU.
 87  *
 88  * All other policy decisions must be made at the call sites:
 89  *
 90  *   - What is marked as an unsafe section.
 91  *   - Whether to spin-wait if there is already an owner and the console is
 92  *     in an unsafe state.
 93  *   - Whether to attempt an unsafe hostile takeover.
 94  *
 95  * The design allows to implement the well known:
 96  *
 97  *     acquire()
 98  *     output_one_printk_record()
 99  *     release()
100  *
101  * The output of one printk record might be interrupted with a higher priority
102  * context. The new owner is supposed to reprint the entire interrupted record
103  * from scratch.
104  */
105 
106 /**
107  * nbcon_state_set - Helper function to set the console state
108  * @con:        Console to update
109  * @new:        The new state to write
110  *
111  * Only to be used when the console is not yet or no longer visible in the
112  * system. Otherwise use nbcon_state_try_cmpxchg().
113  */
114 static inline void nbcon_state_set(struct console *con, struct nbcon_state *new)
115 {
116         atomic_set(&ACCESS_PRIVATE(con, nbcon_state), new->atom);
117 }
118 
119 /**
120  * nbcon_state_read - Helper function to read the console state
121  * @con:        Console to read
122  * @state:      The state to store the result
123  */
124 static inline void nbcon_state_read(struct console *con, struct nbcon_state *state)
125 {
126         state->atom = atomic_read(&ACCESS_PRIVATE(con, nbcon_state));
127 }
128 
129 /**
130  * nbcon_state_try_cmpxchg() - Helper function for atomic_try_cmpxchg() on console state
131  * @con:        Console to update
132  * @cur:        Old/expected state
133  * @new:        New state
134  *
135  * Return: True on success. False on fail and @cur is updated.
136  */
137 static inline bool nbcon_state_try_cmpxchg(struct console *con, struct nbcon_state *cur,
138                                            struct nbcon_state *new)
139 {
140         return atomic_try_cmpxchg(&ACCESS_PRIVATE(con, nbcon_state), &cur->atom, new->atom);
141 }
142 
143 /**
144  * nbcon_seq_read - Read the current console sequence
145  * @con:        Console to read the sequence of
146  *
147  * Return:      Sequence number of the next record to print on @con.
148  */
149 u64 nbcon_seq_read(struct console *con)
150 {
151         unsigned long nbcon_seq = atomic_long_read(&ACCESS_PRIVATE(con, nbcon_seq));
152 
153         return __ulseq_to_u64seq(prb, nbcon_seq);
154 }
155 
156 /**
157  * nbcon_seq_force - Force console sequence to a specific value
158  * @con:        Console to work on
159  * @seq:        Sequence number value to set
160  *
161  * Only to be used during init (before registration) or in extreme situations
162  * (such as panic with CONSOLE_REPLAY_ALL).
163  */
164 void nbcon_seq_force(struct console *con, u64 seq)
165 {
166         /*
167          * If the specified record no longer exists, the oldest available record
168          * is chosen. This is especially important on 32bit systems because only
169          * the lower 32 bits of the sequence number are stored. The upper 32 bits
170          * are derived from the sequence numbers available in the ringbuffer.
171          */
172         u64 valid_seq = max_t(u64, seq, prb_first_valid_seq(prb));
173 
174         atomic_long_set(&ACCESS_PRIVATE(con, nbcon_seq), __u64seq_to_ulseq(valid_seq));
175 
176         /* Clear con->seq since nbcon consoles use con->nbcon_seq instead. */
177         con->seq = 0;
178 }
179 
180 /**
181  * nbcon_seq_try_update - Try to update the console sequence number
182  * @ctxt:       Pointer to an acquire context that contains
183  *              all information about the acquire mode
184  * @new_seq:    The new sequence number to set
185  *
186  * @ctxt->seq is updated to the new value of @con::nbcon_seq (expanded to
187  * the 64bit value). This could be a different value than @new_seq if
188  * nbcon_seq_force() was used or the current context no longer owns the
189  * console. In the later case, it will stop printing anyway.
190  */
191 static void nbcon_seq_try_update(struct nbcon_context *ctxt, u64 new_seq)
192 {
193         unsigned long nbcon_seq = __u64seq_to_ulseq(ctxt->seq);
194         struct console *con = ctxt->console;
195 
196         if (atomic_long_try_cmpxchg(&ACCESS_PRIVATE(con, nbcon_seq), &nbcon_seq,
197                                     __u64seq_to_ulseq(new_seq))) {
198                 ctxt->seq = new_seq;
199         } else {
200                 ctxt->seq = nbcon_seq_read(con);
201         }
202 }
203 
204 /**
205  * nbcon_context_try_acquire_direct - Try to acquire directly
206  * @ctxt:       The context of the caller
207  * @cur:        The current console state
208  *
209  * Acquire the console when it is released. Also acquire the console when
210  * the current owner has a lower priority and the console is in a safe state.
211  *
212  * Return:      0 on success. Otherwise, an error code on failure. Also @cur
213  *              is updated to the latest state when failed to modify it.
214  *
215  * Errors:
216  *
217  *      -EPERM:         A panic is in progress and this is not the panic CPU.
218  *                      Or the current owner or waiter has the same or higher
219  *                      priority. No acquire method can be successful in
220  *                      this case.
221  *
222  *      -EBUSY:         The current owner has a lower priority but the console
223  *                      in an unsafe state. The caller should try using
224  *                      the handover acquire method.
225  */
226 static int nbcon_context_try_acquire_direct(struct nbcon_context *ctxt,
227                                             struct nbcon_state *cur)
228 {
229         unsigned int cpu = smp_processor_id();
230         struct console *con = ctxt->console;
231         struct nbcon_state new;
232 
233         do {
234                 if (other_cpu_in_panic())
235                         return -EPERM;
236 
237                 if (ctxt->prio <= cur->prio || ctxt->prio <= cur->req_prio)
238                         return -EPERM;
239 
240                 if (cur->unsafe)
241                         return -EBUSY;
242 
243                 /*
244                  * The console should never be safe for a direct acquire
245                  * if an unsafe hostile takeover has ever happened.
246                  */
247                 WARN_ON_ONCE(cur->unsafe_takeover);
248 
249                 new.atom = cur->atom;
250                 new.prio        = ctxt->prio;
251                 new.req_prio    = NBCON_PRIO_NONE;
252                 new.unsafe      = cur->unsafe_takeover;
253                 new.cpu         = cpu;
254 
255         } while (!nbcon_state_try_cmpxchg(con, cur, &new));
256 
257         return 0;
258 }
259 
260 static bool nbcon_waiter_matches(struct nbcon_state *cur, int expected_prio)
261 {
262         /*
263          * The request context is well defined by the @req_prio because:
264          *
265          * - Only a context with a higher priority can take over the request.
266          * - There are only three priorities.
267          * - Only one CPU is allowed to request PANIC priority.
268          * - Lower priorities are ignored during panic() until reboot.
269          *
270          * As a result, the following scenario is *not* possible:
271          *
272          * 1. Another context with a higher priority directly takes ownership.
273          * 2. The higher priority context releases the ownership.
274          * 3. A lower priority context takes the ownership.
275          * 4. Another context with the same priority as this context
276          *    creates a request and starts waiting.
277          */
278 
279         return (cur->req_prio == expected_prio);
280 }
281 
282 /**
283  * nbcon_context_try_acquire_requested - Try to acquire after having
284  *                                       requested a handover
285  * @ctxt:       The context of the caller
286  * @cur:        The current console state
287  *
288  * This is a helper function for nbcon_context_try_acquire_handover().
289  * It is called when the console is in an unsafe state. The current
290  * owner will release the console on exit from the unsafe region.
291  *
292  * Return:      0 on success and @cur is updated to the new console state.
293  *              Otherwise an error code on failure.
294  *
295  * Errors:
296  *
297  *      -EPERM:         A panic is in progress and this is not the panic CPU
298  *                      or this context is no longer the waiter.
299  *
300  *      -EBUSY:         The console is still locked. The caller should
301  *                      continue waiting.
302  *
303  * Note: The caller must still remove the request when an error has occurred
304  *       except when this context is no longer the waiter.
305  */
306 static int nbcon_context_try_acquire_requested(struct nbcon_context *ctxt,
307                                                struct nbcon_state *cur)
308 {
309         unsigned int cpu = smp_processor_id();
310         struct console *con = ctxt->console;
311         struct nbcon_state new;
312 
313         /* Note that the caller must still remove the request! */
314         if (other_cpu_in_panic())
315                 return -EPERM;
316 
317         /*
318          * Note that the waiter will also change if there was an unsafe
319          * hostile takeover.
320          */
321         if (!nbcon_waiter_matches(cur, ctxt->prio))
322                 return -EPERM;
323 
324         /* If still locked, caller should continue waiting. */
325         if (cur->prio != NBCON_PRIO_NONE)
326                 return -EBUSY;
327 
328         /*
329          * The previous owner should have never released ownership
330          * in an unsafe region.
331          */
332         WARN_ON_ONCE(cur->unsafe);
333 
334         new.atom = cur->atom;
335         new.prio        = ctxt->prio;
336         new.req_prio    = NBCON_PRIO_NONE;
337         new.unsafe      = cur->unsafe_takeover;
338         new.cpu         = cpu;
339 
340         if (!nbcon_state_try_cmpxchg(con, cur, &new)) {
341                 /*
342                  * The acquire could fail only when it has been taken
343                  * over by a higher priority context.
344                  */
345                 WARN_ON_ONCE(nbcon_waiter_matches(cur, ctxt->prio));
346                 return -EPERM;
347         }
348 
349         /* Handover success. This context now owns the console. */
350         return 0;
351 }
352 
353 /**
354  * nbcon_context_try_acquire_handover - Try to acquire via handover
355  * @ctxt:       The context of the caller
356  * @cur:        The current console state
357  *
358  * The function must be called only when the context has higher priority
359  * than the current owner and the console is in an unsafe state.
360  * It is the case when nbcon_context_try_acquire_direct() returns -EBUSY.
361  *
362  * The function sets "req_prio" field to make the current owner aware of
363  * the request. Then it waits until the current owner releases the console,
364  * or an even higher context takes over the request, or timeout expires.
365  *
366  * The current owner checks the "req_prio" field on exit from the unsafe
367  * region and releases the console. It does not touch the "req_prio" field
368  * so that the console stays reserved for the waiter.
369  *
370  * Return:      0 on success. Otherwise, an error code on failure. Also @cur
371  *              is updated to the latest state when failed to modify it.
372  *
373  * Errors:
374  *
375  *      -EPERM:         A panic is in progress and this is not the panic CPU.
376  *                      Or a higher priority context has taken over the
377  *                      console or the handover request.
378  *
379  *      -EBUSY:         The current owner is on the same CPU so that the hand
380  *                      shake could not work. Or the current owner is not
381  *                      willing to wait (zero timeout). Or the console does
382  *                      not enter the safe state before timeout passed. The
383  *                      caller might still use the unsafe hostile takeover
384  *                      when allowed.
385  *
386  *      -EAGAIN:        @cur has changed when creating the handover request.
387  *                      The caller should retry with direct acquire.
388  */
389 static int nbcon_context_try_acquire_handover(struct nbcon_context *ctxt,
390                                               struct nbcon_state *cur)
391 {
392         unsigned int cpu = smp_processor_id();
393         struct console *con = ctxt->console;
394         struct nbcon_state new;
395         int timeout;
396         int request_err = -EBUSY;
397 
398         /*
399          * Check that the handover is called when the direct acquire failed
400          * with -EBUSY.
401          */
402         WARN_ON_ONCE(ctxt->prio <= cur->prio || ctxt->prio <= cur->req_prio);
403         WARN_ON_ONCE(!cur->unsafe);
404 
405         /* Handover is not possible on the same CPU. */
406         if (cur->cpu == cpu)
407                 return -EBUSY;
408 
409         /*
410          * Console stays unsafe after an unsafe takeover until re-initialized.
411          * Waiting is not going to help in this case.
412          */
413         if (cur->unsafe_takeover)
414                 return -EBUSY;
415 
416         /* Is the caller willing to wait? */
417         if (ctxt->spinwait_max_us == 0)
418                 return -EBUSY;
419 
420         /*
421          * Setup a request for the handover. The caller should try to acquire
422          * the console directly when the current state has been modified.
423          */
424         new.atom = cur->atom;
425         new.req_prio = ctxt->prio;
426         if (!nbcon_state_try_cmpxchg(con, cur, &new))
427                 return -EAGAIN;
428 
429         cur->atom = new.atom;
430 
431         /* Wait until there is no owner and then acquire the console. */
432         for (timeout = ctxt->spinwait_max_us; timeout >= 0; timeout--) {
433                 /* On successful acquire, this request is cleared. */
434                 request_err = nbcon_context_try_acquire_requested(ctxt, cur);
435                 if (!request_err)
436                         return 0;
437 
438                 /*
439                  * If the acquire should be aborted, it must be ensured
440                  * that the request is removed before returning to caller.
441                  */
442                 if (request_err == -EPERM)
443                         break;
444 
445                 udelay(1);
446 
447                 /* Re-read the state because some time has passed. */
448                 nbcon_state_read(con, cur);
449         }
450 
451         /* Timed out or aborted. Carefully remove handover request. */
452         do {
453                 /*
454                  * No need to remove request if there is a new waiter. This
455                  * can only happen if a higher priority context has taken over
456                  * the console or the handover request.
457                  */
458                 if (!nbcon_waiter_matches(cur, ctxt->prio))
459                         return -EPERM;
460 
461                 /* Unset request for handover. */
462                 new.atom = cur->atom;
463                 new.req_prio = NBCON_PRIO_NONE;
464                 if (nbcon_state_try_cmpxchg(con, cur, &new)) {
465                         /*
466                          * Request successfully unset. Report failure of
467                          * acquiring via handover.
468                          */
469                         cur->atom = new.atom;
470                         return request_err;
471                 }
472 
473                 /*
474                  * Unable to remove request. Try to acquire in case
475                  * the owner has released the lock.
476                  */
477         } while (nbcon_context_try_acquire_requested(ctxt, cur));
478 
479         /* Lucky timing. The acquire succeeded while removing the request. */
480         return 0;
481 }
482 
483 /**
484  * nbcon_context_try_acquire_hostile - Acquire via unsafe hostile takeover
485  * @ctxt:       The context of the caller
486  * @cur:        The current console state
487  *
488  * Acquire the console even in the unsafe state.
489  *
490  * It can be permitted by setting the 'allow_unsafe_takeover' field only
491  * by the final attempt to flush messages in panic().
492  *
493  * Return:      0 on success. -EPERM when not allowed by the context.
494  */
495 static int nbcon_context_try_acquire_hostile(struct nbcon_context *ctxt,
496                                              struct nbcon_state *cur)
497 {
498         unsigned int cpu = smp_processor_id();
499         struct console *con = ctxt->console;
500         struct nbcon_state new;
501 
502         if (!ctxt->allow_unsafe_takeover)
503                 return -EPERM;
504 
505         /* Ensure caller is allowed to perform unsafe hostile takeovers. */
506         if (WARN_ON_ONCE(ctxt->prio != NBCON_PRIO_PANIC))
507                 return -EPERM;
508 
509         /*
510          * Check that try_acquire_direct() and try_acquire_handover() returned
511          * -EBUSY in the right situation.
512          */
513         WARN_ON_ONCE(ctxt->prio <= cur->prio || ctxt->prio <= cur->req_prio);
514         WARN_ON_ONCE(cur->unsafe != true);
515 
516         do {
517                 new.atom = cur->atom;
518                 new.cpu                 = cpu;
519                 new.prio                = ctxt->prio;
520                 new.unsafe              |= cur->unsafe_takeover;
521                 new.unsafe_takeover     |= cur->unsafe;
522 
523         } while (!nbcon_state_try_cmpxchg(con, cur, &new));
524 
525         return 0;
526 }
527 
528 static struct printk_buffers panic_nbcon_pbufs;
529 
530 /**
531  * nbcon_context_try_acquire - Try to acquire nbcon console
532  * @ctxt:       The context of the caller
533  *
534  * Return:      True if the console was acquired. False otherwise.
535  *
536  * If the caller allowed an unsafe hostile takeover, on success the
537  * caller should check the current console state to see if it is
538  * in an unsafe state. Otherwise, on success the caller may assume
539  * the console is not in an unsafe state.
540  */
541 __maybe_unused
542 static bool nbcon_context_try_acquire(struct nbcon_context *ctxt)
543 {
544         unsigned int cpu = smp_processor_id();
545         struct console *con = ctxt->console;
546         struct nbcon_state cur;
547         int err;
548 
549         nbcon_state_read(con, &cur);
550 try_again:
551         err = nbcon_context_try_acquire_direct(ctxt, &cur);
552         if (err != -EBUSY)
553                 goto out;
554 
555         err = nbcon_context_try_acquire_handover(ctxt, &cur);
556         if (err == -EAGAIN)
557                 goto try_again;
558         if (err != -EBUSY)
559                 goto out;
560 
561         err = nbcon_context_try_acquire_hostile(ctxt, &cur);
562 out:
563         if (err)
564                 return false;
565 
566         /* Acquire succeeded. */
567 
568         /* Assign the appropriate buffer for this context. */
569         if (atomic_read(&panic_cpu) == cpu)
570                 ctxt->pbufs = &panic_nbcon_pbufs;
571         else
572                 ctxt->pbufs = con->pbufs;
573 
574         /* Set the record sequence for this context to print. */
575         ctxt->seq = nbcon_seq_read(ctxt->console);
576 
577         return true;
578 }
579 
580 static bool nbcon_owner_matches(struct nbcon_state *cur, int expected_cpu,
581                                 int expected_prio)
582 {
583         /*
584          * Since consoles can only be acquired by higher priorities,
585          * owning contexts are uniquely identified by @prio. However,
586          * since contexts can unexpectedly lose ownership, it is
587          * possible that later another owner appears with the same
588          * priority. For this reason @cpu is also needed.
589          */
590 
591         if (cur->prio != expected_prio)
592                 return false;
593 
594         if (cur->cpu != expected_cpu)
595                 return false;
596 
597         return true;
598 }
599 
600 /**
601  * nbcon_context_release - Release the console
602  * @ctxt:       The nbcon context from nbcon_context_try_acquire()
603  */
604 static void nbcon_context_release(struct nbcon_context *ctxt)
605 {
606         unsigned int cpu = smp_processor_id();
607         struct console *con = ctxt->console;
608         struct nbcon_state cur;
609         struct nbcon_state new;
610 
611         nbcon_state_read(con, &cur);
612 
613         do {
614                 if (!nbcon_owner_matches(&cur, cpu, ctxt->prio))
615                         break;
616 
617                 new.atom = cur.atom;
618                 new.prio = NBCON_PRIO_NONE;
619 
620                 /*
621                  * If @unsafe_takeover is set, it is kept set so that
622                  * the state remains permanently unsafe.
623                  */
624                 new.unsafe |= cur.unsafe_takeover;
625 
626         } while (!nbcon_state_try_cmpxchg(con, &cur, &new));
627 
628         ctxt->pbufs = NULL;
629 }
630 
631 /**
632  * nbcon_context_can_proceed - Check whether ownership can proceed
633  * @ctxt:       The nbcon context from nbcon_context_try_acquire()
634  * @cur:        The current console state
635  *
636  * Return:      True if this context still owns the console. False if
637  *              ownership was handed over or taken.
638  *
639  * Must be invoked when entering the unsafe state to make sure that it still
640  * owns the lock. Also must be invoked when exiting the unsafe context
641  * to eventually free the lock for a higher priority context which asked
642  * for the friendly handover.
643  *
644  * It can be called inside an unsafe section when the console is just
645  * temporary in safe state instead of exiting and entering the unsafe
646  * state.
647  *
648  * Also it can be called in the safe context before doing an expensive
649  * safe operation. It does not make sense to do the operation when
650  * a higher priority context took the lock.
651  *
652  * When this function returns false then the calling context no longer owns
653  * the console and is no longer allowed to go forward. In this case it must
654  * back out immediately and carefully. The buffer content is also no longer
655  * trusted since it no longer belongs to the calling context.
656  */
657 static bool nbcon_context_can_proceed(struct nbcon_context *ctxt, struct nbcon_state *cur)
658 {
659         unsigned int cpu = smp_processor_id();
660 
661         /* Make sure this context still owns the console. */
662         if (!nbcon_owner_matches(cur, cpu, ctxt->prio))
663                 return false;
664 
665         /* The console owner can proceed if there is no waiter. */
666         if (cur->req_prio == NBCON_PRIO_NONE)
667                 return true;
668 
669         /*
670          * A console owner within an unsafe region is always allowed to
671          * proceed, even if there are waiters. It can perform a handover
672          * when exiting the unsafe region. Otherwise the waiter will
673          * need to perform an unsafe hostile takeover.
674          */
675         if (cur->unsafe)
676                 return true;
677 
678         /* Waiters always have higher priorities than owners. */
679         WARN_ON_ONCE(cur->req_prio <= cur->prio);
680 
681         /*
682          * Having a safe point for take over and eventually a few
683          * duplicated characters or a full line is way better than a
684          * hostile takeover. Post processing can take care of the garbage.
685          * Release and hand over.
686          */
687         nbcon_context_release(ctxt);
688 
689         /*
690          * It is not clear whether the waiter really took over ownership. The
691          * outermost callsite must make the final decision whether console
692          * ownership is needed for it to proceed. If yes, it must reacquire
693          * ownership (possibly hostile) before carefully proceeding.
694          *
695          * The calling context no longer owns the console so go back all the
696          * way instead of trying to implement reacquire heuristics in tons of
697          * places.
698          */
699         return false;
700 }
701 
702 /**
703  * nbcon_can_proceed - Check whether ownership can proceed
704  * @wctxt:      The write context that was handed to the write function
705  *
706  * Return:      True if this context still owns the console. False if
707  *              ownership was handed over or taken.
708  *
709  * It is used in nbcon_enter_unsafe() to make sure that it still owns the
710  * lock. Also it is used in nbcon_exit_unsafe() to eventually free the lock
711  * for a higher priority context which asked for the friendly handover.
712  *
713  * It can be called inside an unsafe section when the console is just
714  * temporary in safe state instead of exiting and entering the unsafe state.
715  *
716  * Also it can be called in the safe context before doing an expensive safe
717  * operation. It does not make sense to do the operation when a higher
718  * priority context took the lock.
719  *
720  * When this function returns false then the calling context no longer owns
721  * the console and is no longer allowed to go forward. In this case it must
722  * back out immediately and carefully. The buffer content is also no longer
723  * trusted since it no longer belongs to the calling context.
724  */
725 bool nbcon_can_proceed(struct nbcon_write_context *wctxt)
726 {
727         struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);
728         struct console *con = ctxt->console;
729         struct nbcon_state cur;
730 
731         nbcon_state_read(con, &cur);
732 
733         return nbcon_context_can_proceed(ctxt, &cur);
734 }
735 EXPORT_SYMBOL_GPL(nbcon_can_proceed);
736 
737 #define nbcon_context_enter_unsafe(c)   __nbcon_context_update_unsafe(c, true)
738 #define nbcon_context_exit_unsafe(c)    __nbcon_context_update_unsafe(c, false)
739 
740 /**
741  * __nbcon_context_update_unsafe - Update the unsafe bit in @con->nbcon_state
742  * @ctxt:       The nbcon context from nbcon_context_try_acquire()
743  * @unsafe:     The new value for the unsafe bit
744  *
745  * Return:      True if the unsafe state was updated and this context still
746  *              owns the console. Otherwise false if ownership was handed
747  *              over or taken.
748  *
749  * This function allows console owners to modify the unsafe status of the
750  * console.
751  *
752  * When this function returns false then the calling context no longer owns
753  * the console and is no longer allowed to go forward. In this case it must
754  * back out immediately and carefully. The buffer content is also no longer
755  * trusted since it no longer belongs to the calling context.
756  *
757  * Internal helper to avoid duplicated code.
758  */
759 static bool __nbcon_context_update_unsafe(struct nbcon_context *ctxt, bool unsafe)
760 {
761         struct console *con = ctxt->console;
762         struct nbcon_state cur;
763         struct nbcon_state new;
764 
765         nbcon_state_read(con, &cur);
766 
767         do {
768                 /*
769                  * The unsafe bit must not be cleared if an
770                  * unsafe hostile takeover has occurred.
771                  */
772                 if (!unsafe && cur.unsafe_takeover)
773                         goto out;
774 
775                 if (!nbcon_context_can_proceed(ctxt, &cur))
776                         return false;
777 
778                 new.atom = cur.atom;
779                 new.unsafe = unsafe;
780         } while (!nbcon_state_try_cmpxchg(con, &cur, &new));
781 
782         cur.atom = new.atom;
783 out:
784         return nbcon_context_can_proceed(ctxt, &cur);
785 }
786 
787 /**
788  * nbcon_enter_unsafe - Enter an unsafe region in the driver
789  * @wctxt:      The write context that was handed to the write function
790  *
791  * Return:      True if this context still owns the console. False if
792  *              ownership was handed over or taken.
793  *
794  * When this function returns false then the calling context no longer owns
795  * the console and is no longer allowed to go forward. In this case it must
796  * back out immediately and carefully. The buffer content is also no longer
797  * trusted since it no longer belongs to the calling context.
798  */
799 bool nbcon_enter_unsafe(struct nbcon_write_context *wctxt)
800 {
801         struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);
802 
803         return nbcon_context_enter_unsafe(ctxt);
804 }
805 EXPORT_SYMBOL_GPL(nbcon_enter_unsafe);
806 
807 /**
808  * nbcon_exit_unsafe - Exit an unsafe region in the driver
809  * @wctxt:      The write context that was handed to the write function
810  *
811  * Return:      True if this context still owns the console. False if
812  *              ownership was handed over or taken.
813  *
814  * When this function returns false then the calling context no longer owns
815  * the console and is no longer allowed to go forward. In this case it must
816  * back out immediately and carefully. The buffer content is also no longer
817  * trusted since it no longer belongs to the calling context.
818  */
819 bool nbcon_exit_unsafe(struct nbcon_write_context *wctxt)
820 {
821         struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);
822 
823         return nbcon_context_exit_unsafe(ctxt);
824 }
825 EXPORT_SYMBOL_GPL(nbcon_exit_unsafe);
826 
827 /**
828  * nbcon_emit_next_record - Emit a record in the acquired context
829  * @wctxt:      The write context that will be handed to the write function
830  *
831  * Return:      True if this context still owns the console. False if
832  *              ownership was handed over or taken.
833  *
834  * When this function returns false then the calling context no longer owns
835  * the console and is no longer allowed to go forward. In this case it must
836  * back out immediately and carefully. The buffer content is also no longer
837  * trusted since it no longer belongs to the calling context. If the caller
838  * wants to do more it must reacquire the console first.
839  *
840  * When true is returned, @wctxt->ctxt.backlog indicates whether there are
841  * still records pending in the ringbuffer,
842  */
843 __maybe_unused
844 static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt)
845 {
846         struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);
847         struct console *con = ctxt->console;
848         bool is_extended = console_srcu_read_flags(con) & CON_EXTENDED;
849         struct printk_message pmsg = {
850                 .pbufs = ctxt->pbufs,
851         };
852         unsigned long con_dropped;
853         struct nbcon_state cur;
854         unsigned long dropped;
855         bool done;
856 
857         /*
858          * The printk buffers are filled within an unsafe section. This
859          * prevents NBCON_PRIO_NORMAL and NBCON_PRIO_EMERGENCY from
860          * clobbering each other.
861          */
862 
863         if (!nbcon_context_enter_unsafe(ctxt))
864                 return false;
865 
866         ctxt->backlog = printk_get_next_message(&pmsg, ctxt->seq, is_extended, true);
867         if (!ctxt->backlog)
868                 return nbcon_context_exit_unsafe(ctxt);
869 
870         /*
871          * @con->dropped is not protected in case of an unsafe hostile
872          * takeover. In that situation the update can be racy so
873          * annotate it accordingly.
874          */
875         con_dropped = data_race(READ_ONCE(con->dropped));
876 
877         dropped = con_dropped + pmsg.dropped;
878         if (dropped && !is_extended)
879                 console_prepend_dropped(&pmsg, dropped);
880 
881         if (!nbcon_context_exit_unsafe(ctxt))
882                 return false;
883 
884         /* For skipped records just update seq/dropped in @con. */
885         if (pmsg.outbuf_len == 0)
886                 goto update_con;
887 
888         /* Initialize the write context for driver callbacks. */
889         wctxt->outbuf = &pmsg.pbufs->outbuf[0];
890         wctxt->len = pmsg.outbuf_len;
891         nbcon_state_read(con, &cur);
892         wctxt->unsafe_takeover = cur.unsafe_takeover;
893 
894         if (con->write_atomic) {
895                 done = con->write_atomic(con, wctxt);
896         } else {
897                 nbcon_context_release(ctxt);
898                 WARN_ON_ONCE(1);
899                 done = false;
900         }
901 
902         /* If not done, the emit was aborted. */
903         if (!done)
904                 return false;
905 
906         /*
907          * Since any dropped message was successfully output, reset the
908          * dropped count for the console.
909          */
910         dropped = 0;
911 update_con:
912         /*
913          * The dropped count and the sequence number are updated within an
914          * unsafe section. This limits update races to the panic context and
915          * allows the panic context to win.
916          */
917 
918         if (!nbcon_context_enter_unsafe(ctxt))
919                 return false;
920 
921         if (dropped != con_dropped) {
922                 /* Counterpart to the READ_ONCE() above. */
923                 WRITE_ONCE(con->dropped, dropped);
924         }
925 
926         nbcon_seq_try_update(ctxt, pmsg.seq + 1);
927 
928         return nbcon_context_exit_unsafe(ctxt);
929 }
930 
931 /**
932  * nbcon_alloc - Allocate buffers needed by the nbcon console
933  * @con:        Console to allocate buffers for
934  *
935  * Return:      True on success. False otherwise and the console cannot
936  *              be used.
937  *
938  * This is not part of nbcon_init() because buffer allocation must
939  * be performed earlier in the console registration process.
940  */
941 bool nbcon_alloc(struct console *con)
942 {
943         if (con->flags & CON_BOOT) {
944                 /*
945                  * Boot console printing is synchronized with legacy console
946                  * printing, so boot consoles can share the same global printk
947                  * buffers.
948                  */
949                 con->pbufs = &printk_shared_pbufs;
950         } else {
951                 con->pbufs = kmalloc(sizeof(*con->pbufs), GFP_KERNEL);
952                 if (!con->pbufs) {
953                         con_printk(KERN_ERR, con, "failed to allocate printing buffer\n");
954                         return false;
955                 }
956         }
957 
958         return true;
959 }
960 
961 /**
962  * nbcon_init - Initialize the nbcon console specific data
963  * @con:        Console to initialize
964  *
965  * nbcon_alloc() *must* be called and succeed before this function
966  * is called.
967  *
968  * This function expects that the legacy @con->seq has been set.
969  */
970 void nbcon_init(struct console *con)
971 {
972         struct nbcon_state state = { };
973 
974         /* nbcon_alloc() must have been called and successful! */
975         BUG_ON(!con->pbufs);
976 
977         nbcon_seq_force(con, con->seq);
978         nbcon_state_set(con, &state);
979 }
980 
981 /**
982  * nbcon_free - Free and cleanup the nbcon console specific data
983  * @con:        Console to free/cleanup nbcon data
984  */
985 void nbcon_free(struct console *con)
986 {
987         struct nbcon_state state = { };
988 
989         nbcon_state_set(con, &state);
990 
991         /* Boot consoles share global printk buffers. */
992         if (!(con->flags & CON_BOOT))
993                 kfree(con->pbufs);
994 
995         con->pbufs = NULL;
996 }
997 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php