> А теперь такое же проверьте на UFS2 во FreeBSD, если не трудно. в freebsd vm такой баг не возможен в принципе, там другая архитектура LRU кэша страниц. это только в linux могли придумать игнорировать активацию страниц в сязи с тем что она слишком ранная и устраивать задержку в добавлении в LRU пока не наберется 14 страниц per CPU - что дает 14 * 4kb * 512 = несколько мегабайт памяти пролетающей мимо LRU кэша;
Это так "оптимизировали" LRU локинг. Хотя один хрен чуть что вызывают lru_add_drain для перемещения в нормальный LRU. как собственно и исправили для ext3/4.
Отдельный прикол о том что служебную иноду забыли пометить как I_NEW что флушит ее при первом же чихе.
Index: linux-stage/fs/ext4/mballoc.c
===================================================================
--- linux-stage.orig/fs/ext4/mballoc.c
+++ linux-stage/fs/ext4/mballoc.c
@@ -26,6 +26,7 @@
#include <linux/debugfs.h>
#include <linux/vmalloc.h>
#include <trace/events/ext4.h>
+#include <linux/swap.h>
/*
* MUSTDO:
@@ -943,8 +944,11 @@ static int ext4_mb_init_cache(struct pag
incore = data;
}
}
- if (likely(err == 0))
+ if (likely(err == 0)) {
SetPageUptodate(page);
+ /* make sure it's in active list */
+ mark_page_accessed(page);
+ }
out:
if (bh) {
@@ -1050,6 +1054,7 @@ int ext4_mb_init_group(struct super_bloc
}
page = e4b.bd_bitmap_page;
+ lru_add_drain();
ret = ext4_mb_init_cache(page, NULL);
if (ret)
goto err;
@@ -1070,6 +1075,7 @@ int ext4_mb_init_group(struct super_bloc
}
/* init buddy cache */
page = e4b.bd_buddy_page;
+ lru_add_drain();
ret = ext4_mb_init_cache(page, e4b.bd_bitmap);
if (ret)
goto err;
@@ -1151,6 +1157,7 @@ ext4_mb_load_buddy(struct super_block *s
if (page) {
BUG_ON(page->mapping != inode->i_mapping);
if (!PageUptodate(page)) {
+ lru_add_drain();
ret = ext4_mb_init_cache(page, NULL);
if (ret) {
unlock_page(page);
@@ -1182,6 +1189,7 @@ ext4_mb_load_buddy(struct super_block *s
if (page) {
BUG_ON(page->mapping != inode->i_mapping);
if (!PageUptodate(page)) {
+ lru_add_drain();
ret = ext4_mb_init_cache(page, e4b->bd_bitmap);
if (ret) {
unlock_page(page);
@@ -2483,6 +2491,7 @@ static int ext4_mb_init_backend(struct s
* not in the inode hash, so it should never be found by iget(), but
* this will avoid confusion if it ever shows up during debugging. */
sbi->s_buddy_cache->i_ino = EXT4_BAD_INO;
+ sbi->s_buddy_cache->i_state = I_NEW;
EXT4_I(sbi->s_buddy_cache)->i_disksize = 0;
for (i = 0; i < ngroups; i++) {
desc = ext4_get_group_desc(sb, i, NULL);
@@ -2711,6 +2720,7 @@ int ext4_mb_release(struct super_block *
}
kfree(sbi->s_mb_offsets);
kfree(sbi->s_mb_maxs);
+ sbi->s_buddy_cache->i_state = 0;
if (sbi->s_buddy_cache)
iput(sbi->s_buddy_cache);
if (sbi->s_mb_stats) {