скачать рефераты
  RSS    

Меню

Быстрый поиск

скачать рефераты

скачать рефератыРеферат: Побудова надійних операційних систем, що допускають наявність ненадійних драйверів пристроїв

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

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

Уникання тупиків

Оскільки за замовчуванням для IPC використовуються синхронні виклики SEND і RECEIVE, можуть виникати тупики, коли два або більше число процесів одночасно намагаються обмінюватися повідомленнями, і всі процеси блокуються в очікуванн один одного. Тому ми ретельно розробляли протокол уникнення тупиків, що приписує часткове, що сходить впорядкування повідомлень.

Впорядкування повідомлень приблизно відповідає розбивка на рівні, описаного в розд. 2.2. Наприклад, звичайним користувальницьким процесам дозволяється тільки посилати повідомлення з використанням примітиву SENDREC серверів, які реалізують нтерфейс POSIX, а ці сервери можуть запитувати сервіси від драйверів, які, у свою чергу, можуть виробляти виклики ядра. Однак для асинхронних подій, таких як переривання і таймери, потрібні повідомлення, що посилаються в протилежному напрямку, від ядра сервера або драйверу. Використання синхронних викликів SEND для передачі цих подій може легко призвести до глухого кута. Ми уникаємо ц проблеми шляхом використання для асинхронних подій механізму NOTIFY, який ніколи не блокує викликає бік. Якщо оповестітельное повідомлення не може бути доставлено процесу-адресату, воно зберігається в його елементі таблиці процесів до тих пір, поки він не виконає RECEIVE.

Хоча протокол уникнення тупиків підтримується обговорювалося вище механізмом масок посилки повідомлень, ми також реалізували в ядрі розпізнавання тупиків. Якщо виклик примітиву в деякому процесі непередбачуваних чином привів би до виникнення безвиході, то виконання примітиву не проводиться, і закликають учасника повертається повідомлення про помилку.

Уніфікація переривань і повідомлень

Базовим механізмом IPC є передача повідомлень на основі рандеву, але потрібні й асинхронні повідомлення, наприклад, для надання інформації про переривання, що потенційним джерелом помилок в операційних системах. Ми суттєво зменшили тут шанси на появу помилок, уніфікувавши асинхронні сигнали та повідомлення. Зазвичай, коли деякий процес посилає повідомлення іншому процесу і одержувач не готовим, відправник блокується. Ця схема не працює для переривань, оскільки обробник переривань не може дозволити собі блокування. Замість цього використовується асинхронний механізм сповіщень, при використанні якого обробник переривань виробляє виклик NOTIFY для драйвера. Якщо драйвер очіку повідомлення, то сповіщення доставляється безпосередньо. Якщо він його не очікує, то сповіщення зберігається в бітові масиви до тих пір, поки згодом драйвер не виконає виклик RECEIVE.

Обмеження функціональних можливостей драйвера

Ядро експортує обмежений набір функцій, які можна викликати ззовні. Цей ядерний API представляє собою єдиний спосіб взаємодії драйвера з ядром. Однак не кожному драйверу дозволяється використовувати будь-який виклик ядра. Для кожного драйвера в ядрі (в таблиці процесів) підтримується бітовий масив, який показує, які виклики ядра може виробляти цей драйвер. Гранулярні викликів ядра є досить дрібною. Відсутній мультиплексування викликів в один і той же номер функції. Кожен виклик індивідуально захищається власним бітом в бітові масиви. Проте на внутрішньому рівні кілька викликів може оброблятися однієї і тієї ж ядерно функцією. Цей метод дозволяє реалізувати детальне керування доступом до ядра.

Наприклад, деяким драйверам потрібен доступ по читанню і запису до даних, що знаходяться в призначених для користувача адресних просторах, але виклики для читання запису в цих просторах є різними. Так що ми не мультіплексіруем читання і запис в один виклик з використанням параметра «напрямок». Відповідно, можна дозволити, наприклад, драйверу принтера виконувати виклик ядра для читання даних з користувацьких процесів, але не дозволяти виконання викликів для запису. Внаслідок цього помилка в драйвері, якому дозволено тільки читання, не може призвести до випадкового пошкодження користувацького адресного простору.

Порівняємо цю ситуацію з можливим поведінкою драйвера у монолітному ядрі. Помилка в код може призвести до запису в адресний простір користувацького процесу замість читання з нього, що зруйнує процес. Крім того, ядерний драйвер може викликати будь-яку функцію в усьому ядрі, включаючи функції, які не повинні викликатися драйверами. Оскільки відсутня будь-яка внутрішньоядерні захист, це практично неможливо запобігти. У нашій розробці жоден драйвер не може викликати ядерну функцію, яка не була явно експортована як частина інтерфейсу між ядром і цим драйвером.

Заборона доступу до портів введення-виведення

Для кожного драйвера в ядрі підтримується список портів введення-виведення, з яких він може читати, а також тих, у які він може писати. Читання і запис захищаються по окремо, так що процес, у якого є право на тільки читання з деякого порту вводу-виводу, не може писати в нього. Будь-яка спроба порушення цих правил призводить до вироблення коду помилки, що повертається закликають учасника. Таким чином, драйвер принтера може бути обмежений доступом тільки до портів введення-виведення принтера, аудіо-драйвер може бути обмежений доступом тільки до портів введення-виведення звукової карти і т.д.

