Чому існує політика ядра Linux, щоб ніколи не порушувати користувальницький простір?


38

Я почав думати над цим питанням у контексті етикету у списку розсилки ядра Linux. Як найвідоміший у світі та, напевно, найуспішніший та важливий проект вільного програмного забезпечення, ядро ​​Linux отримує багато преси. А засновнику та керівнику проекту Лінусу Торвальдсу тут явно не потрібне представлення.

Лінус час від часу викликає суперечки своїм полум’ям на LKML. Ці полум'я, за його власним визнанням, часто пов'язані з порушенням простору користувача. Що підводить мене до мого питання.

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

Як я розумію, заявлена ​​політика Лінуса полягає в тому, що не порушувати користувальницький простір козиряє все інше, включаючи якість коду. Чому це так важливо, і які плюси і мінуси такої політики?

(Очевидно, що в такій політиці послідовно застосовуються такі мінуси, оскільки Лінус час від часу має «незгоди» зі своїми головними лейтенантами в ЛКМЛ саме на цю тему. Наскільки я можу сказати, він завжди пробирається в цьому питанні.)


1
Ви неправильно написали ім’я Лінуса у вступі.
Ісмаїл Мігель

Це не я точно, але я забув подати свій голос і віддали свій голос.
Ісмаїл Мігель

Відповіді:


38

Причина не історична, а практична. Є багато багатьох багатьох програм, які працюють над ядром Linux; якщо інтерфейс ядра порушує ці програми, то всім потрібно буде оновити ці програми.

Тепер правда, що більшість програм насправді не залежать безпосередньо від інтерфейсів ядра ( система дзвінки ), а лише від інтерфейсів стандартної бібліотеки C (C обгортки навколо викликів системи). О, але яка стандартна бібліотека? Глібч? uClibC? Діетлібк? Біонік? Musl? тощо.

Але є також багато програм, які реалізують специфічні для ОС послуги і залежать від інтерфейсів ядра, які не піддаються стандартній бібліотеці. (У Linux багато з них пропонуються через /procта /sys.)

А далі є статично складені бінарні файли. Якщо оновлення ядра порушує одне з них, єдиним рішенням буде перекомпілювати їх. Якщо у вас є джерело: Linux також підтримує власні програми.

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

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

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

Це кілька нормально мати чітко визначений односторонню залежність. Сумно, але іноді неминуче. (...) Що НЕ нормально - це мати двосторонню залежність. Якщо HAL-код для простору користувача залежить від нового ядра, це нормально, хоча я підозрюю, що користувачі сподіваються, що це не "ядро тижня", а більше "ядро останніх кількох місяців".

Але якщо у вас є ДВІ ШЛЯХА залежність, вас накрутили. Це означає, що вам доведеться оновити в режимі блокування, і це просто НЕ ПРИЙОМНО. Для користувача це жахливо, але що ще важливіше, це жахливо для розробників, оскільки це означає, що ви не можете сказати, що "помилка трапилася", і робити такі дії, як спробувати звузити її бісекцією чи подібним.

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

офіційно ,

зворотна сумісність для [системних дзвінків, оголошених стабільними] буде гарантована принаймні 2 роки.

На практиці, однак,

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

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

Підсумовуючи це,

розбиття простору користувача вимагає виправлень на рівні програми

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


1
Дякую за відповідь. Отже, інтерфейси, які оголошені стабільними, є набором системних викликів POSIX? Моє запитання про історію полягає в тому, як ця практика розвивалася. Імовірно, оригінальні версії ядра Linux, принаймні спочатку, не турбувалися про поломку користувальницького простору.
Faheem Mitha

3
@FaheemMitha Так, з 1991 року . Я не думаю, що підхід Лінуса розвивався, він завжди був "інтерфейси для звичайних додатків не змінюються, інтерфейси для програмного забезпечення, які дуже сильно прив'язані до ядра, змінюються дуже рідко".
Жил "ТАК - перестань бути злим"

24

У будь-яких взаємозалежних системах є в основному два варіанти. Абстракція та інтеграція. (Я навмисно не використовую технічні умови). За допомогою абстракції ви говорите, що, коли ви здійснюєте виклик в API, який, хоча код за API може змінюватися, результат завжди буде однаковим. Наприклад, коли нам зателефонують, fs.open()нам не важливо, чи це мережевий диск, SSD або жорсткий диск, ми завжди отримаємо відкритий дескриптор файлів, з яким ми можемо працювати. Завдяки "інтеграції" мета - забезпечити "найкращий" спосіб зробити щось, навіть якщо спосіб зміниться. Наприклад, відкриття файлу може відрізнятися для спільної мережі, ніж для файлу на диску. Обидва способи досить широко використовуються на сучасному робочому столі Linux.

З точки зору розробників, це питання "працює з будь-якою версією" або "працює з певною версією". Чудовим прикладом цього є OpenGL. Більшість ігор налаштовані на роботу з певною версією OpenGL. Не має значення, чи збираєте ви з джерела. Якщо гра була написана для використання OpenGL 1.1, а ви намагаєтеся змусити її працювати на 3.x, ви не будете добре провести час. На іншому кінці спектру, деякі дзвінки, очікується, незважаючи ні на що. Наприклад, я хочу зателефонувати, fs.open()я не хочу байдуже, на якій версії ядра я перебуваю. Я просто хочу дескриптор файлу.

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

