zoukankan      html  css  js  c++  java
  • 一个EMFILE问题定位:lsof、ulimit的应用,以及简单分析

    关键词:errno、EMFILE、ulimit、lsof等等。

    背景是在对程序进行压力测试,运行了一段时间之后出现一个复位操作失败。

    这个复位操作通过打开一个设备,进行读写操作,已达到控制GPIO输入输出的目的。

    1. 初步分析原因

    经过初步分析发觉fopen()返回NULL指针,说明fopen()错误了。

    但是要想知道错误原因,还需要借助errno。通过errno为24,即可知道出错的原因为EMFILE。

    由errno-base.h可知,EMFILE是打开文件过多的意思

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

    2. 找到是谁打开了哪个文件而没有释放

    首先明白系统对资源使用限制的,通过ulimit可以查看限制或者修改限制。

    关于文件打开文件数目的限制通过ulimit -n查看,或者ulimit -n <file null>修改限制。

    通过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即可查看到相关信息。

    通过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;
    }
  • 相关阅读:
    shell入门-cut命令
    shell入门-特殊符号
    shell入门-系统和用户的配置文件
    shell入门-变量
    shell入门-shell特性
    linux命令-yum工具详解
    linux命令-rpm查询包
    linux命令-rpm安装和卸载
    math 数学模块
    random 随机模块
  • 原文地址:https://www.cnblogs.com/arnoldlu/p/11681141.html
Copyright © 2011-2022 走看看