На відміну від цього, в монолітних системах відсутній спосіб обмеження доступу внутрішньоядерно драйвера тільки до невеликого числа портів введення-виведення. Ядерний драйвер може випадково виконати запис в будь-який порт вводу-виводу і завдати істотно шкоди.

У деяких випадках в адресний простір драйвера можуть відображатися реальні регістри пристрої введення-виведення, щоб уникнути якого б то не було взаємодії з ядром при здійсненні введення-виведення. Однак, оскільки не в усіх архітектурах допускається відображення регістрів введення-виведення в призначені для користувача процеси із забезпеченням необхідного рівня захисту, ми вибрали модель, в якій реальні операції введення-виведення виконуються тільки ядром. Це проектне рішення є ще одним прикладом того, що ми віддаємо перевагу надійност на шкоду ефективності.

Хоча в даний час таблиці, що дозволяють доступ до портів введення-виведення, ніціалізувалися з конфігураційного файлу, ми плануємо реалізувати сервер шини PCI, який буде робити це автоматично. Сервер шини PCI може отримати з BIOS порти введення-виведення, необхідні кожному драйверу, і використовувати цю нформацію для ініціалізації таблиць ядра.

Перевірка параметрів

Оскільки всі виклики ядра проводяться шляхом генерації внутрішнього переривання, ядро може виконати обмежену валідацію параметрів до диспетчеризації дзвінка. Ця валідація включає перевірки як справності (sanity), так і прав доступу (permission). Наприклад, якщо драйвер просить ядро записати блок даних з використанням фізичної адресації, то цей виклик може бути відхилений, оскільки не в усіх драйверів є право на такі дії. Використовуючи віртуальну адресацію, ядро, мабуть, не зможе сказати, чи є ця адреса записи правильним, але воно, принаймні, зможе перевірити, що ця адреса дійсно є допустимим адресою в сегменті даних або стека користувацького процесу, а не відноситься до сегменту тексту і не є якимось випадковим недійсним адресою.

Хоча такі перевірки справності є грубими, це краще, ніж нічого. У монолітних системах ніщо не перешкоджає драйверу виконувати запис за адресами, за якими не можна писати не за яких умов, таким як адреси в сегменті тексту ядра.

Відлов поганих покажчиків

У програмах на мовах C і C + + використовується безліч покажчиків, і ці програми весь час схильні помилок, пов'язаних з використанням поганих покажчиків. Разменованіе невірного покажчика часто призводить до виявлення апаратурою помилки сегментації. У нашій розробці сервер або драйвер, що намагаються разименовать поганий покажчик, примусово завершуються, і видається дамп пам'яті для майбутньої налагодження, точно так само, як і для інших користувальницьких процесів. Якщо поганий покажчик виявляється в частині операційної системи, що виконується в режимі користувача, то сервер реінкарнації негайно поміча наявність збійної ситуації і замінює примусово завершений процес його свіжою копією.

Приборкання нескінченних циклів

Коли драйвер впадає в нескінченний цикл, це створює загрозу споживання нескінченного часу ЦП. Планувальник зауважує наявність такої поведінки і поступово знижу пріоритет несправного процесу, поки він не стає непрацюючим процесом. Проте нші процеси можуть продовжувати нормально працювати. Після вичерпання зумовленого інтервалу часу сервер реінкарняціі помітить, що даний драйвер не відповідає на запити, примусово завершить і перезапустить його.

На відміну від цього, коли в нескінченний цикл впадає ядерний драйвер, він споживає весь час ЦП і фактично завішують всю систему.

Перевірка DMA

