LINUX.ORG.RU

Линус Торвальдс раскритиковал Rust в ядре

 ,


3

9

Линус Торвальдс критикует использование Rust в ядре. Причины: возможность panic(), неделимость библиотеки и соответственно опасные попытки использования 128 bit типов (в ядре запрещено), бесполезность предложенных примеров драйверов.

>>> Подробности

anonymous

Проверено: Shaman007 ()
Последнее исправление: alpha (всего исправлений: 3)

Ответ на: комментарий от anonymous-angler

В Rust стандартная библиотека имеет 3 слоя: coreallocstd. Все фичи языка доступны в core. Если подразумевается, что у системы есть какой-то глобальный аллокатор, то становится доступен alloc, если система может в Net, I/O, FS, Threads, и т.д. - это std.

anonymous-angler ★☆
()
Ответ на: комментарий от X512

с обработкой исключений

Согласно методичке, исключений в раст нет. Обработка panic! возможна (еще бы!), но порицается.

Проблема в panic! заключается в том, что это буквально исключения, благодаря которым в ядро не попал С++.

Siborgium ★★★★★
()
Ответ на: комментарий от BattleCoder

А возможность разыменования неправильного указателя (и ошибку сегментации) в C уже отменили что ли?

Вы не видите разницы между выбросом исключения и разыменованием нулевого указателя?

Siborgium ★★★★★
()
Ответ на: комментарий от meliafaro

Си просто напишет «Segmentation fault» и всё

Сразу видно разработчиков ядра.

hatred ★★★
()
Ответ на: комментарий от X512

Может лучше убрать странные запреты?

Ты только с x64 сталкивался? Не слышал про LP системы, где под задачу выделяется минимум ресурсов и Linux там вполне логичен/удобен и, более того, нормально работает. При этом 128 бит там в пень не сдались. А софтовая эмуляция уже как раз странное решение в этом случае будет.

hatred ★★★
()
Ответ на: комментарий от X512

Только serial debugging, только хардкор.

От как раз serial debugging норм такое себе решение. Тем паче, что ядро поддерживает оный через USB. Я потихоньку собираю компонентную базу, для USB-null modem с изолированными землями, как раз для подобной отладки. Идея простая: два USB-to-UART, но RX/TX и другие сигналы через быстрые оптопары. Каждая сторона получает своё питание, нет опасности ground-loop.

И да, таки и так ядро стектрейсами неплохо так кидаться может, без Rust. И часто только этого достаточно, что бы понять причину проблемы. И да, это не только при тотальном Kernel Panic возможно.

По сути, в том комменте была речь про User-space и обработку реакции на один и тот же сигнал от ядра, но разным рантаймом. Вот только рантайм в ядре у Си - это само ядро. И оно сильно отличается от оного в User-space ;-)

PS я уже говорил, что в ядре Linux тотальный ООП? С ручными vtable, наследованием и всё такое? :)

hatred ★★★
()
Ответ на: комментарий от zabbal

У сишечных фанатов такой радостный помпаж начался что половина даже по ссылке перейти не успели - срочно рванули делиться в комментах наболевшим и опухшим :-D

Вот что я увидел.

WatchCat ★★★★★
()
Ответ на: комментарий от ChekPuk

Обычно автор новости больше знает об обсуждаемом предмете. И в последнее время много новостей от анонимов. Это плохо. Кто-то стесняется? Или брезгует? Зачем тогда на лор ходит?

