一個EMFILE問題定位:lsof、ulimit的應用,以及簡單分析

關鍵詞:errno、EMFILE、ulimit、lsof等等。linux

 

背景是在對程序進行壓力測試,運行了一段時間以後出現一個復位操做失敗。ide

這個復位操做經過打開一個設備,進行讀寫操做,已達到控制GPIO輸入輸出的目的。測試

1. 初步分析緣由

通過初步分析發覺fopen()返回NULL指針,說明fopen()錯誤了。spa

可是要想知道錯誤緣由,還須要藉助errno。經過errno爲24,便可知道出錯的緣由爲EMFILE。指針

由errno-base.h可知,EMFILE是打開文件過多的意思code

#define    EMFILE        24    /* Too many open files */

2. 找到是誰打開了哪一個文件而沒有釋放

首先明白系統對資源使用限制的,經過ulimit能夠查看限制或者修改限制。blog

關於文件打開文件數目的限制經過ulimit -n查看,或者ulimit -n <file null>修改限制。ip

經過ulimit -n命令能夠查看linux系統裏打開文件描述符的最大值,通常缺省值是1024資源

ulimit -a
-f: file size (blocks)             unlimited
-t: cpu time (seconds)             unlimited
-d: data seg size (kb)             unlimited
-s: stack size (kb)                8192
-c: core file size (blocks)        0
-m: resident set size (kb)         unlimited
-l: locked memory (kb)             64
-p: processes                      3274
-n: file descriptors               1024
-v: address space (kb)             unlimited
-w: locks                          unlimited
-e: scheduling priority            0
-r: real-time priority             0

lsof顯示系統全部打開文件,那麼很簡單經過lsof便可查看到相關信息。get

經過lsof能夠看到打開的文件很是多,並且主要集中在uImage這個文件。

...
14232    /heop/package/AiApp/AiApp    /heop/package/AiApp/uImage
14232    /heop/package/AiApp/AiApp    /heop/package/AiApp/uImage
14232    /heop/package/AiApp/AiApp    /heop/package/AiApp/uImage
...

而後看到uImage這個文件被打開了1000屢次,問題就很明瞭了。

經過走查代碼,發現uImage文件在被打開後因爲某些條件未fclose()。解決也比較簡單。

3. EMFILE出現代碼走查

open系統調用入口是do_sys_open(),經過get_unused_fd_flags()來得到可用的句柄號。

long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
{
...
    fd = get_unused_fd_flags(flags);
    if (fd >= 0) {
...
    }
    putname(tmp);
    return fd;
}

SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
{
    if (force_o_largefile())
        flags |= O_LARGEFILE;

    return do_sys_open(AT_FDCWD, filename, flags, mode);
}

而後就看看句柄是如何分配的,以及有什麼限制。

經過rlimit(RLIMIT_NOFILE)能夠得到系統對打開文件數目的限制,等同於ulimit -n。

而後__alloc_fd()應該着這個範圍以內。當判斷fd>=end的時候,返回-EMFILE

int get_unused_fd_flags(unsigned flags)
{
    return __alloc_fd(current->files, 0, rlimit(RLIMIT_NOFILE), flags);
}

int __alloc_fd(struct files_struct *files,
           unsigned start, unsigned end, unsigned flags)
{
...
    error = -EMFILE;
    if (fd >= end)
        goto out;
...

out:
    spin_unlock(&files->file_lock);
    return error;
}
相關文章
相關標籤/搜索