1. 程式人生 > >linux mce的一些相關內容和使用者態監控的設計方法

linux mce的一些相關內容和使用者態監控的設計方法

之所以想起寫一點關於mce的東西,倒不是因為遇到mce的異常了,之前遇到過很多mce的異常,記憶體居多,但沒有好好記錄下來,寫這個是因為參加2018 clk南京會議的一點想法。

void __init trap_init(void)
{
。。。
#ifdef CONFIG_X86_MCE
    set_intr_gate_ist(X86_TRAP_MC, &machine_check, MCE_STACK);
#endif
。。。
}

其中mce的初始化流程為:

Start_kernel-->check_bugs-->identify_boot_cpu-->identify_cpu-->mcheck_cpu_init  
/*
 * Called for each booted CPU to set up machine checks.
 * Must be called with preempt off:
 */
void mcheck_cpu_init(struct cpuinfo_x86 *c)
{
...
    machine_check_vector = do_machine_check;----------這個函式,主要工作函式

    __mcheck_cpu_init_generic();
    __mcheck_cpu_init_vendor(c);
    __mcheck_cpu_init_clear_banks();
    __mcheck_cpu_init_timer();
....
}

 

 

如果為了除錯mce功能,模擬硬體真的出問題,那麼可以使用 mce-inject 使用者態工具來實現,對應核心的函式為:

void mce_inject_log(struct mce *m)
{
    mutex_lock(&mce_chrdev_read_mutex);
    mce_log(m);
    mutex_unlock(&mce_chrdev_read_mutex);
}

當然除錯的時候,一般需要修改tolerant 值,不然有可能引起復位:

cat /sys/devices/system/machinecheck/machinecheck15/tolerant
1 [[email protected] ~]# [[email protected] ~]# ls -alrt /sys/devices/system/machinecheck/machinecheck15/tolerant -rw-r--r--. 1 root root 4096 10月 15 10:05 /sys/devices/system/machinecheck/machinecheck15/tolerant [[email protected] ~]# echo 2 > /sys/devices/system/machinecheck/machinecheck15/tolerant [[email protected]
~]# cat /sys/devices/system/machinecheck/machinecheck15/tolerant 2 /* * Tolerant levels: * 0: always panic on uncorrected errors, log corrected errors * 1: panic or SIGBUS on uncorrected errors, log corrected errors * 2: SIGBUS or log uncorrected errors (if possible), log corr. errors * 3: never panic or SIGBUS, log all errors (for testing only) */

下面描述的是引發思考的過程,即mce的通知機制,為什麼突然想寫mce的機制,是因為其實它應用的模式可以解籤,

我們把核心維護mce資料的方式視為mce資料的生產者,而使用者態取該資料視為消費者的話,生產消費模型非常明顯,針對這種模型,一般由兩種方式來處理:

1.輪詢,

2.中斷通知

其中中斷通知又可以細分為有守護程序,即daemon 方式,還有一種是無守護程序,直接回調一個trigger的方式。

[[email protected] ~]# ps -ef |grep -i mce
root       920     1  0 10月13 ?      00:00:00 /usr/sbin/mcelog --ignorenodev --daemon --syslog
root     22125  7650  0 10:18 pts/0    00:00:00 grep --color=auto -i mce
[[email protected] ~]# cat /proc/920/stack
[<ffffffff81212b95>] poll_schedule_timeout+0x55/0xb0
[<ffffffff8121411d>] do_sys_poll+0x4cd/0x580
[<ffffffff8121443e>] SyS_ppoll+0xce/0x1d0
[<ffffffff816965c9>] system_call_fastpath+0x16/0x1b
[<ffffffffffffffff>] 0xffffffffffffffff

上面這個例子就是daemon方式,等待在poll中,等核心事件通知。

等待的檔名是/dev/mcelog:

[[email protected] ~]# lsof -p 920
COMMAND PID USER   FD   TYPE             DEVICE SIZE/OFF     NODE NAME
mcelog  920 root  cwd    DIR                8,2     4096        2 /
mcelog  920 root  rtd    DIR                8,2     4096        2 /
mcelog  920 root  txt    REG                8,2   155952 11550884 /usr/sbin/mcelog
mcelog  920 root  mem    REG                8,2    61752 11535695 /usr/lib64/libnss_files-2.17.so
mcelog  920 root  mem    REG                8,2  2116736 11535677 /usr/lib64/libc-2.17.so
mcelog  920 root  mem    REG                8,2   155064 11535670 /usr/lib64/ld-2.17.so
mcelog  920 root    0u   CHR                1,3      0t0     2052 /dev/null
mcelog  920 root    1u   CHR                1,3      0t0     2052 /dev/null
mcelog  920 root    2u   CHR                1,3      0t0     2052 /dev/null
mcelog  920 root    3r   CHR             10,227      0t0     2205 /dev/mcelog------------------這個裝置
mcelog  920 root    4u  unix 0xffff880035de8000      0t0    25331 /var/run/mcelog-client

那麼,既然是sys檔案系統,肯定有對應的read和write來提供給使用者使用,read顯而易見,是讀取mce日誌,write是幹啥的?其實這裡的write主要就是為了給別人註冊用的,mce本身不是

呼叫write來寫資料,它直接維護一個數據區,等別人來讀,另外daemon是使用poll方法來等待的,所以自然還得實現poll方法:

static const struct file_operations mce_chrdev_ops = {
    .open            = mce_chrdev_open,
    .release        = mce_chrdev_release,
    .read            = mce_chrdev_read,
    .write            = mce_chrdev_write,
    .poll            = mce_chrdev_poll,
    .unlocked_ioctl        = mce_chrdev_ioctl,
    .llseek            = no_llseek,
};

poll方法的最終實現:

static unsigned int mce_chrdev_poll(struct file *file, poll_table *wait)
{
    poll_wait(file, &mce_chrdev_wait, wait);----------一般阻塞在這,mce_chrdev_wait是一個等待佇列
    if (READ_ONCE(mcelog.next))
        return POLLIN | POLLRDNORM;
    if (!mce_apei_read_done && apei_check_mce())
        return POLLIN | POLLRDNORM;
    return 0;
}

既然有等待佇列,自然而然就會想,我什麼時候喚醒:

int mce_notify_irq(void)
{
    /* Not more than two messages every minute */
    static DEFINE_RATELIMIT_STATE(ratelimit, 60*HZ, 2);

    if (test_and_clear_bit(0, &mce_need_notify)) {
        /* wake processes polling /dev/mcelog */
        wake_up_interruptible(&mce_chrdev_wait);

        if (mce_helper[0])
            schedule_work(&mce_trigger_work);

        if (__ratelimit(&ratelimit))
            pr_info(HW_ERR "Machine check events logged\n");

        return 1;
    }
    return 0;
}

既然mce的來源有使用者除錯,以及真實檢測,所以很自然喚醒也有多個來源。比如inject來喚醒和mce真實中斷喚醒。

使用者程序被poll喚醒之後,一般是poll_in,自然需要去讀取資料,直接呼叫read方法就行。也就是一個簡單的read和poll,就解決了監控使用者態側的大部分功能。

其他資訊就不一一列了,昨天參加clk南京的會議,其中富士通一個兄弟說他們實現了NVDIMM 的一個監控,原因在於他們認為NVDIMM 是很難replace,所有有必要監控它。

它列出了一個模型,就是使用者態daemon,然後設定filter到核心,核心將其監控到的event發給等待的使用者程序,使用的方法正是triggers a poll event ,和目前的mce有異曲同工之妙。

假設讓你設計這種監控類的東西,你會怎麼設計呢?