согласен. если уж новость пишешь, несложно и залогиниться. а иначе можно новости с токсами объединить. но Проверено: Shaman007 %(

я думаю, он сам один из тех, кто дурацкие комменты под анонимами пишет.

crypt ★★★★★
()
Последнее исправление: crypt (всего исправлений: 1)
Ответ на: комментарий от AVL2

а разве panic() в сишных драйверах невозможен?

Панику тогда вызовет не драйвер, а ядро, которое определит исключительную ситуацию (там достаточно много способов отмониторить и NULL-dereference и обращение не к той памяти и т.п.). Драйвер что-то делает. Обычно это что-то - реакция на внешние события. Например, что-то пошло не так, не смог выделить память в foo_probe(). Возвращаешь -ENOMEM. Не смог захватить ресурс, который, возможно, появится позже (например, чуть позже загрузится драйвер DMA), возвращай -EPROBE_DEFER (пишу по памяти). Эти ошибки обработаются инфраструктурой ядра. Если подобное случилось при IOCTL - ошибка пробросится в user-space, и уже прикладная программа решит, что делать. Аналогично для мини-драйверов, которые работают в составе фреймворков, типа dmaengine, i2c, spi, ALSA/ASoC, V4L2, только там сначала ошибка обрабатывается фреймворком и дальше - или ядру или пользователю.

Иными словами: драйвер ни прямо, ни косвенно (через цепочку вызовов) не должен звать panic().

Панику может вызвать только базовый, обслуживающий код, супервайзеры.

В Rust, насколько я понял, нормальная ситуация в недрах рантайма (псевдроядерный код):

struct vscaler_device *vdev = kzalloc_vscaler_dev();
if (!vdev)
  panic("scaler device");
hatred ★★★
()
Ответ на: комментарий от Pipidastre

Какой вопрос такой и ответ, в чём проблема?

WatchCat ★★★★★
()
Ответ на: комментарий от meliafaro

Земная жизнь для страданий

Когда имеешь дело с железом, там Си, это наименьший источник страданий:

  1. Наличие документации на железо/чипы, которая не соответствует реальности: это хуже её отсутствия. В случае отсутствия, при проектировании железа, ты просто этот модуль не используешь. А наличие, создаёт иллюзию того, что всё будет чики пуки. А по факту, твоя работа начинает мало отличаться от реверс-инжиниринга. Очень мешает нормальной оценке проектов.
  2. Драйвера от китайско/индусских товарищей, которые вроде и есть, но покрывают только какие-то узкие кейсы. Вкупе с документацией… Тоже мешает.
  3. Внезапные баги в железе. Когда оказывается, что твой use-case, не очень популярен, и просто мало человек с ним сталкивалось, а errata спрятана так глубоко, что не зная, чего конкретно искать, хрен найдёшь.
  4. Косорукие подрядчики, которые не смогли перерисовать и развести обвязку для чипа из его же даташита.
  5. Опытное производство, которое перепутало часть конденсаторов с резисторами.
  6. Сборщики на опытном производстве, которые криво воткнули шлейф, превратив его в бомбу замедленного действия, из-за которой волшебный белый дым вышел не сразу, а после энного времени мук и агонии и непонятно как работающего железа.
  7. Разработчики чипа, которые сделали SPI, но не совсем по спекам.
  8. Доступ к памяти: DMA (непрерывная и SG), virtual, user-space (и zero-copy между ними), выравнивания, паддинги.

Казалось бы… при чём тут программирование :-D Но это краткий список того, с чем я столкнулся как sw-разработчик за последний год. И Си в ядре это далеко не предел страданий :-)

hatred ★★★
()
Ответ на: комментарий от SkyMaverick

(например ошибки malloc - это тоже исключения, конечно но смысл процессу жить тогда).

В случае ядра Linux: процесс == всё ядро. Не нужно гасить то, что уже работает, а кто не смог - вернуть -ENOMEM наверх.

hatred ★★★
()
Ответ на: комментарий от BattleCoder

А возможность разыменования неправильного указателя (и ошибку сегментации) в C уже отменили что ли?

А кто это детектирует и сигнализирует (буквально, через SIGSEGV) процессу? А как это детектируется? А вы пробовали в модуле ядра разыменовать указатель на NULL? На произвольный участок? Обратиться к освобождённой памяти? Освободить память повторно? Что при этом наблюдается?

hatred ★★★
()
Последнее исправление: hatred (всего исправлений: 1)
Ответ на: комментарий от X512

что железо глючное

Эхех. Всё консюмерское железо глючное. Обкладывается костылями и подпорками. Возможно и не только консьмерское.

hatred ★★★
()
Ответ на: комментарий от hibou

Но здесь не совсем понятно, что имеет ввиду Линус.