З точки зору комунальних питань, без по-справжньому вагомих причин абстракція завжди краще в складній системі. Наприклад, уявіть, чи fs.open()працювали б інакше залежно від версії ядра. Тоді для простої бібліотеки взаємодії з файловою системою потрібно було б підтримувати кілька сотень різних «відкритих файлів» методів (або, ймовірно, блоків). Коли вийшла нова версія ядра, ви не зможете "оновити", вам доведеться протестувати кожен використаний програмний продукт. Ядро 6.2.2 (підроблене) може просто зламати ваш текстовий редактор.

Для деяких прикладів реального світу OSX, як правило, не піклується про порушення простору користувача. Вони спрямовані на частіше "інтеграцію" над "абстракцією". І при кожному великому оновленні ОС все ламається. Це не означає, що один спосіб краще, ніж інший. Це вибір та дизайнерське рішення.

Найголовніше, що екосистема Linux наповнена дивовижними проектами з відкритими джерелами, де люди або групи працюють над проектом у вільний час або тому, що інструмент корисний. Зважаючи на це, друге, коли воно перестане бути веселим і починає бути PIA, ці розробники підуть кудись ще.

Наприклад, я подав патч BuildNotify.py. Не тому, що я альтруїст, а тому, що я використовую інструмент, і мені хотілося функції. Це було легко, так що тут, мати патч. Якби це було складно або громіздко, я б не користувався BuildNotify.pyі знайшов би щось інше. Якби кожен раз, коли з'являлось оновлення ядра, мій текстовий редактор зламався, я просто використовував би іншу ОС. Мої внески до громади (хоч і невеликі) не продовжувались б і не існували тощо.

Отже, проектне рішення було прийнято до абстрактних системних викликів, так що коли я fs.open()це роблю, це просто працює. Це означає збереження fs.openдовго після fs.open2()здобуття популярності.

Історично це мета POSIX систем загалом. "Ось набір викликів і очікувані значення повернення. Ви з'ясуєте середину." Знову з міркувань портативності. Чому Лінус вирішив використовувати цю методологію, є внутрішньою для його мозку, і вам доведеться попросити його точно знати, чому. Якби я, проте, я вибрав би абстракцію над інтеграцією на складній системі.


1
API до простору користувачів, API 'syscall', чітко визначений (особливо підмножина POSIX) і стабільний, оскільки видалення будь-якої його частини порушить програмне забезпечення, яке люди, можливо, встановили. У ньому немає стабільного API драйвера .
pjc50

4
@FaheemMitha, це навпаки. Розробники ядра можуть порушувати API драйверів коли завгодно, доки вони не виправлять усі драйвери в ядрі до наступного випуску. Порушення API простору користувачів або навіть те, що не стосується API, що може зламати простір користувачів, що створює епічні реакції від Linus.
Марк

4
Наприклад, якщо хтось вирішить змінити його, повернувши інший код помилки з ioctl () за деяких обставин: lkml.org/lkml/2012/12/23/75 (містить лайку та особисті атаки на відповідального розробника). Цей патч було відхилено, оскільки він би зламав PulseAudio, а отже, і все аудіо в системах GNOME.
pjc50

1
@FaheemMitha, в основному, def add (a, b); повернути a + b; кінець --- def add (a, b); c = a + b; повернути c; кінець --- def add (a, b); c = a + b +10; повернення c - 10; end - все це "однакова" реалізація add. Що його так засмучує, коли люди роблять def add (a, b); повернення (a + b) * -1; кінець По суті, змінити те, як "внутрішні" речі в ядрі працюють нормально. Зміна того, що повертається на визначений та "загальнодоступний" виклик API, не є. Існує два види викликів API - "приватний" та "загальнодоступний". Він вважає, що публічні дзвінки API ніколи не повинні змінюватися без поважних причин.
coteyr

3
Приклад без коду; Заходиш у магазин, купуєш 87 октанового газу. Ви, як споживач, не переймаєтесь, звідки надходив газ, або як він перероблявся. Ви просто дбаєте про те, щоб отримати газ. Якщо газ пройшов інший процес очищення, то вам все одно. Звичайно, процес очищення може змінитися. Існують навіть різні джерела нафти. Але те, що вам важливо - це отримати 87 октанового газу. Тож його позиція - це зміни джерел, зміна нафтопереробних заводів, зміна того, що коли-небудь, поки те, що виходить на насос, становить 87 октанового газу. Усі речі "поза кадром" не мають значення. Поки є 87 октанового газу.
coteyr

8

Це дизайнерське рішення та вибір. Linus хоче бути в змозі гарантувати розробникам простору користувачів, що, за винятком надзвичайно рідкісних та виняткових (наприклад, пов'язаних із безпекою) обставин, зміни ядра не порушать їх програми.

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

Мінуси полягають у тому, що ядро ​​має назавжди зберігати старий код та старі систематичні дзвінки тощо (або, принаймні, давно минулі дати їх використання).


Дякую за відповідь Чи знаєте ви про історію розвитку цього рішення? Я знаю про проекти, які мають дещо іншу точку зору. Наприклад, проект Mercurial не має фіксованого API, і він може порушити код, який спирається на нього.
Faheem Mitha

Ні, вибачте, я не можу згадати, як це сталося. Ви можете надіслати електронний лист Лінусу або LKML і запитати його.
cas

2
Mercurial - це не ОС. Вся суть ОС полягає в тому, щоб дозволити запускати інше програмне забезпечення поверх неї, і зламати це інше програмне забезпечення дуже непопулярно. Для порівняння, Windows також дуже довго підтримувала сумісність із зворотним рівнем; 16-розрядний код Windows був нещодавно застарілий.
pjc50

@ pjc50 Це правда, що Mercurial - це не ОС, але незалежно від цього є інше програмне забезпечення, навіть якщо це лише сценарії. І потенційно можуть бути порушені змінами.
Faheem Mitha
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.