Однією з речей, яку ми не можемо забезпечити, є запобігання заподіяння шкоди систем через невірного DMA (Direct Memory Access, прямий доступ до пам'яті). Для запобігання перезапису драйвером через DMA довільної частини реальної пам'ят потрібно апаратна захист. Проте ми можемо виявити деякі помилки DMA наступним чином. DMA зазвичай запускається шляхом запису адреси DMA в деякий порт вводу-виводу. Ми можемо надати бібліотечну процедуру, яка викликається для запису в деякий порт вводу-виводу з попередніми декодуванням (способом, що залежить від пристрою) записів у цей порт вводу-виводу з метою знаходження використовуваних адрес DMA і перевірки їх допустимості. У зловмисних драйверах така перевірка може обходитися, але в добропорядних драйверах цей спосіб дозволяє виловити хоча б деякі помилки при помірних накладних витратах.

Залежно від апаратури ми можемо надійти ще краще. Якщо б на периферійної шині малося MMU (Memory Management Unit, пристрій управління пам'яттю) введення-виведення, ми могли б точно обмежити доступ до пам'яті для кожного драйвера [16]. Для систем з шиною PCI-X ми збираємося покласти на свій сервер шини PCI відповідальність за ініціалізацію таблиць MMU введення-виведення. Це частина нашої майбутньо роботи.


6. Аналіз надійності

Для перевірки надійності системи ми вручну внесли деякі ретельно підібрані помилки в деякі з своїх серверів і драйверів, щоб побачити, що в результат відбудеться. Як описувалося в розд. 3.3, наша система розробляється для виявлення та виправлення багатьох помилок, і саме це ми і спостерігали. Якщо з якої б то не було причини відбувався збій деякого компонента, це розпізнавалася сервером реінкарнації, який застосовував усі необхідні кошти для пожвавлення збійного компонента. Нижче це описується більш детально.

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

Другий клас складається з протокольних помилок, за наявності яких порушуються правила, що визначають поведінку серверів і драйверів. Наприклад, в нашій системі від серверів і драйверів потрібно відповідати на періодичні запити стану, що надходять від сервера реінкарнації. Якщо вони не підкоряються цьому правилу, робиться коригуючий дію. Наша система розробляється для боротьби з протокольними помилками.

Сервер реінкарнації

Сервер реінкарнації – це центральний сервер, керуючий усіма серверами і драйверами операційної системи. Він дозволяє істотно підвищити надійність, забезпечуючи:

1.         Негайне розпізнавання фатальних збоїв.

2.         Періодичний моніторинг стану.

Таким чином, він допомагає відловлювати два поширених виду збоїв: померлі або погано себе провідні системні процеси і негайно береться за вирішення найбільш гостро проблеми. Якщо системний процес завершується, то сервер реінкарнації безпосередньо оповіщається про це і перевіряє свої таблиці, щоб зрозуміти, чи слід перезапустити сервіс. Цей механізм, наприклад, забезпечує негайну заміну драйвера, примусово завершеного через використання поганого покажчика. Крім того, періодичний моніторинг стану допомагає дисциплінувати погано себе провідні системні сервіси. Наприклад, драйвер, який впадає в нескінченний цикл не може відповісти на запит стану від сервера реінкарнації, буде примусово завершений і перезапущений.

Заміна драйвера пристрою складається з суворо контрольованій послідовності дій. По-перше, сервер реінкарнації породжує новий процес, виконання якого затримується, оскільки для нього ще не призначено привілеї. Потім сервер реінкарнації повідомляє про новий драйвері файлової системи і, нарешті, призначає необхідні привілеї. Коли всі ці кроки успішно виконуються, новий процес починає працювати і виконує код драйвера, що береться з файлово системи. В якості додаткової обережності двійковий код деяких драйверів може дублюватися в основній пам'яті, щоб, наприклад, драйвер для диска коренево файлової системи можна було завантажити без потреби в обміні з диском.

Надійність рівня додатків

Наявність збійного драйвера може приводити до наслідків для файлової системи і додатків, що виробляють введення-виведення. Якщо у файлової системи був невиконаний запит вводу-виводу, їй буде повернуто код помилки, що говорить про збій драйвера. У цей момент можуть бути зроблені різні дії. Необхідно проводити відмінність між блоковими і символьними пристроями, тому що введення-виведення для блокових пристроїв буферізуется в буферному кеші файлової системи. На рис. 3 наводиться огляд різних сценаріїв відновлення на рівні програми.

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

Прозоре відновлення іноді є можливим і при збоях драйверів символьних пристроїв. Оскільки запит вводу-виводу не буферізуется в кеші блоків файлової системи, нформація про помилку вводу-виводу повинна бути доведена до програми. Якщо програма не може призвести відновлення, про проблему буде сповіщений користувач. Фактично, збої драйверів проштовхуються нагору, що призводить до різних сценаріїв відновлення. Наприклад, якщо відбувається збій драйвера Ethernet, то мережевий сервер помітить відсутність пакетів і зробить прозоре відновлення, якщо додаток використовує надійний транспортний протокол, такий як TCP. З іншого боку, якщо відбувається збій драйвера принтера, то користувач, звичайно, помітить, що його виведення на друк не вдався і повторить команду друку.

Таким чином, у багатьох випадках наша система може забезпечити повне відновлення на прикладному рівні. В решті випадках інформація про збої введення-виведення доводиться до користувача. Можна було б пом'якшити цю незручність шляхом використання тіньового драйвера для відновлення додатків, який використовували зіпсований драйвер в момент його фатального збою, застосовуючи методи, продемонстровані в [25]. Нам не дає зробити це брак робочої сіли.

Результати перевірки надійності

Для перевірки надійності своєї системи ми вручну внесли збої в деякі з своїх драйверів, щоб протестувати деякі види помилок і подивитися на те, що вийде. У найпростішому випадку ми завершували драйвер з застосуванням сигналу SIGKILL. Більш серйозні тестові випадки змушували драйвери разименовивать поган покажчики або впадати в нескінченний цикл. У всіх випадках сервер реінкарнац розпізнавав проблему і заміняв несправний драйвер свіжої копією.

Страницы: 1, 2, 3, 4


Новости

Быстрый поиск

Группа вКонтакте: новости

Пока нет

Новости в Twitter и Facebook

  скачать рефераты              скачать рефераты

Новости

скачать рефераты

© 2010.