Там всё понятно. По ссылке только про панику при невозможности аллокации. Драйвер в этом случае однозначно делает возврат -ENOMEM. Всё. Никакой паники. Паника прерогатива только Kernel-core, иными словами, инфраструктурного кода.

hatred ★★★
()
Ответ на: комментарий от Meyer

В NetBSD, кстати, поддержка Lua есть.

Если взять новый netfilter или как он там зовётся, то, по сути, это тоже отдельный язык внутри ядра. Обработка ACPI - своя виртуальная машина. В отличии от DeviceTree, там вполне себе могут быть функции, всякие инициалки для железа, блобы для программирования и всяких work-around железячных багов.

hatred ★★★
()
Ответ на: комментарий от red75prim

stack unwinding в ядре - это то ещё приключение.

Регулярная операция.

И как-то нужно гарантировать отсутствие выделений памяти в cleanup коде.

Решается резервированием памяти, обычно. Как 10% (или сколько там) пространства на ExtFS для root :-)

hatred ★★★
()
Ответ на: комментарий от X512

Ты прям заинтересовал Обероном) надо потыкать на досуге.

hatred ★★★
()
Ответ на: комментарий от matumba

Если вы решаете «проблемы с памятью», они должны решаться КОМПИЛЯТОРОМ, а не тем, что ударяете прогера по яйцам каждые 10 минут и заставляете играть в хоккей на костылях.

Так они и решаются. То, что ты назвал «удары по яйцам» на самом деле предложение компилятора объяснить ему, как ты собрался работать с памятью. Подразумевается, что это не java и программист понимает где объекты создаются, где живут и где умирают. Более того, так как программист пишет не лабу, а серьёзный код, подразумевается что эту информацию программист описал для тех кто придёт после него, в комментариях, и если что-то меняется, то информация в комментариях обновляется соответственно, причём не только там где поменяно, но и выше по стеку вызовов. Раст всего лишь предложил формальный язык для такого описания и компилятор, который сможет проверять, соответствует ли это описание реальности. Спотыкаются обычно просто от непривычки.

Рад, что Линус адекватно и без стеснения размазал эту «ржу» по просторам тырнетов.

Чувак, он просто сообщил, что конкретно в текущей либе раста не соответствует политике ядра. Даже в простом как валенок C код для юзерспейса и код для ядра отличается, другой аллокатор, те же флоаты нельзя. А если брать не язык, а компилятор gcc, то там ещё больше фич, которые в ядре запрещены. И ты не можешь просто скачать удобную библиотечку для парсинга JSON и заюзать её в ядре. С Растом то же самое, если будут двигать дальше - ну в худшем случае сделают особый kernellib, который будет несовместим с большинством крейтов, но как бы и так не предполагалось (надеюсь), что можно будет просто через карго накачать библиотек и собрать драйвер как собирается юзерспейс.

khrundel ★★★★
()
Ответ на: комментарий от hatred

Да это прикладники, что с них взять? Ладно бы это были просто прикладники (я сам прикладник, что греха таить), так они еще и думают, что кроме их юзерспейса и x64 ничего не существует, а сегфолты им посылает Сам Господь!

crutch_master ★★★★★
()
Последнее исправление: crutch_master (всего исправлений: 1)
Ответ на: комментарий от hatred

Ну так оно понятно, что это не пользовательское приложение и для kernel паниковать неприемлемо. Я ж и не спорю с этим утверждением. Это, я как понял, и есть один из основных критикуемых Линусом моментов и, как я понял, он то как раз решаемый и без внесения изменений в рантайм rust-а.

SkyMaverick ★★★★★
()
Ответ на: комментарий от Siborgium

Notes там для кого написан

Note that this function may not catch all panics in Rust. A panic in Rust is not always implemented via unwinding, but can be implemented by aborting the process as well. This function only catches unwinding panics, not those that abort the process.

Also note that unwinding into Rust code with a foreign exception (e.g. a an exception thrown from C++ code) is undefined behavior.

Ну и да, читаю руским по белому официальный перевод документации

