LINUX.ORG.RU

Снова «грязный дисковый кэш»


0

0

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

idle писал: есть какая-то документация про 2.4 vm, автор - Mel Gorman
так вот посмотрел я ее (Understanding The
Linux Virtual Memory Manager) -меня интересовали нити bdflush, kupdate, kswapd -но там только kswapd упоминается.
Так вот просветите меня если не трудно по таким вопросам:
кто из этих процессов помимо сбрасывания "грязных" данных освобождает страницы? И что значит освобождение страницы -это помещение ее в список inactive_clean, чтоб можно было использовать под другие данные?

> И что значит освобождение страницы

зависит от контекста, этому можно придать разный смысл

> это помещение ее в список inactive_clean, чтоб можно было
> использовать под другие данные?

я уже плохо помню, что было в 2.4, а смотреть лень.
в 2.6 inactive_clean нет, есть zone->{,in}active_list.

страицы в обоих списках не могут быть использованы сразу,
они могут быть mapped или dirty.

смотрите mm/vmscan.c:shrink_list() около метки free_it:,
вот там страницы освобождаются в том смысле, что могут
быть получены через alloc_page().

> кто из этих процессов помимо сбрасывания "грязных" данных
> освобождает страницы?

вы немного "не с той стороны" на это смотрите. никто из них
этого как бы и не делает.

грубо. кому-то нужна память, он вызывает __alloc_pages(), памяти
нет, она вызывает try_to_free_pages(), далее shrink_zone(),
shrink_cache(), shrink_list(), и у нас (возможно) появилась память.

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

>я уже плохо помню, что было в 2.4, а смотреть лень.
>в 2.6 inactive_clean нет, есть zone->{,in}active_list.

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

>страицы в обоих списках не могут быть использованы сразу,
>они могут быть mapped или dirty.

а когда они начинают использоваться, видимо после __alloc_pages().. ?

>смотрите mm/vmscan.c:shrink_list() около метки free_it:,
>вот там страницы освобождаются в том смысле, что могут
>быть получены через alloc_page().

это pegevec-функции чтоли

>вы немного "не с той стороны" на это смотрите. никто из них
>этого как бы и не делает.
>грубо. кому-то нужна память, он вызывает __alloc_pages(), памяти
>нет, она вызывает try_to_free_pages(), далее shrink_zone(),
>shrink_cache(), shrink_list(), и у нас (возможно) появилась память.

нет! страницы очищаются двумя путями: kswapd и "direct reclaim"(это имеется ввиду и __alloc_pages) -оба пути ведут к shrink_zone()
--это в 2.6



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

> > никто из них этого как бы и не делает.
> нет! страницы очищаются двумя путями: kswapd

да, конечно, я говорил про kupdate и bdflush.

try_to_free_pages() - это почти kswapd и есть, только
в контексте процесса, которому нужна память.

__alloc_pages() также сделает wake_up_kswapd().

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

idle:

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

mm - еще цветочки. вот fs, drivers/scsi - вот где реально не ступала нога человека. Наверное, небольшие порывы здравой мысли поживают только в kernel.

