Функція printk ()

Функція форматованого виведення повідомлень printk () працює аналогічно бібліотечної функції printf () мови С Дійсно в цій книзі до цього моменту ми не бачили ніяких істотних відмінностей в її використанні Для більшості завдань це саме так: функція printk () – це просто функція ядра, що виконує форматований вивід повідомлень Однак, деякі відмінності все ж є

Стійкість функції printk ()

Одне з перевірених і часто використовуваних властивостей функції printk () – це її стійкість Функцію print k () можна викликати практичнов будь-який час і в будь-якому місці ядра Її можна викликати з контексту переривання і з контексту процесу Її можна викликати під час утримання блокування Її можна викликати одночасно на декількох процесорах і вона не вимагає при цьому утримувати небудь блокування

Ця функція дуже стійка, і це дуже важливо, тому що корисність функції print k () базується на тому факті, що вона завжди доступна і завжди працює

Нестійкість функції printk ()

Слабке місце у функції printk () в плані стійкості все ж існує Її не можна використовувати до деякого моменту при завантаження ядра, поки консоль ще инициализирована Дійсно, якщо немає консолі, то куди будуть виводиться повідомлення

Звич про пов про не проблема, якщо не потрібно виконають ь налагодження коду, який ї виполняетс я на очен ь ранні х стадіях процес а завантаження (наприклад, функції setup_arch (), яка виконує ініціалізацію специфічну для апаратної платформи) Налагодження такого роду-справжнє завдання: відсутність будь-яких способів виведення повідомлень, а тільки проблема в повному складі

У таких ситуаціях теж є деякі обнадійливі моменти, але їх не багато Справжні хакери, які працюють з апаратурою на такому низькому рівні, для звязку із зовнішнім світом використовують апаратне забезпечення відповідної платформи, яке завжди працює (наприклад, послідовний порт) Повірте, що у більшості людей така робота не викличе радості Для одних апаратних платформ таке рішення працює, для інших платформ (включаючи платформу i386) існують латки коду, які теж дозволяють заощадити час

Одне з решени ї проблеми – варіант функції printk (), яка й може виводити інформацію па консоль на дуже ранніх стадіях процесу завантаження early_printk () Поведінка цієї функції аналогічно функції printk (), з а винятком імені і можливості працювати на дуже ранніх стадіях завантаження Однак, таке рішення не переносимо, тому що не для всіх підтримуваних апаратних платформ цей метод роботи реалізований Якщо ж він є, то може послужити хорошу службу

Крім ситуацій, коли необхідно виводити на консоль інформацію на дуже ранніх стадіях завантаження системи, можна покластися на функцію printk (), яка працює практично завжди

Рівні виведення повідомлень ядра

Головна відмінність між функціями printk () і printf () – це можливість у першому вказувати рівень виведення повідомлень ядра (loglevel)  Ядро використовує рівень виведення повідомлень для прийняття рішення про те, виводити повідомлення на консоль чи ні Ядро виводить на консоль все повідомлення з рівнями меншими, або рівними, відповідному значенням для консолі (console logleyel) Рівень виведення повідомлень можна вказувати наступним чином

printk (KERN_WARNTNG Це попередження \ n) printk (KERN_DEBUG Це налагоджувальне повідомлення \ n) printk (М Ин е вказали значення loqlevel \ n)

Рядки KERN_WARNING і KERN_DEBUG визначені через препроцесор в заголовному файлі Ці макроси розкриваються в рядки, соответстпенно <4> і <7>” , Які обєднуються з рядком формату на самому початку повідомлення, що виводиться функцією printk () Після цього на підставі рівня виподят повідомлення і рівня виведення консолі (значення змінної console_loglevel) ядро ​​приймає рішення виводити інформацію на консоль чи ні У табл 181 наведено повний список можливих значень рівня виведення повідомлень

Таблиця 181 Доступні значення рівня виведення повідомлень ядра (loglevel)

Значення loglevel Опис

KERN_EMERG KERN_ALERT KERN_CRIT KERN_ERR KERN_WARNING KERN_NOTICE KERN_INFO

KERN_DEBUG

Аварійна ситуація

Проблема, на яку потрібно негайно звернути увагу

Критична ситуація Помилка Попередження

Звичайна ситуація, але на яку слід звернути увагу

Інформаційне повідомлення

Налагоджувальні повідомлення – зазвичай надлишкова інформація

Якщо рівень виведення повідомлень ядра не вказаний, то його значени е за замовчуванням дорівнює DEFAULT_MESSAGE_LOGLEVEL, який в даний момент дорівнює KERN_ WARNING Так як це значення може змінитися, то для своїх повідомлень необхідно завжди вказувати рівень виводу