Большинство языков не различают эти два вида ошибок и обрабатывают оба вида одинаково, используя такие механизмы, как исключения. В Rust нет исключений. Вместо этого он имеет тип Result<T, E> для обрабатываемых (исправимых) ошибок и макрос panic!, который останавливает выполнение, когда программа встречает необрабатываемую (неисправимую) ошибку.
SkyMaverick ★★★★★
()
Ответ на: комментарий от khrundel

Даже в простом как валенок C код для юзерспейса и код для ядра отличается

Ой, да ладно. У вас не подходит не какая-то либа от не понять кого, а базовые компоненты. Это все плата за вашу безопасность и хз сколько еще сюрпризов в этом поделии. В Си такой проблемы нет, аналогия вообще мимо. Вот что должно произойти здесь, если память не дали:

let arr = vec![0; 100500];

А если пуш не удастся? Будете накидывать ещё слой абстракции над массивом и ошибкой? С рантайм проверками? Ну да, низкоуровневый и системный. А 100500 проверок после каждого пуша сделают раст еще уродливей.

Чувак, он просто сообщил, что конкретно в текущей либе раста не соответствует политике ядра.

А еще он сказал, что не видит примера, где раст бы себя показал.

Сидели бы тихо и клепали бы хелоу ворлды, ну зачем серьезным дядькам на производство безопасные, пластиковые молотки? Обгадитесь на входе - позорно и обидно. Конечно, возможно вы зашкварите ядро своим входом, но надеюсь, разум победит.

pavlick ★★
()
Ответ на: комментарий от pavlick

Ой, да ладно. У вас не подходит не какая-то либа от не понять кого, а базовые компоненты.

Какие базовые компоненты? Вектор? Он в Расте даже на уровне синтаксиса не поддерживается, создаётся макросом. Напишут для ядра другой макрос для другого вектора. Чем это «базовее» malloc’а или printf’а в C? Соответственно и свои фантазии про неудавшийся пуш можешь запихать куда подальше, примерно туда же где могут сидеть фантазии про неподнявшуюся либу по парсингу JSON. Сделают для случая выхода индекса за границы другой panic!, который только драйвер выгружает, например.

Базовые компоненты Rust - это лайфтаймы и мув на уровне языка. Они никуда не исчезают.

А еще он сказал, что не видит примера, где раст бы себя показал.

И что? Ты вообще понимаешь насколько это тупо, из фразы «я не понимаю зачем вам X» от человека, который X не пользовался строить какие-то выводы? А если, положим, Линус не видит примера твоей личной полезности, ты что, самовыпиливаться пойдёшь? Ну не понимает и ладно, может поймёт. А может и нет, если бы в ядро попадало только то что лично Линусу нужно, Linux году к 1995 бы форкнулся, а финский студент пошёл бы работу искать.

Я вот лично не слежу в последнее время за Растом, но видимо всё вообще отлично, если хейтеры каждое высказывание в духе «я не фанат Раста» записывают в перемогу. Да даже если эти внедряторы всех достанут и их ссаными тряпками из мейлинглиста погонят, то Раст просто окажется в компании с примерно всеми остальными языками программирования, за исключением C и ассембрлера.

khrundel ★★★★
()
Ответ на: комментарий от khrundel

И что?

Можно начать с того, что он этого не говорил (Линус), как минимум в данном конкретном lkml-треде.

Линус говорит про то, что хотел бы видеть рабочий пример драйвера (там ЕМНИП даже предлагали NVMe реализовать, как вариант) конкретного устройства, который можно использовать на практике. Он хочет понимать наглядно, за каким лешим нужен Rust в ядре и какие практические проблемы это решает (какие создаёт?), а не просто «чтоб было, а там разберёмся».

SkyMaverick ★★★★★
()
Ответ на: комментарий от pavlick

Вот что должно произойти здесь, если память не дали:

let arr = vec![0; 100500];

В ядре этого кода не должно быть! Это из std. В пользовательском коде, пожалуйста. При этом не забываем, что обрабатывать этот вектор надо как-то так:

fn main() {
    let arr = vec![0; 100500];
    foo(&arr);
}