Главное, все ж куда-то идет, а базовый redesign лучше делать раньше, чем позже. В пень скорость, в пень поддержку кластеров - хочу, чтобы дыры находились раз в месяц, а не раз в неделю. :(

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

мда каша еще та..

> __alloc_pages() также сделает wake_up_kswapd()
это да, это я уже увидел..
тогда не понятно что имеется ввиду под термином "direct reclaim" (в комментариях к функции shrink_zone "..Used by both kswapd and direct reclaim" ), я предполагал что прямая очистка используется при выделении страниц.
кстати Mel Gorman про kswapd вот что пишет:
"Historically, kswapd used to wake up every 10 seconds but now it is only
woken by the physical page allocator when the pages_low number of free pages in
a zone is reached"

guestes
() автор топика
Ответ на: комментарий от Murr

Murr:
> Одним словом - каша.

не согласен. kswapd работает асинхронно и не имеет полной
информации о причине нехватки памяти и какая именно память
нужно именно сейчас, в момент __alloc_pages.

кроме того, у нас вполне может быть достаточно clean unmapped
pages в inactive_list, так что гораздо быстрее и проще получить
их через direct reclaim, чем ждать, когда это сделает kswapd.

так что я вижу определенный смысл в __alloc_page()->shrink_zone().

> mm - еще цветочки. вот fs, drivers/scsi - вот где реально не
> ступала нога человека.

моя нога туда точно не ступала (исключая очень поверхностного
знакомства с fs/*.c). легко могу поверить, что в drivers/
много не очень хорошего кода, и это вполне понятно. однако
vfs в linux мне не кажется устроенным плохо, но это вполне
может вызвано тем, что я очень плохо в нем разбираюсь.

> а базовый redesign лучше делать раньше, чем позже.

это нереально. кто будет этим заниматься? даже если кто-то
и станет, к тому моменту, когда этот дизайн будет подкреплен
хоть каким-то кодом (с массой ошибок, естественно), текущая
версия linux уйдет далеко вперед, и этот код никому не будет
интересен.

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

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

guestes:
> тогда не понятно что имеется ввиду под термином "direct reclaim"

то, что я приводил в качестве примера, try_to_free_pages() path,
я думаю.

> now it is only woken by the physical page allocator when the
> pages_low number of free pages in a zone is reached

ну так а я о чем говорил? если у нас нет памяти для __alloc_page,
то уже конечно у нас !zone_watermark_ok().

> мда каша еще та..

ох... ну вот как это по lor'овски. если вы задаете такие
детские вопросы про vm, понятно, что у вас каша. непонятно
почему _вы_ сразу делаете вывод, что эта каша в kernel.

конечно, вы имеете право на собственное мнения. приношу
извинения за мое плохое настроение.

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

idle:

Вообще, можем ли мы получить ENOMEM из ядра в том смысле, что нет доступной памяти? Помнится, в свое время у меня было такое развлечение: написал модуль, который лопал память из slab (а может и прямо через alloc_page), так вот что творилось на последних мегабайтах, наверное, описывать не надо.

Да и вспомнить последний race - page fault, опля, проверили на стек без блокирования (ну бог с ним - ошибка, конечно, но понятная и некритичная), но что происходит дальше - вызываем handle_mm_fault, который по анонимным mapping вообще до упора ни разу не проверяет границы VMA и устанавливает вслепую страницу, хотя если бы была некая разумная memory model, то мы просто упали бы в pager под его блокировкой и обнаружили, что вторая нить лезет куда не надо и вернули бы ей FAULT.

По хорошему, конечно, описанный Старзетцом код должен быть в критической секции, но опять же, IMHO, сие не есть дизайновая ошибка, а вот handle_mm_fault->...->do_anonymous_page - уже концептуальный глюк. Вообще, при чтении кода ядра Linux очень много где не берется блокировок, поскольку авторам кажется, что такая схема доступа невозможно, но благодаря отсутствию дизайна и недокументированности в какой-то момент кто-то ломает дизайн и очередной Старзетц находит очередную уязвимость. Типичный монолитный дизайн.

>однако vfs в linux мне не кажется устроенным плохо

Совершенно дурная концепция inode cache. В 2.4 нельзя перехватить вызов stat, т.к. вся информация берется из VFS inode. Так же непонятно зачем вообще нужен inode cache, поскольку ни одна часть ядра не может вызвать iget - iget вызывает обычно lookup той же файловой системы. Если и решишься использовать inode cache, то всплывает ограничение на размер inode number в unsigned long (32 бита на IA-32). Для некоторых файловых систем вообще понятие номера inode не очень естественно, как, например, в файловых системах с множественными потоками данных(наш случай). Печально как решаются такие проблемы - просто добавляются callbacks в драйвер где попало (а-ля read_inode2) вместо redesign.

Ввод-вывод в 2.4 - через buffer_head тоже еще тот маразм. Ну его порешили через bio и то хорошо. Но нет в интерфейсе возможности сбросить аппаратные кеши устройств. Нет, кстати, и интерфейса частичного сброса елеватора.

Потом те же prepare_write/commit_write/writepage. Было бы разумно избавиться от первых двух и пользовать только writepage, было бы меньше каши. Особенно маразматично выглядит в 2.4, когда generic функции абсолютно одинаково на несколько екранов занимаются выкладыванием страниц буферами, инициированием ввода-вывода и прочими глупостями. Еще ж у буферов куча состояний, часть из которых пересекается с состояниями страницы page cache.

От lock_kernel тоже до сих пор не могут избавиться (а есть ряд критичных мест под такой блокировкой).

>текущая версия linux уйдет далеко вперед

Куда вперед то? :) Для меня самым серьезным движением вперед Linux был бы redesign FS и MM.

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

> Вообще, можем ли мы получить ENOMEM из ядра в том смысле, что нет доступной памяти?

ЗАМЕЧАНИЕ: все, что я скажу следует понимать как AFAICS.

можем. во-первых, GFP_ATOMIC, но это понятно.

во-вторых, если память найти не удается, работает oom_kill(), и если он выберет
для убийства процесс, который пытается получить память, ему будет поставлен
PF_MEMDIE, после чего __alloc_pages() вернет NULL (после еще одной попытки найти
страницу в buffered_rmqueue()).

если такое поведение нежелательно - __GFP_NORETRY. в этом случае будет reclaim
до упора, но без oom и опять-таки NULL если памяти нет.

кроме того, если order > 3, try_to_free_pages() не будет вызываться в цикле.

далее. процессу ставится PF_MEMALLOC перед try_to_free_pages(), поэтому при
повторном входе в аллокатор (скажем, ему понадобится память для i/o), этот
флаг будет учитываться как PF_MEMDIE (собственно, они проверяются одновременно),
поэтому этот запрос также может вернуть NULL.

> Да и вспомнить последний race - page fault, опля, проверили на стек без блокирования

ЗАМЕЧАНИЕ: к AFAICS мысленно добавлять IMHO.

да ну, ошибка как ошибка, сколько таких уже было и будет.

> но что происходит дальше - вызываем handle_mm_fault, который по анонимным mapping вообще до упора
> ни разу не проверяет границы VMA и устанавливает вслепую страницу,

и совершенно правильно не проверяет. все границы и access rights уже проверены
в do_page_fault.

> хотя если бы была некая разумная memory model, то мы просто упали бы в pager под его блокировкой
> и обнаружили, что вторая нить лезет куда не надо и вернули бы ей FAULT.

именно так и делается, но вот в реализации этой проверки баг и был.
expand_stack() собственно часть этой проверки и есть.

> а вот handle_mm_fault->...->do_anonymous_page - уже концептуальный глюк.

не согласен.

> Вообще, при чтении кода ядра Linux очень много где не берется блокировок, поскольку авторам кажется,
> что такая схема доступа невозможно,

да, и стараются еще уменьшить. сейчас вот пытаются разгрузить page_table_lock
в do_page_fault path. сколько еще ошибок будет? perfomance...

> но благодаря отсутствию дизайна и недокументированности в какой-то момент кто-то ломает
> дизайн и очередной Старзетц находит очередную уязвимость. Типичный монолитный дизайн.

так он есть, или нет, дизайн-то? ;)

но это достаточно естественно. это в любом большом проекте бывает. добавили
фичу в одном месте, поломали в другом. что тут сделаешь? люди всегда будут
делать ошибки. да, документации нет. это плохо, некому написать. потому
что те, кто могли бы написать doc, пишут code.

> Печально как решаются такие проблемы - просто добавляются callbacks в драйвер где попало
> (а-ля read_inode2) вместо redesign.

вот хороший пример, где ты не прав (про IMHO не забываем :).

мне кажется, Linus и сотоварищи придерживаются правильного (прагматичного)
подхода. вот приходит reiserfs, и что делать? неужели менять дизайн и
переписывать linux, чтобы _попробовать_ включить эту fs? может, лучше
будет добавить нужный хак в кернел, чтобы оно _работало_ и тестировалось?
мне кажется - да.

конечно, есть шанс, что этот хак останется навечно, но это уже - добро
пожаловать в реальность!

этот read_inode2 из super_operations пропал.

про inode cache ничего не буду говорить, тк не знаю.

> Ввод-вывод в 2.4 - через buffer_head тоже еще тот маразм. Ну его порешили через bio и то хорошо.

маразм. да и весь block i/o никто не считал сделанным хорошо. о чем разговор?
никто (включая разработчиков) не утверждает, что все в linux замечательно.

> Потом те же prepare_write/commit_write/writepage. Было бы разумно избавиться от первых двух и пользовать только writepage,
> было бы меньше каши.

здесь мы вступаем на территорию, где ты явно лучше ориентируешься, но
я не согласен.

разделение prepare_write/commit_write очень разумно, и позволяет
факторизовать много общего кода (для простой fs реализация prepare_write
просто вызов generic helper с нужным параметром (*get_block)()).
то же самое про commit_write.

что касается writepage, то не забывай, что prepare_write работает
c _user-level_ данными (точнее, caller), а writepage - c page cache.
я уже не говорю про partial writes.

я бы рассматривал writepage как synchronization point для fdatawrite
path.

то есть, грубо говоря, я считаю, что нам нужно prepare_write/commit_write
для sys_write, а writepage для (например) того, чтобы kswapd/bdflush мог
отмыть страницу. или можно рассматривать это как вход и выход в page cache.

> От lock_kernel тоже до сих пор не могут избавиться (а есть ряд критичных мест под такой блокировкой).

ну это уже offtopic. конечно плохо, что этот рудимент сохранился, но
избавляются потихоньку, вот он уже из ioctl уходит. к дизайну это
не имеет отношения. в свое время это был весьма прагматичный подход
для начальной поддержки SMP, хотя сразу было понятно что вычищать его
нужно будет долго.

уфффф, устал даже :)

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

idle:

>ЗАМЕЧАНИЕ: все, что я скажу следует понимать как AFAICS.

Дык и я выражаю лишь свое личное мнение. :) Причем не kernel designer, а просто человека, использующего Linux в определенных целях. :)

>можем. во-первых, GFP_ATOMIC, но это понятно.

Я имел в виду не ошибки внутри ядра, а интерфейс системных вызовов. То есть мы запросили памяти, ядро решило, что памяти нет или не стоит устраивать paging в данной ситуации и вернуло ENOMEM. :)

>да ну, ошибка как ошибка, сколько таких уже было и будет. >> но что происходит дальше - вызываем handle_mm_fault, который по анонимным mapping вообще до упора >> ни разу не проверяет границы VMA и устанавливает вслепую страницу, > >и совершенно правильно не проверяет. все границы и access rights уже проверены >в do_page_fault. > >> хотя если бы была некая разумная memory model, то мы просто упали бы в pager под его блокировкой >> и обнаружили, что вторая нить лезет куда не надо и вернули бы ей FAULT. >именно так и делается, но вот в реализации этой проверки баг и был. >expand_stack() собственно часть этой проверки и есть.

Я имел в виду примерно следующее. mm должна быть построена в некой микромодели - т.е. должны быть четко выделены компоненты, задокументированы, которые защищают свои данные своими блокировками. То есть реализация того же pager должна быть скрыта в нем, а не быть размазана как в Linux по всему коду ядра. И уж вдвойне абсурдно, когда по случаю часть кода pager находится в архитектурно-зависимой части и делает часть проверок(в случае Linux неверных - благодаря тому, что код сильно размазан по ядру и плохо документирован), передавая дальше управление в середину нормального pager. По идее page fault должен просто передавать hint в pager, который уже под своими блокировками определяет будет ли он выдавать страницу или нет.

IMHO, вообще, концепция GROW VMA довольно глупа и самый красивый вариант обработки роста стека был бы в банальном обработчике сигнала в runtime библиотеке(SEGFAULT->проверка->mmap->return). Правда, было бы несколько медленнее. IMHO, надо по максимуму разгружать ядро в RT lib.

>так он есть, или нет, дизайн-то? ;)

С какой стороны посмотреть. Вроде с одной есть, а с другой ну совсем нет. :(

>но это достаточно естественно. это в любом большом проекте бывает. >добавили фичу в одном месте, поломали в другом. что тут сделаешь? >люди всегда будут делать ошибки. да, документации нет. это плохо, >некому написать. потому что те, кто могли бы написать doc, пишут >code.

Для распределенной разработки немало создано технологий, которые можно было применить для Linux, но никто не утруждается: проектирование, компоненты, документирование, моделирование, тесты.

>вот хороший пример, где ты не прав (про IMHO не забываем :). > >мне кажется, Linus и сотоварищи придерживаются правильного >(прагматичного)подхода. вот приходит reiserfs, и что делать? неужели >менять дизайн и переписывать linux, чтобы _попробовать_ включить эту >fs? может, лучше будет добавить нужный хак в кернел, чтобы оно >_работало_ и тестировалось? >мне кажется - да. > >конечно, есть шанс, что этот хак останется навечно, но это уже - >добро пожаловать в реальность! > >этот read_inode2 из super_operations пропал.

Дело тут не в reiserfs. Я же описал кучу ситуаций, когда понятие VFS inode не имеет разумного смысла. Просто родные линуксячьи файловые системы построены более-менее одинаково и в них не возникает проблем с номерами. Для более-менее интересных вариантов storage уже все по-другому. Кроме того, бог с тем, что просто VFS inode криво спроектирована, так ведь она и не нужна по существу самому Linux, который прекрасно использует dentry cache(корректное в отличие от inode cache понятие), при етом приходится поддерживать консистентность такого атавизма.

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

>разделение prepare_write/commit_write очень разумно, и позволяет
>факторизовать много общего кода (для простой fs реализация
>prepare_write просто вызов generic helper с нужным параметром
>(*get_block)()).то же самое про commit_write.
>что касается writepage, то не забывай, что prepare_write работает
>c _user-level_ данными (точнее, caller), а writepage - c page cache.
>я уже не говорю про partial writes.
>
>я бы рассматривал writepage как synchronization point для fdatawrite
>path.
>
>то есть, грубо говоря, я считаю, что нам нужно
>prepare_write/commit_write
>для sys_write, а writepage для (например) того, чтобы kswapd/bdflush
>мог отмыть страницу. или можно рассматривать это как вход и выход в
>page cache.

Спасибо за подробное объяснение того, чем отличаются prepare/commit от writepage. :) Теперь смотри такой вариант:
1) берем вместо prepare делаем readpage, потом writepage
2) берем вместо prepare делаем readpage, потом метим страничку грязной.

Полный путь можно сократить за счет полных writes (опускаем readpage).

>конечно плохо, что этот рудимент сохранился, но избавляются
>потихоньку, вот он уже из ioctl уходит. к дизайну это
>не имеет отношения.

Помнится (могу ошибаться) на iso9660 самые основные операции с директорией идут под lock_kernel.

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

IMHO, ядро должно быть как можно меньше и как можно проще.

Если мы немного потеряем на sparse файлах из-за меньшей гранулярности блоков или в конце файлов или иногда будет лишний ввод-вывод из-за лишнего readpage (при cache miss) и одновременно частичном write(редко).

Зато сколько сколько кода можно было бы выкинуть из ядра!

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

> Я имел в виду не ошибки внутри ядра, а интерфейс системных вызовов. То есть мы запросили памяти,
> ядро решило, что памяти нет или не стоит устраивать paging в данной ситуации и вернуло ENOMEM. :)

я что-то не понимаю... имеешь в виду, может ли mmap() вернуть ENOMEM?
конечно да. или я опять не про то?

> То есть реализация того же pager должна быть скрыта в нем, а не быть размазана как в Linux по всему
> коду ядра. И уж вдвойне абсурдно, когда по случаю часть кода pager находится в архитектурно-зависимой
> части и делает часть проверок(в случае Linux неверных - благодаря тому, что код сильно размазан по ядру
> и плохо документирован), передавая дальше управление в середину нормального pager.

о чем ты? все проверки, а не часть, делаются в do_page_fault.

> По идее page fault должен просто передавать hint в pager, который уже под своими блокировками определяет
> будет ли он выдавать страницу или нет.

да всех generic проверок кот наплакал, несколько строк. ну можно было бы
их факторизовать, толку-то. вот expand_stack() и была вынесена за скобки,
в ней-то ошибка и была.

> концепция GROW VMA довольно глупа и самый красивый вариант обработки роста стека был бы в банальном
> обработчике сигнала в runtime библиотеке(SEGFAULT->проверка->mmap->return). Правда, было бы несколько
> медленнее. IMHO, надо по максимуму разгружать ядро в RT lib.

не могу поверить, что ты это всерьез. прощай, sigaltstack, например.
как будут договариваться с libc приложения, которые напр GC через
SEGFAULT делают? да и что этот обработчик будет проверять, RLIMIT_STACK?
так ядру все равно придется делать проверку еще раз.

у меня лучше идея. предлагаю запретить запись в файл за его пределы.
разгрузим kernel, пусть libc сначала truncate сделает перед write.

> Я же описал кучу ситуаций, когда понятие VFS inode не имеет разумного смысла. Просто родные
> линуксячьи файловые системы построены более-менее одинаково и в них не возникает проблем с
> номерами.

это что, Linus придумал, что tar/find и др читают inode number для
оптимизации? претензии к отцам основателям unix, linux не при чем.
то же самое про file forks.

> Кроме того, бог с тем, что просто VFS inode криво спроектирована

я не компетентен, чтобы это комментировать

> так ведь она и не нужна по существу самому Linux, который прекрасно использует dentry cache

этого я не понимаю. c точки зрения vm, dentry существует только ради ->d_inode.

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

> Теперь смотри такой вариант:
> 1) берем вместо prepare делаем readpage, потом writepage
> 2) берем вместо prepare делаем readpage, потом метим страничку грязной.

итак, readpage вместо prepare. можно, конечно. только придется
добавить параметр prepare_mode для readpage(), чтобы:
   не делать unlock_page()
   не забыть create==1 для getblock()
   не читать лишних блоков с диска
   не забыть что читаем синхронно
   не забыть про journal_start() etc
   ... да много чего ...

хм, дизайн становится все изящнее!

writepage вместо commit. Murr, это просто _абсолютно_ разные
операции. writepage() стартует i/o этой страницы, commit не
имеет к этому никакого отношения.

> потом метим страничку грязной.

ну да, еще всякие мелочи, типа i_size_write(), mark_inode_dirty(),
ну журнал, конечно, но мы добавим параметер commit_mode в
set_page_dirty() и пусть перехватывают через aops->set_page_dirty
если кому надо.

> Помнится (могу ошибаться) на iso9660 самые основные операции с директорией идут под
> lock_kernel

ну плохо, коли так (даже смотреть не буду), но еще раз: дизайн
здесь при чем? все начинают c BKL, это прагматично.

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

> IMHO, ядро должно быть как можно меньше и как можно проще.

а вот с этим я _абсолютно_ согласен. я уже как-то писал
тебе, что я бы предпочел простое и маленькое ядро, пусть
и помедленнее. ну на хрена мне cpu hotplug, например?
ну вот ускоряют pagevec что-то на SMP на пару процентов,
но зато читать замучаешься, хоть это и просто. да я могу
бесконечно перечислять.

ну вот я сегодня увидел:

#ifdef __ARCH_IRQ_EXIT_IRQS_DISABLED
# define invoke_softirq()       __do_softirq()
#else
# define invoke_softirq()       do_softirq()
#endif

во, сэкономили local_irq_save(). наверное, есть какой-то
benchmark, который это сумеет обнаружить.

но linux хочет быть всеядным и производительным, а моего
мнения не спрашивают.

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

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

ух какое тут жаркое обсуждение! Парни в выходные что ли работаете?

Хотел бы все таки ответить на
>ох... ну вот как это по lor'овски. если вы задаете такие
>детские вопросы про vm, понятно, что у вас каша. непонятно
>почему _вы_ сразу делаете вывод, что эта каша в kernel.

каша -из за отсутствия нормальной документации
читаешь по 2.4 -а в 2.6 уже по другому, еще есть скупые комментарии кое где в коде, а также сам код -- не так просто сразу все понять.

Так что конечно огромное спасибо за ответы на "детские" вопросы но все ж не надо злорадствовать над начинающими разбираться в ядре.
..Получаются "детские" воросы на которые знают ответы единицы..

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

> но все ж не надо злорадствовать над начинающими
> разбираться в ядре.

я не злорадствовал. я прицепился к этой самой каше,
и заранее извинился. я и сам знаю не чересчур много,
и довольно в узкой области.

> каша -из за отсутствия нормальной документации читаешь по 2.4
> -а в 2.6 уже по другому, еще есть скупые комментарии кое где в коде

а вы бы хотели, чтобы сначала документацию писали,
а потом уже код?

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

в таком случае - еще раз прошу меня извинить.

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

> #ifdef __ARCH_IRQ_EXIT_IRQS_DISABLED

самое смешное, что i386 как раз имеет irqs disabled
к моменту irq_exit(). но этот define не определяет,
потому что поломается в случае CONFIG_4KSTACKS.

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

idle:

>я что-то не понимаю... имеешь в виду, может ли mmap() вернуть ENOMEM?
>конечно да. или я опять не про то?

Посмотрел do_mmap_pgoff. В 90% случаев ENOMEM возвращается в случае, не имеющим никакого отношения к нехватке памяти. Единственных два места, где речь идет о нехватке памяти - vm_enough_memory и выделение структур из slab. Во втором случае, если не ошибаюсь, 0 вернуться может в совершенно исключительных случаях, первая проверка - тоже по существу профанация, иначе бы не нужен был OOM-killer (интересно, такой зверь кроме как в Linux где-нибудь есть?).

>о чем ты? все проверки, а не часть, делаются в do_page_fault.

Вот-вот. Проверки делаются в одном месте, а оставшийся код - в другом.
IMHO, там надо было оставить только ахинеистические архитектурные проверки, а find_vma->expand_stack вынести в pager.

>не могу поверить, что ты это всерьез. прощай, sigaltstack, например.
>как будут договариваться с libc приложения, которые напр GC через
>SEGFAULT делают? да и что этот обработчик будет проверять,
>RLIMIT_STACK?так ядру все равно придется делать проверку еще раз.

Госпидя... ну зачем же так пугаться? :)
Ну обзови такой сигнал SIGSTACK, не в названии же смысл.
Если прикладуха переопределит обработчик такого сигнала - ее право и ее проблемы. Нефиг переопределять системные сигналы не понимая смысла. :)

Что до RLIMIT_STACK, то он в Linux к классическому стеку UNIX приложения не имеет никакого отношения, да и вообще считает какую-то полную байду, которая не дает никаких серьезных средств администрирования и только мешает любителям рекурсивных программ. В топку! :)

>это что, Linus придумал, что tar/find и др читают inode number для
>оптимизации? претензии к отцам основателям unix, linux не при чем.
>то же самое про file forks.

Так уже 21 век на дворе. Доколе Linux будет копией описанного в книжке Баха UNIX? :)

>этого я не понимаю. c точки зрения vm, dentry существует только ради ->d_inode.

Все, что на таком уровне имеет смысл для VM можно разделить на dentry и address space и, вероятно, несколько callbacks в файловую систему. inode - понятие сугубо внутреннее для файловой системы и оно не должно иметь incore образа в VFS.

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

>итак, readpage вместо prepare. можно, конечно. только придется
>добавить параметр prepare_mode для readpage(), чтобы:
> не делать unlock_page()

???

> не забыть create==1 для getblock()

writepage может всегда вызывать запись с alloc_conditional

> не читать лишних блоков с диска

См. выше. Нет ничего страшного, если прочитаем, т.к.
1) у нас есть page cache, в котором возможно уже лежит нужная страница
2) с большой вероятностью у нас на диске нефрагментированная страница
и мы затратим только o() при лишнем линейном чтении
3) большое количество ввода-вывода идет целыми страницами

К тому же мы получаем pre-read/заполнение кеша, что не так уж плохо.

> не забыть что читаем синхронно

См. выше. "Ничто не забыто, никто не забыт".
Кстати, в общем случае в prepare два блока тоже читаются синхронно.

> не забыть про journal_start() etc

А что, у нас данные уже в page cache журналируются?

> ... да много чего ...

Конечно, чтобы поломать голимый дизайн до нормального нужно многое изменить. :)

>writepage вместо commit. Murr, это просто _абсолютно_ разные
>операции. writepage() стартует i/o этой страницы, commit не
>имеет к этому никакого отношения.

idle, вообще-то writepage делает то, что захочет. Про commit вообще не идет речь, т.к. мы обсуждаем его отсутствие. :) Для любителей делать wait_on_page после writepage можно либо дать io-флажок, либо немного изменить семантику wait_on_page.

>ну да, еще всякие мелочи, типа i_size_write(), mark_inode_dirty(),
>ну журнал, конечно, но мы добавим параметер commit_mode в
>set_page_dirty() и пусть перехватывают через aops->set_page_dirty
>если кому надо.

mark_inode_dirty - бред. Файловая система сама в состоянии понять, когда ей нужно обновлять свои данные. Опять же VFS inode нужно выкинуть.

Про i_size_write - нет ничего плохого если filemap будет делать truncate сам.

Про журнал опять не понимаю. Метаданные обычно ФС держит во внутренних буферах или buffer cache. page cache - достаточно неудобная структура для хранения метаданных. Если говорить про данные, то пока ФС не выдает наружу интерфейс журналирования, говорить о журналируемости данных не имеет смысла. Данные не могут быть по определению журналируемы, поскольку как BLOB они всегда консистентны с точки зрения файловой системы. Можно говорить об ordered writes, как о неком механизма разумного обновления данных, но он к журналу вообще не имеет отношения.

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

>На ваш вгляд, ядро FreeBSD по сравнению с линуксовым лучше или хуже по качеству?

Там нет многих вещей, которые есть в Linux.
Но там есть то, что мне очень нравится - продуманная архитектура и последовательность в базовых вещах. Я бы даже, наверное, пересел на FreeBSD, но все же есть там определенные проблемы с поддержкой hardware и дистрибутив(RELEASE) не такой user-friendly, как FC3, а мне лениво(и не интересно) заниматься подкручиванием винтиков.

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

> Посмотрел do_mmap_pgoff. В 90% случаев ENOMEM возвращается в случае, не имеющим никакого отношения к нехватке памяти.
> Единственных два места, где речь идет о нехватке памяти - vm_enough_memory и выделение структур из slab. Во втором случае,
> если не ошибаюсь, 0 вернуться может в совершенно исключительных случаях, первая проверка - тоже по существу профанация,
> иначе бы не нужен был OOM-killer (интересно, такой зверь кроме как в Linux где-нибудь есть?).

нет, vm_enough_memory не профанация, особенно в случае OVERCOMMIT_NEVER.
там же, в mmap.c, смотри __vm_enough_memory(), если ядро свежее, иначе
ищи где-то в security/*.c.

> Ну обзови такой сигнал SIGSTACK, не в названии же смысл.

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

> Что до RLIMIT_STACK, то он в Linux к классическому стеку UNIX приложения не имеет никакого отношения, да и вообще считает
> какую-то полную байду, которая не дает никаких серьезных средств администрирования и только мешает любителям рекурсивных
> программ. В топку! :)

ну так а я о чем? что же тогда этот обработчик будет проверять? просто
вызывать mmap() безусловно? ну и зачем тогда весь этот гемор с сигналом.

> Все, что на таком уровне имеет смысл для VM можно разделить на dentry и address space и, вероятно, несколько callbacks в
> файловую систему. inode - понятие сугубо внутреннее для файловой системы и оно не должно иметь incore образа в VFS.

да не имеет dentry никакого смысла для vm. hardlinks хотя бы. ну введешь ты
d_aops_and_some_callbacks_holder, в чем выиграем, я не понимаю.

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

про writepage vs commit. я только некоторые места прокомментирую, где
могу быть кратким.

> > не забыть create==1 для getblock()
> writepage может всегда вызывать запись с alloc_conditional

либо я тебя не понял, либо это просто кошмарная идея (имхо).

> > не забыть что читаем синхронно
> См. выше. "Ничто не забыто, никто не забыт".
> Кстати, в общем случае в prepare два блока тоже читаются синхронно.

Murr, да я про другое. после readpage мы можем (и должны ждать)
PageUptodate(). после prepare и даже commit - не факт. и это
дает определенные возможности. поэтому, если readpage использовать
вместо prepare, она должна вернуть страницу PG_locked+PG_uptodate.
если нет - то имеет смысл не ждать end_io, caller, возможно, делает
readahead.

> idle, вообще-то writepage делает то, что захочет. Про commit вообще не идет речь, т.к. мы обсуждаем его отсутствие. :) Для
> любителей делать wait_on_page после writepage можно либо дать io-флажок, либо немного изменить семантику wait_on_page.

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

но writepage не делает то, что захочет, у него вполне определенная
семантика. по поводу изменения семантики wait_on_page_writeback()...
у меня есть определенные причины считать весь этот wait_bit механизм
хорошо устроенным, и менять его лучше не надо.

> mark_inode_dirty - бред. Файловая система сама в состоянии понять, когда ей нужно обновлять свои данные.

вот _именно_ по этому (в том числе) и нужен commit, чтобы fs и решила,
нужен ли ей сейчас mark_inode_dirty(), в частности.

> К тому же мы получаем pre-read/заполнение кеша, что не так уж плохо.

это как раз плохо, нам бы наоборот ahead_size сбросить, если в окно
попали. но readahead'a не будет, ни readpage, ни prepare_write этим
не занимаются и не должны.

про журнал. посмотри fs/ext3/inode.c:ext3_prepare_write().
ты можешь сказать, что ext3 также плохо спроектирована, но
разные это операции, readpage и prepare. ну имеет смысл их
разделять, потому, что семантика разная.

Murr, разумеется, все можно было сделать по другому. но
просто так выкинуть prepare/commit и оставить {read,write}page
не получится без серьезных изменений. получится ли лучше?
я не знаю. но я пока этого нового дизайна в упор не вишу,
кроме очень общих фраз.

так что я завязываю. я с интересом прочитаю все, что ты
напишешь (если захочешь), но отвечу только в случае, если
смогу аргументировать конкретно и технически, не оперируя
туманными категориями.

а вообще, было интересно :)

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

>да не в названии смысл. где будет выполняться обработчик, в каком
>стэке?sigaltstack же пропадает...

Обработчик может выполняться где угодно. Внутри анонимной или неанонимной VMA(sigaltstack). На not-committed-stack (что по определнию извращение) работать, конечно, не будет, но в том и нет большого (и малого) смысла.

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

>ну так а я о чем? что же тогда этот обработчик будет проверять? просто
>вызывать mmap() безусловно? ну и зачем тогда весь этот гемор с
>сигналом.

Как зачем? Чтобы вынести из ядра всю ахинею, связанную со stack expansion, VMA_GROW*. Благо, сие делается без проблем.

Смысл очень простой - вынести по максимуму кода из ядра.

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

>да не имеет dentry никакого смысла для vm. hardlinks хотя бы. ну
>введешь ты d_aops_and_some_callbacks_holder, в чем выиграем, я не
>понимаю.

Я, наверное, совсем не умею изъяснять свои идеи. Ведь столько уже про VFS inode писал. Ну сейчас напрягусь и попытаюсь, глядишь - может даже внятно получится.

Идея примерно такая:

Сейчас файл в ядре представлен цепочкой
VFS dentry(FS)->VFS inode(FS,MM)->address space(MM)

Предлагается сделать так:
VFS dentry(FS)+FS inode(FS,MM)->address space(MM)
т.е. инкапсулировать все, что связано с VFS inode, внутрь ФС(в первую очередь через интерфейс callbackов).

Почему плохо то, как есть:

1) VFS inode фактически является VFS кешем метаданных для файлов (например, stat кешем), причем без нормального механизма оповещения ФС, т.е. слабоуправляемым кешем - ФС может туда писать, но ФС не может отловить обращение VFS туда.
2) Концепция VFS inode очень плохо сочетается со многими файловыми системами, благодаря тому, что определяет некоторый интерфейс, который не имеет смысла для них (для таких файловых систем)
3) Крива концепция inode cache, поскольку для fake inodes VFS не может реализовать некий прозрачный кеш.

Что сейчас реально происходит (в ядрах 2.6 и то, что касается reiserfs), просто несколько примеров:
1) при том, что оставляется VFS inode происходит некая ориентация на файловую систему, например, файловая система уже может отлавливать stat (добавлен соответствующий callback в ФС)
2) кеш становится (реально, уже достаточно давно) некой аморфной структурой, в которой все реальные функции поиска осуществляет ФС (iget4/read_inode2 или iget4 с нужным параметром).

Таким образом, проблемы решаются, но полумерами, без коренного изменения дизайна, т.е. реально redesign просто растягивается на неопределенное время, несмотря на то, что назрел ряд проблем. Вероятно, из-за боязни все поломать.

Просто для примера:
1) в WinNT отсутствует то, что соответствует Linux VFS. Часть ядра под названием I/O Manager реализует минимальный интерфейс между файловой системой и системными DLL. Таким образом, файловая система наиболее свободна в внутренних представлениях и действиях
2) FreeBSD. Кроме минимальной обертки VFS между ФС и системными вызовами там реализованы что-то вроде внешних подсистем кеширования (в частности, dentry cache), которые могут в достаточно свободной формой использоваться файловой системой, а могут и не использоваться.

Второй вариант мне кажется самым симпатичным вариантом. Из
а) FreeBSD
б) Linux с его монолитным дизайном и насильно интегрированными кешами и интерфейсами
в) WinNT, где ядро вообще не реализует "лишнего"

Короче, вот такие мысли.

P.S. Блин, голова болит. Доктор говорит, что в анализе крови какой-то нереальный уровень гемоглобина... Похоже, придется что-то пить. :(

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

>Второй вариант мне кажется самым симпатичным вариантом. Из
В смысле 2)==а)

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

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

Я в таких обсуждениях преследую одну простую цель, которую можно сформулировать, как
"аппетит приходит во время еды" или "в дискуссии рождается истина".
Надеюсь, я тебя не сильно напрягаю... ;)

>либо я тебя не понял, либо это просто кошмарная идея (имхо).

Почему? :)
Ты же не забывай, что сам по себе writepage работает.
Все, что нам нужно в readpage/writepage - ввод-вывод блоков данных. 
То есть в одном случае нам нужно просто прочитать данные с диска 
(например, понулить страницу и прочитать блоки с ненулевой 
трансляцией get_block(,0)), в другом - записать (вызвать get_block
(,0), потом get_block(,1), потом записать данные туда). Т.о. 
семантика get_block(,1) не используется в "чистом виде", используется 
alloc_conditional.

Использование кеша буферов на странице, по-моему, очень коряво. От 
него можно избавиться (вместе с prepare/commit) за счет некоторого 
увеличения ввода-вывода (по моим оценкам очень небольшого за счет
1) cache hits
2) нефрагментированности данных
3) использования дополнительно прочитанных данных, как часть page cache).

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

Еще я пока гулял в поликлинику вот что надумал:

Насчет стека и его реализации в Linux.

Насколько я представляю, в Linux достаточно криво реализован стек в том смысле, что вроде как не существует механизма предотвращения перетирания стеком предыдущей VMA. На граничной странице стек расширится, а при переходе на предыдущую уже перетрет данные (в лучшем случае возникнет access violation, если предыдущая VMA спроецирована с флажками, запрещающими запись).

Насколько я помню, подобный механизм в Windows работает немного иначе (и более разумно). В Windows стеке граница помечена т.н. сторожевой страницей, которая помечена флажками "нет доступа". Соответственно, когда стек расширится на последнюю страницу, отделяющую его от VMA, подобное не случится.

Есть еще ряд нюансов со стеком и в етом смысле было бы удобно иметь механизм работы с ним в userspace.

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

Теперь по поводу ext3, его журнала, VFS и его поддержки журналируемости.

Как я понимаю, в ext3 изначально журнал проектировался для метаданных.
Потом уже добавили такие дурные режимы, как ordered и journal, просто потому что так было просто. Вообще, журнал - очень простой способ обеспечить ordered writes, но достаточно затратный (компонента записи лишних данных в журнал всегда присутствует). Идея "журналировать" данные по определению абсурдна, согласись. ;)

Теперь по поводу архитектуры VFS и журналируемости. Задача на разминку.
Представь себе ситуацию, когда на файл ссылается ровно одна ondisk dentry(nlink=1), допустим кто-то его открыл, пришел запрос на удаление dentry (unlink), как обеспечим удаление dentry и inode в одной транзакции (сам файл могут закрыть очень нескоро)?

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

Murr, ты столько написал, что нельзя не ответить :)

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

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

idle:

Ничего страшного. Я, наверное, тоже до четверга-пятницы могу не появиться. Пора уже в Москву возвращаться. Отдых-отдыхом, а труба зовет. :)

Murr ★★
()

Интересно, а зачем вообще нужны анонимные маппинги?

Неужели swap работает быстрее, чем подкачка по запросу из обычного файла?

И почему бы не сделать такой MM, который будет рассматривать только 4 типа страниц памяти:

1) Свободные страницы.

2) Страницы, которые принадлежат какому-то slab cache (например, dentry_cache), но на которых нет активных объектов. Их ВСЕГДА можно освободить.

3) Незаблокированные страницы кэшей блочных устройств. В случае нехватки памяти их ВСЕГДА можно освободить.

4) Страницы, которые освободить нельзя (занятые структурами данных ядра, заблокированные страницы кэшей блочных устройств).

При этом все функции выделения памяти должны быть написаны так, чтобы количество памяти типа1+типа2+типа3 всегда было больше определённой разумной величины.

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

продолжая флэйм ...

Murr, реализация VM_GROWXXX в user-space работать не будет.

не забывай, что fault в stack area может быть и в kernel-mode.
И что тогда делать? кто-то говорил, что любит get_user_pages()
использовать, у меня для тебя сюрприз - она перестанет работать.
а вместе с ней direct i/o, futex, например.

а что должен делать sys_read(fd, ptr_into_stack_area)? он должен
будет вернуть EFAULT. и не говори про EINTR, это сюда не прикрутишь.

и еще раз повторю, для этого механизма придется вводить специальный
sigaltstack.

>  Насколько я представляю, в Linux достаточно криво реализован стек в том смысле, что вроде как не существует механизма
>  предотвращения перетирания стеком предыдущей VMA. На граничной странице стек расширится, а при переходе на предыдущую уже
>  перетрет данные (в лучшем случае возникнет access violation, если предыдущая VMA спроецирована с флажками, запрещающими
>  запись).

ну вот, опять криво. а кто мешает приложению всунуть guard page
с помощью mmap(MAP_FIXED) ?

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