The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]

В Linux ядре исправлена ошибка связанная с потерей данных в ФС

29.12.2006 16:57

В Linux ядре исправлена трудноуловимая ошибка приводящая к потере данных в файловых системах ext2, ext3, reiserfs. Ошибка присутствует во всех ядрах начиная с 2.6.5. Патч прилагается.

----
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index b3a198c..ec01da1 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -862,17 +862,46 @@ int clear_page_dirty_for_io(struct page *page)
{
struct address_space *mapping = page_mapping(page);

- if (!mapping)
- return TestClearPageDirty(page);
-
- if (TestClearPageDirty(page)) {
- if (mapping_cap_account_dirty(mapping)) {
- page_mkclean(page);
+ if (mapping && mapping_cap_account_dirty(mapping)) {
+ /*
+ * Yes, Virginia, this is indeed insane.
+ *
+ * We use this sequence to make sure that
+ * (a) we account for dirty stats properly
+ * (b) we tell the low-level filesystem to
+ * mark the whole page dirty if it was
+ * dirty in a pagetable. Only to then
+ * (c) clean the page again and return 1 to
+ * cause the writeback.
+ *
+ * This way we avoid all nasty races with the
+ * dirty bit in multiple places and clearing
+ * them concurrently from different threads.
+ *
+ * Note! Normally the "set_page_dirty(page)"
+ * has no effect on the actual dirty bit - since
+ * that will already usually be set. But we
+ * need the side effects, and it can help us
+ * avoid races.
+ *
+ * We basically use the page "master dirty bit"
+ * as a serialization point for all the different
+ * threds doing their things.
+ *
+ * FIXME! We still have a race here: if somebody
+ * adds the page back to the page tables in
+ * between the "page_mkclean()" and the "TestClearPageDirty()",
+ * we might have it mapped without the dirty bit set.
+ */
+ if (page_mkclean(page))
+ set_page_dirty(page);
+ if (TestClearPageDirty(page)) {
dec_zone_page_state(page, NR_FILE_DIRTY);
+ return 1;
}
- return 1;
+ return 0;
}
- return 0;
+ return TestClearPageDirty(page);
}
EXPORT_SYMBOL(clear_page_dirty_for_io);


  1. Главная ссылка к новости (http://kerneltrap.org/node/751...)
  2. Linux: Chasing Down Data Corruption
  3. Linux: Data Corruption Bug Fixed
Лицензия: CC BY 3.0
Короткая ссылка: https://opennet.ru/9388-linux
Ключевые слова: linux, kernel, ext3, ext2, patch
При перепечатке указание ссылки на opennet.ru обязательно


Обсуждение (12) Ajax | 1 уровень | Линейный | +/- | Раскрыть всё | RSS
  • 1.1, anonymous (??), 19:05, 29/12/2006 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Шило на мыло...
     
     
  • 2.10, Dvorkin (??), 08:45, 30/12/2006 [^] [^^] [^^^] [ответить]  
  • +/
    Как выразился Линус, теперь этот race стал tiny tiny... у вас есть идеи?
     

  • 1.5, fi (?), 21:18, 29/12/2006 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Можно поздравить Линуса с находкой такой редкой, но тем ни менее зловредной, ошибкой. Отдельное спасибо сетям p2p - они сумели поймать баг :)  Если бы NTFS так же тщательно тестировали, а затем исправляли :).
     
  • 1.6, avatar (ok), 21:59, 29/12/2006 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Согласен с тем,что лучше найденая ошибка чем ненайденая.
     
  • 1.7, Дмитрий Ю. Карпов (?), 22:37, 29/12/2006 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Что-то я при первом "наезде" не смог понять, в чём была ошибка. Похоже, речь идёт об отложенной записи страниц на диск, но дальше я увяз.
     
     
  • 2.11, hvv (?), 11:41, 30/12/2006 [^] [^^] [^^^] [ответить]  
  • +/
    'The VM layer asked the filesystem to do the write, but the filesystem just didn't do it. I personally think it's because some buffer-head BH_dirty bit got scrogged, but it could be some event that makes the filesystem simply not do the IO because it thinks the "disk queues are too full", so it just says "IO completed", without actually doing anything at all.' (c) Linus. Я так понял, пачтик именно фиксит возможность легко протерять dirty бит из-за race condition, а от этого бита зависит, будет ли страница записана на диск.
     

  • 1.12, Аноним (-), 12:18, 30/12/2006 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Как понял из треда на LORе, баг касается только ext3, смонтированной по дефолту с data=ordered. Хотелось бы уточнить, читать тред на lkml влом :)
     
  • 1.13, pavlinux (??), 13:38, 30/12/2006 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Ну незнаю как на ext3, а вот если корневая стоит xfs, то при загрузке она отказывается проверятся, орёт мол unable to run fsck: cannot load shared object  libsepol.so все либы от SELinux: на месте. Да и вообще, до этого патча работало же.!!!
     
  • 1.14, G0D (?), 15:34, 30/12/2006 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Народ, как его применять?Я что то не въехал.
     
     
  • 2.15, pavlinux (??), 21:20, 30/12/2006 [^] [^^] [^^^] [ответить]  
  • +/
    Копируешь этот исходный код в пустой файл, скажем race_fix.diff, сохраняешь.
    Копируешь в директорию с исходниками ядра, например /usr/src/linux

    # cp race_fix.diff /usr/src/linux
    # cd /usr/src/linux
    # patch -p1 < race_fix.txt
    # make V=1

    Всё!

     
  • 2.17, D3V1L (?), 20:11, 31/12/2006 [^] [^^] [^^^] [ответить]  
  • +/
    Сохраняешь код патча в race_fix.diff, копируешь в директорию с исходниками, на всякий случай  очищаешь директорию сборки от предыдущих билдов, патчишь, и запускаешь сборку:

    # cp race_fix.diff /usr/src/linux
    # cd /usr/src/linux
    # patch -p1 < race_fix.txt
    # make V=1

     

  • 1.16, pavlinux (??), 00:21, 31/12/2006 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Короче, этот патч для старых ядер... вот переделал под 2.6.19.х

    === кусь ===

    --- b/mm/page-writeback.c 1970-01-01 00:00:00.000000000 +0300
    +++ a/mm/page-writeback.c 2006-12-30 23:53:04.124975836 +0300
    @@ -893,16 +893,16 @@
    {
    struct address_space *mapping = page_mapping(page);

    - if (mapping) {
    - if (TestClearPageDirty(page)) {
    - if (mapping_cap_account_dirty(mapping)) {
    - page_mkclean(page);
    - dec_zone_page_state(page, NR_FILE_DIRTY);
    - }
    - return 1;
    - }
    - return 0;
    - }
    +        if (mapping && mapping_cap_account_dirty(mapping)) {
    +             if (page_mkclean(page))
    +             set_page_dirty(page);
    +                if (TestClearPageDirty(page))
    +        {
    +                      dec_zone_page_state(page, NR_FILE_DIRTY);
    +                   return 1;
    +         }
    +                return 0;
    +        }
    return TestClearPageDirty(page);
    }
    EXPORT_SYMBOL(clear_page_dirty_for_io);

    === кусь ===

     

     Добавить комментарий
    Имя:
    E-Mail:
    Текст:



    Партнёры:
    PostgresPro
    Inferno Solutions
    Hosting by Hoster.ru
    Хостинг:

    Закладки на сайте
    Проследить за страницей
    Created 1996-2024 by Maxim Chirkov
    Добавить, Поддержать, Вебмастеру