fn foo(arr: &[i32]) {
    println!("{}", arr.len());
}

alloc тоже не подходит. Так что всё ручками (смотри [no_std] библиотеки). При этом всё желательно сводить к одному KernelResult (или приводимое к нему). Тогда должно быть как-то так (очень схематично):

fn bar() -> KernelResult {
  let xs = KVec::try_new(100500)?;
  baz(&arr)?;
}
AlexVR ★★★★★
()
Ответ на: комментарий от khrundel

Какие базовые компоненты? Вектор? Он в Расте даже на уровне синтаксиса не поддерживается, создаётся макросом.

Ну вообще-то это не я на заборе написал, а оф дока раста здесь. Плевать как он там создается.

Чем это «базовее» malloc’а или printf’а в C?

Ну как бы понимаешь, что malloc и printf я могу слинковать с чем угодно и вернуть ошибку, а не падать? Поэтому пишите на своем Расте неответсвенные хелоу ворлды, ну негоже со свиным рылом в калашный ряд, а

Соответственно и свои фантазии про неудавшийся пуш можешь запихать куда подальше

просочиться во все щели засунь себе туда же.

pavlick ★★
()
Последнее исправление: pavlick (всего исправлений: 1)
Ответ на: комментарий от hatred

Регулярная операция.

Занятно. А почему тогда в стектрейсах в x86 не разбирают структуру ядерного стека, а используют эвристику: если число в стеке указывает куда-то внутрь кода ядра, то наверно это адрес функции.

https://www.kernel.org/doc/html/latest/x86/kernel-stacks.html#printing-backtraces-on-x86

А для ORC unwinder там недалеко есть такое предложение: «If GCC optimizations become too complicated for objtool to follow, the ORC data generation might stop working or become incomplete. (It’s worth noting that livepatch already has such a dependency on objtool’s ability to follow GCC code flow.)»

То есть корректность размотки стека не гарантируется.

red75prim ★★★
()
Последнее исправление: red75prim (всего исправлений: 2)
Ответ на: комментарий от pavlick

Ну вообще-то это не я на заборе написал, а оф дока раста здесь.

И что? Stl есть в доках по плюсам, что, не может существовать проекта на плюсах, в котором stl пользоваться запрещено? Если что, сам Страуструп требует забыть о new и delete и пользоваться умными указателями и контейнерами и при этом в каждом серьёзном проекте на плюсах запилена собственная версия умных строк.

В доках по C есть и malloc и printf, однако в ядре ими пользоваться запрещено. Даже больше, в доках есть float это вообще встроенный тип, и с ним тоже kernel нельзя.

Плевать как он там создается.

Да нет, не плевать. Во многих языках строковые литералы создают сложные объекты особого типа. В тех же плюсах базовая синтаксическая конструкция new подразумевает наличие аллокатора и тоже, кстати, не возвращает nullptr. В Расте вон выше написали, даже уже существующая стандартная либа заранее разбита на куски и уже, без напильника, можно писать на Расте без встроенного аллокатора.

Ну как бы понимаешь, что malloc и printf я могу слинковать с чем угодно и вернуть ошибку, а не падать?

Попробуй. Даже бог с ним с malloc и printf (последний, кстати, будет падать всегда и везде), попробуй добиться приёма в ядро 1 .c файла, который просто внутри себя, по всем стандартам языка C, определит макрос аналогичный по функционалу уже существующему в ядре, просто называющемуся иначе. Ну типа ты скопировал свой код и вместо того чтоб менять везде название макроса просто определил свой вначале файла.

khrundel ★★★★
()
Ответ на: комментарий от khrundel

в доках есть float это вообще встроенный тип, и с ним тоже kernel нельзя

не сказать чтобы совсем нельзя - это будет тормозить потому что если использовать FPU в ядре то при каждом переключении контекста требуется сохранять и восстанавливать регистры FPU

попробуй добиться приёма в ядро 1 .c файла, который просто внутри себя, по всем стандартам языка C, определит макрос аналогичный по функционалу уже существующему в ядре, просто называющемуся иначе.

не поверишь - их тысячи наверно

