URL: https://www.opennet.me/cgi-bin/openforum/vsluhboard.cgi
Форум: vsluhforumID3
Нить номер: 36346
[ Назад ]

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

Отправлено opennews , 29-Дек-06 19:05 
В Linux ядре исправлена (http://kerneltrap.org/node/7518) трудноуловимая ошибка приводящая к потере данных  в файловых системах 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);

URL: http://kerneltrap.org/node/7518
Новость: http://www.opennet.me/opennews/art.shtml?num=9388


Содержание

Сообщения в этом обсуждении
"В Linux ядре исправлена ошибка связанная с потерей данных в ФС"
Отправлено anonymous , 29-Дек-06 19:05 
Шило на мыло...

"В Linux ядре исправлена ошибка связанная с потерей данных в ..."
Отправлено Dvorkin , 30-Дек-06 08:45 
Как выразился Линус, теперь этот race стал tiny tiny... у вас есть идеи?

"В Linux ядре исправлена ошибка связанная с потерей данных в ФС"
Отправлено fi , 29-Дек-06 21:18 
Можно поздравить Линуса с находкой такой редкой, но тем ни менее зловредной, ошибкой. Отдельное спасибо сетям p2p - они сумели поймать баг :)  Если бы NTFS так же тщательно тестировали, а затем исправляли :).

"В Linux ядре исправлена ошибка связанная с потерей данных в ФС"
Отправлено avatar , 29-Дек-06 21:59 
Согласен с тем,что лучше найденая ошибка чем ненайденая.

"А в чём суть ошибки?"
Отправлено Дмитрий Ю. Карпов , 29-Дек-06 22:37 
Что-то я при первом "наезде" не смог понять, в чём была ошибка. Похоже, речь идёт об отложенной записи страниц на диск, но дальше я увяз.

"А в чём суть ошибки?"
Отправлено hvv , 30-Дек-06 11:41 
'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, а от этого бита зависит, будет ли страница записана на диск.

"В Linux ядре исправлена ошибка связанная с потерей данных в ФС"
Отправлено Аноним , 30-Дек-06 12:18 
Как понял из треда на LORе, баг касается только ext3, смонтированной по дефолту с data=ordered. Хотелось бы уточнить, читать тред на lkml влом :)

"В Linux ядре исправлена ошибка связанная с потерей данных в ФС"
Отправлено pavlinux , 30-Дек-06 13:38 
Ну незнаю как на ext3, а вот если корневая стоит xfs, то при загрузке она отказывается проверятся, орёт мол unable to run fsck: cannot load shared object  libsepol.so все либы от SELinux: на месте. Да и вообще, до этого патча работало же.!!!

"В Linux ядре исправлена ошибка связанная с потерей данных в ФС"
Отправлено G0D , 30-Дек-06 15:34 
Народ, как его применять?Я что то не въехал.

"В Linux ядре исправлена ошибка связанная с потерей данных в ..."
Отправлено pavlinux , 30-Дек-06 21:20 
Копируешь этот исходный код в пустой файл, скажем 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

Всё!


"В Linux ядре исправлена ошибка связанная с потерей данных в ..."
Отправлено D3V1L , 31-Дек-06 20:11 
Сохраняешь код патча в race_fix.diff, копируешь в директорию с исходниками, на всякий случай  очищаешь директорию сборки от предыдущих билдов, патчишь, и запускаешь сборку:

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


"В Linux ядре исправлена ошибка связанная с потерей данных в ФС"
Отправлено pavlinux , 31-Дек-06 00:21 
Короче, этот патч для старых ядер... вот переделал под 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);

=== кусь ===