最近和同事一起處理了乙個 fuse 的大bug;
首先看堆疊:
core was generated by `/sf/cluster/bin/pmxcfs'.
program terminated with signal sigabrt, aborted.
#0 0x00007f2debdcc475 in raise () from /lib/x86_64-linux-gnu/libc.so.6
(gdb) bt
#0 0x00007f2debdcc475 in raise () from /lib/x86_64-linux-gnu/libc.so.6
#1 0x00007f2debdcf6f0 in abort () from /lib/x86_64-linux-gnu/libc.so.6
#2 0x00007f2debdc5621 in __assert_fail () from /lib/x86_64-linux-gnu/libc.so.6
#3 0x00007f2ded4035d2 in fuse_do_release (f=f@entry=0x16148b0, ino=ino@entry=330, path=0x7f2ddc00e040 "/acl.cfg", fi=fi@entry=0x7f2dd73f4b50) at fuse.c:3092
#4 0x00007f2ded403656 in fuse_lib_release (req=0x7f2ddc00c230, ino=330, fi=0x7f2dd73f4b50) at fuse.c:3876
#5 0x00007f2ded4094eb in do_release (req=, nodeid=, inarg=) at fuse_lowlevel.c:1345
#6 0x00007f2ded409f16 in fuse_ll_process_buf (data=0x1614ba0, buf=0x7f2dd73f4d00, ch=) at fuse_lowlevel.c:2441
#7 0x00007f2ded406c5b in fuse_do_work (data=0x7f2dcc0009e0) at fuse_loop_mt.c:117
#8 0x00007f2deca6eb50 in start_thread () from /lib/x86_64-linux-gnu/libpthread.so.0
#9 0x00007f2debe74a7d in clone () from /lib/x86_64-linux-gnu/libc.so.6
#10 0x0000000000000000 in ?? ()
(gdb)
分析:1、這個是libfuse庫源生的bug,在網上檢視了下沒有發現有這個bug的相關資訊;
2、core分析:
(gdb) p *(f->id_table.array[3626])
$15 = , mtime = , size = 0, locks = 0x0, is_hidden = 0, cache_valid = 0,
treelock = 1, inline_name = "acl.cfg", '\000' }
對應**:
pthread_mutex_lock(&f->lock);
node = get_node(f, ino);
assert(node->open_count > 0);// node->open_count = 0
--node->open_count;
if (node->is_hidden && !node->open_count)
pthread_mutex_unlock(&f->lock);
====
本來想好好寫排查過程的,還有一些有效的排查方法的,但發現 csdn 好爛,都找不到預覽功能在**了;
重現方法:
1. 修改**,多個執行緒內增加呼叫system;
2. 修改**,在fuse_kern_chan_receive裡加強assert,如果read正常返回但是緩衝區沒改過,即斷言
這樣可以加大重現概率,基本一天至少可以出4、5個
問題原因:
多執行緒內fork,父子程序先是共用記憶體頁 準備copy-on-write, a執行緒等在read /dev/fuse上,a執行緒的read陷入系統呼叫 fuse.ko準備將資料寫入記憶體,此時b執行緒寫同乙個記憶體頁的記憶體觸發cow,父程序最終使用新頁表新記憶體,但read系統呼叫將資料寫入了舊記憶體
對應用層的表現是,read返回值正確,但是緩衝區資料沒有填充,應用層把緩衝區上舊命令當作新命令執行了兩次
原始不改**的情況下通常表現為兩種core,乙個是fuse_do_release裡open計數斷言,另乙個是fuse_lib_releasedir裡釋放記憶體,其他情況雖然可能命令執行錯了,但通常不會表現出core,而是上層訪問可能異常;
修改辦法:
1、命令結構體申請記憶體時,用4k對齊函式來申請(偏移量4k對齊,申請記憶體大小也要4k對齊);
2、把可能的在多執行緒中呼叫fork()的系統呼叫去掉;
多執行緒服務內應避免使用fork,如system、popen
多執行緒與fork
多執行緒程式裡盡量不使用fork 在多執行緒程式裡,在 自身以外的執行緒存在的狀態 下一使用fork的話,就可能引起各種各樣的問題.比較典型的例子就是,fork出來的子程序可能會死鎖.請不要,在不能把握問題的原委的情況下就在多執行緒程式裡fork子程序,能引起什麼問題呢?那看看例項吧.一執行下面的 ...
c 中使用多執行緒
using system using system.drawing using system.collections using system.componentmodel using system.windows.forms using system.data using system.threa...
c 中使用多執行緒
using system using system.drawing using system.collections using system.componentmodel using system.windows.forms using system.data using system.threa...