https://elixir.bootlin.com/linux/latest/source/drivers/gpu/drm/etnaviv/etnavi...

https://elixir.bootlin.com/linux/latest/source/include/drm/drm_print.h

spbob
()
Ответ на: комментарий от hatred

Я мало чего пробовал, я не программирую ядро. Но kernel panic иногда встречал. Удивительно, да? Наверное, panic() в rust-коде тоже сможет вызвать панику ядра. Называть это недостатком языка как-то странно. Ну свести к минимуму эти вызовы, когда без них никак (например, неожиданный отказ оборудования).

BattleCoder ★★★★★
()
Ответ на: комментарий от khrundel

И что? Stl есть в доках по плюсам, что, не может существовать проекта на плюсах, в котором stl пользоваться запрещено? Если что, сам Страуструп требует забыть о new и delete и пользоваться умными указателями и контейнерами и при этом в каждом серьёзном проекте на плюсах запилена собственная версия умных строк. В доках по C есть и malloc и printf, однако в ядре ими пользоваться запрещено. Даже больше, в доках есть float это вообще встроенный тип, и с ним тоже kernel нельзя.

В рамках Ц/ЦПП я всегда получу что-то валидное, которое вписывается в рамки стандарта. Если я буду компилить сишный модуль, где буду дергать malloc и printf, то он просто не скомпилится т.к libc просто не будет. Но если ядро захочет, то оно спокойно будет экспортировать символы malloc и printf. А у вас в расте ведь нет рантайма (я ничего не путаю?, т.е. нет условной libstdc++.so), т.е. ошибку при сборке ты не получишь.

В тех же плюсах базовая синтаксическая конструкция new подразумевает наличие аллокатора и тоже, кстати, не возвращает nullptr.

Вообще-то возвращает. А наличие исключений ты не заметил.

pavlick ★★
()
Последнее исправление: pavlick (всего исправлений: 3)
Ответ на: комментарий от Siborgium

Паника, в общем случае, не является аналогом исключений и не может быть поймана. Механизм, который делает её поведение похожим на исключения присущ std, которое в ядро никто не тащит. В ядре же драйвер может как-то маякнуть, что «всё рухнуло, хорони меня»? Вот - это и будет panic_handler.

anonymous-angler ★☆
()
Ответ на: комментарий от BattleCoder

Я мало чего пробовал, я не программирую ядро. Но kernel panic иногда встречал. Удивительно, да?

паника ядра означает что оно не может продолжить работу - например не может найти корневую файловую систему или init который по спецификации оно должно запустить

spbob
()
Ответ на: комментарий от spbob

Да, то же самое. А вот то, что код стандартных контейнеров дёргает её - это да, это для ядра неприемлимо. Но стандартные контейнеры в ядро можно и не тащить.

anonymous-angler ★☆
()
Ответ на: комментарий от anonymous-angler

Да, то же самое.

нет, ещё раз прочитай, но вряд ли до тебя дойдёт. Драйвер камеры может запросить у ядра дополнительный буфер DMA но в данный момент свободной памяти у аллокатора нет - например видео кодек тормозит - драйвер должен просто дропнуть кадр и работать дальше.

spbob
()
Ответ на: комментарий от spbob

Да, ещё раз тебе повторяю. panic!() - это эквивалент BUG(). И ещё раз повторяю тебе: Линус прав, что этого не должно происходить при выделении памяти, в частности. И то что сейчас это происходит - проблема стандартной библиотеки, а не языка, потому что именно она дёргает панику при безуспешном выделении памяти. Сам Rust, как язык, не знает ничего ни про какое выделение памяти.

anonymous-angler ★☆
()
Ответ на: комментарий от anonymous-angler

Линус прав, что этого не должно происходить при выделении памяти ... проблема стандартной библиотеки

это проблема людей которые портировали Rust для ядра - фундаментальное непонимание основ

spbob
()
Ответ на: комментарий от pavlick

Плевать как он там создается.

тогда вообще никакой конструктивной беседы у вас не выйдет. Т.к. плевать что вы там себе думаете будет логичным ответом.

abcq ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.