Найбільш важливий рівень виведення-KERN_EMERG визначений як <0>“, а найменш важливий – KERN_DEBUG, як <7>” Наприклад, після обробки препроцесором коду з попереднього прикладу виходить наступне

printk (<4> Етo попередження \ n) printk (<7> Це налагоджувальне повідомлення \ n) printk (<4> Ми не вказали значення loglevel \ n)

Як ви будете використовувати функцію printk () залежить тільки від вас Звичайно, звичайні повідомлення, які повинні бути видимі, повинні мати відповідний рівень виводу Налагоджувальні повідомлення, котори е у великій кількості вбудовуються в самі різні місця коду з метою розібратися з проблемою – припустимо помилка тут, пробуємо, працює можуть мати будь-який рівень виводу Один варіант – залишити рівень при якому повідомлення виводяться на консоль рівним значенню цього параметра за замовчуванням, а рівень виведення ваших повідомлень встановити в значення KERN_CRIT, або щось біля цього Можна вчинити і навпаки-для налагоджувальних повідомлень встановити рівень KERN_DEBUG і підняти рівень при якому повідомлення виводяться на консоль Кожен з варіантів має свої позитивні і негативні сторони – вам вирішувати

Рівні виведення повідомлень визначені у файлі

Буфер повідомлень ядра

Повідомлення ядра зберігаються в кільцевому буфері (log buffer) розміром LOG_BUF_LEN Цей розмір можна змінювати під час компіляції за допомогою параметра CONFIG_ LOG_BUF_SHIFT Для однопроцессорной машини це значення за замовчуванням дорівнює

16 Кбайт Іншими словами в ядрі може зберігається до 16 Кбайт системних повідомлень Якщо загальний розмір усіх повідомлень ядра досягає цього максимального значення і приходить нове повідомлення, то воно переписується поверх самого старого з зберігаються в буфері повідомлень Буфер повідомлень ядра називаєтьсякільцевим, тому що запис і зчитування повідомлень виконується по круговій схемі

Використання кільцевого буфера надає певні переваги Так як одночасні операції читання і запису в кільцевому буфері виконуються досить просто, то функцію printk () можна використовувати навіть з контексту переривання Більш того, це дозволяє просто організувати управління системними повідомленнями Якщо повідомлень виявляється дуже багато, то нові повідомлення просто затирають старі Якщо виникає проблема, яка проявляється в генерації великої кількості повідомлень, то буфер повідомлень просто починає переписувати себе замість того, щоб безконтрольно займати память Єдиний недолік кільцевого буфера – можливість втратити повідомлення, що не така вже й велика плата за ту стійкість, яку таке рішення надає

Демони syslogd і klogd

У стандартній системі Linux для вилучення повідомлень ядра з буфера використовується спеціальний демон простору користувача klogd, який направляє ці повідомлення в файл журналу системних повідомлень Для читання системних повідомлень програма klog d може зчитувати дані з файлу / proc / kmsg, або використовувати системний виклик syslog () За замовчуванням використовується підхід на

основі файлової системи / рrоc Якщо повідомлень немає, то демон klog d блокується на операції читання, поки не надійде нове повідомлення Коли приходить нове повідомлення, демон повертається до виконання, зчитує повідомлення і обробляє їх За замовчуванням повідомлення відправляються демону syslogd

Демон syslog d додає отримані повідомлення в кінець файлу журналу, за замовчуванням – / var / log / messages Імя відповідного файлу можна налаштувати в конфігураційному файлі / etc / syslogconf

Змінити рівень виведення повідомлень на консоль (console loglevel) можна при старті демона klog d за допомогою прапора-с

Зауваження щодо функції printk () і розробки ядра

Коли вперше починають розробляти код ядра, то швидше за все дуже часто доводиться замінювати функцію printf () на функцію printk () Це нормально, тому що не можна не брати до уваги багаторічний досвід з написання програм користувача і використанні функції printf () Слід сподіватися, що повторення таких помилок не буде тривати довго, тому що повторюються помилки компоновщика почнуть швидко набридати

Одного разу раптом виявиться, що ви зловили себе на тому, що почали використовувати функцію printk () замість функції printf () в призначених для користувача програмах Коли для вас цей день нарешті настане, то можна сказати, що ви стали справжнім хакером і фахівцем з розробки коду ядра

Джерело: Лав, Роберт Розробка ядра Linux, 2-е видання : Пер з англ – М: ТОВ «ІД Вільямс »2006 – 448 с : Ил – Парал тит англ

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*