zoukankan      html  css  js  c++  java
  • df空间满,du找不到文件的问题

    最近看了一下问题:

     df -h
    Filesystem      Size  Used Avail Use% Mounted on
    rootfs          271G  267G  2.2G 100% /

    根分区满了,du 找不到占用这么大的文件。lsof查看delete文件,发现了罪魁祸首,

    lsof |grep -i delete |grep -i zxagent
    sleep      4500       root    2w      REG                8,2         1459    7399418 /tmp/.zxagent.command.output.-218666128 (deleted)
    sleep      6081       root    2w      REG                8,2 202907880341    7399434 /tmp/.zxagent.command.output.-218666128 (deleted)
    chk_usr_m 23846       root    2w      REG                8,2 202907880341    7399434 /tmp/.zxagent.command.output.-218666128 (deleted)
    netif_inf 23871       root    2w      REG                8,2 202907880341    7399434 /tmp/.zxagent.command.output.-218666128 (deleted)
    sleep     25497       root    2w      REG                8,2 202907880341    7399434 /tmp/.zxagent.command.output.-218666128 (deleted)----200G
    sh        30440       root    2w      REG                8,2         1459    7399418 /tmp/.zxagent.command.output.-218666128 (deleted)
    uss_jbodm 31946       root    2w      REG                8,2         1459    7399418 /tmp/.zxagent.command.output.-218666128 (deleted)

    这个200G,不一定多落盘了,但根据周期性落盘来推算,这个占空间大肯定是没跑了,查看对应的fd,

    ls -alrt /proc/23846/fd/*
    lrwx------ 1 root root 64 Apr 30 19:20 /proc/23846/fd/4 -> socket:[451533622]
    lr-x------ 1 root root 64 Apr 30 19:20 /proc/23846/fd/255 -> /home/zxcdn/ottcache/bin/chk_usr_mem.sh
    l-wx------ 1 root root 64 Apr 30 19:20 /proc/23846/fd/2 -> /tmp/.zxagent.command.output.-218666128 (deleted)
    l-wx------ 1 root root 64 Apr 30 19:20 /proc/23846/fd/1 -> /dev/null
    lr-x------ 1 root root 64 Apr 30 19:20 /proc/23846/fd/0 -> /dev/null

    对应的fd是2,查看一下里面什么内容:

    more /proc/23846/fd/2
    chmod 777 start.sh
    ./start.sh
    dos2unix: converting file /home/iTool/UPDATE_20190415164111/2/update/start_ott.sh to UNIX format ...
    dos2unix: converting file /home/iTool/UPDATE_20190415164111/2/update/start.sh to UNIX format ...
    dos2unix: converting file /home/iTool/UPDATE_20190415164111/2/update/start_zmss.sh to UNIX format ...
    ###start /home/zxcdn/ottcache/superinit.sh &#################
    Add execute right to script...

    看起来是一些错误日志。

    tail -f /proc/23846/fd/2
    2019-05-05 18:06:54 Watching proccess[/ZMSS/ZMSSComAgent]<3622> was abnormal exited, restart it.
    2019-05-05 18:06:54 Proccess [/ZMSS/ZMSSComAgent]<3623> normal exiting, exit code[1]
    2019-05-05 18:06:54 Watching proccess[/ZMSS/ZMSSComAgent]<3623> was abnormal exited, restart it.
    2019-05-05 18Could not read configuration file [/ZMSS/etc/ZMSSComAgent/etc_memlog/log4cxx.conf].
    Ignoring configuration file [/ZMSS/etc/ZMSSComAgent/etc_memlog/log4cxx.conf].
    Use uss_badchunkget.
    Use uss_tiermode_query.
    Use DFS File System Interface.
    log4cxx_SetThreshold <3><ERROR>
    Cannot change owner of /var/ZMSS to root:root, err<-1>!

    从时间点看,案发当时还在打印错误日志。

    如果只是这么看,那么就不记录这个问题了。问题是,我脑抽地想通过内核模块查看这个文件,会报错。

     如果使用vmtouch去查看这个文件占用内存的大小,会发现报错,报文件不存在,所以写了一个内核模块去查看它的缓存页数:

    21081455    /tmp/.zxagent.command.output.-218666128

    结果显示,这个文件有21081455 个页缓存在内存中,这个大概是84个G,文件本身大小为200G,所以是部分缓存了,

    那如果不通过fd查看,怎么查看这个文件的内容呢,要查看这个内容,内核中通过如下方式来读取和写文件:

    打开文件
    
    struct file *filp_open(const char *filename, int flags, int mode)
    
    读文件
    
    ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
    
    写文件
    
    ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
    
    关闭文件
    
    int filp_close(struct file *filp, fl_owner_t id)

    但要注意的是,需要

    file_caq = filp_open("/tmp/.zxagent.command.output.1246", O_RDWR | O_CREAT | O_TRUNC, 0644);
            if ( !file )
            {
                    printk("file open(%s) failed!
    ", "/tmp/.zxagent.command.output.1246");
                    filp_close(file, NULL);
                    return -1;
            }
            else
            {
                printk("open /tmp/.zxagent.command.output.1246 success
    ");
            }
    
            ret = file_caq->f_op->read(file, (char *)buf, 512, &pos);
                 printk("read /tmp/.zxagent.command.output.1246 ret=%d,read=%p
    ",ret,file_caq->f_op->aio_read);

    打印如下:

    [12833325.784972] pages_total = 21081455(82349M),HZ=250
    [12833325.785019] open /tmp/.zxagent.command.output.1246 success
    [12833325.785022] read /tmp/.zxagent.command.output.1246 ret=-14,read=ffffffff810fd420

    看来是read失败了,这个主要是因为权限检查,然后修改为如下:

            old_fs = get_fs();
            set_fs(KERNEL_DS);
            ret = vfs_read(file_caq, (char *)buf_caq, 511, &pos);
            set_fs(old_fs);

    发现不再报错,但是读取的数据为空,也就是read返回0。

    然后再手工ls一下这个文件,发现确实创建了一个新的文件,为空,文件名是 /tmp/.zxagent.command.output.1246,当然inode号和之前delete 的文件名不一样。

    那就把 对应文件的打开的时候的O_CREAT给去掉,干脆全部改成O_READONLY

    file_caq = filp_open("/tmp/.zxagent.command.output.1246", O_RDWR | O_CREAT | O_TRUNC, 0644);
    
    这行修改为
    file_caq = filp_open("/tmp/.zxagent.command.output.1246", O_RDONLY, 0644);

    结果crash了,打印的crash提示为:

    BUG: unable to handle kernel NULL pointer dereference at 0000000000000026

    经过反汇编查看,发现因为file_caq虽然不为NULL,但是返回的是-2,所以导致 :

     if ( !file )这个判断失效了,导致打印了open success。
    ret = file_caq->f_op->read(file, (char *)buf, 512, &pos);

    这行出现crash了,因为 file_caq的值为-2,加上f_op是偏移,一开始为了这个26的偏移还看了一会,后来才想通是因为-2 + 0x28 才等于0x26。

    所以把NULL的判断改为 if (IS_ERR(file_caq)),再进行测试,发现文件打开失败,返回的错误是-2.

    那么返回-2就是说,文件不存在,因为我去掉了create标志,自然报错了。所以标记为delete的文件,如果使用file_open去打开也是不行的,会报文件不存在的。

    那么要获取这个文件,只能在内核态从inode入手,找到对应的address_space,然后再把radix_tree中的page 拷贝出来了,此为后话。

     绕了半圈,费了劲,没什么收获。不过顺便确定了下lsof看到的deleted,并不是lsof实现的,而是内核在打印 

    path_with_deleted 的时候,append进去的,判断标准就是对应path的dentry是否被hashed。
      2 ffff882b9020ad00 ffff882cd153f680 ffff882f79b0f5f0 CHR  /dev/pts/26
      3 ffff8859f47ac700 ffff885f79a69380 ffff882dee933d48 REG  /home/caq/caq.txt-----------这个是测试用的deleted的文件
    crash> dentry.d_hash ffff885f79a69380
      d_hash = {
        next = 0x0,
        pprev = 0x0
      }
    crash> dentry.d_hash ffff882cd153f680
      d_hash = {
        next = 0x0,
        pprev = 0xffffc9000ff81f60
      }

    判断方式:

    static inline int hlist_bl_unhashed(const struct hlist_bl_node *h)
    {
        return !h->pprev;
    }
    
    static inline int d_unhashed(struct dentry *dentry)
    {
        return hlist_bl_unhashed(&dentry->d_hash);
    }
    
    
    static int path_with_deleted(const struct path *path,
                     const struct path *root,
                     char **buf, int *buflen)
    {
        prepend(buf, buflen, "", 1);
        if (d_unlinked(path->dentry)) {------判断是否增加deleted
            int error = prepend(buf, buflen, " (deleted)", 10);
            if (error)
                return error;
        }
  • 相关阅读:
    ImageView的属性android:scaleType作用
    android程序内存泄漏的原因和解决办法
    如何在Android使用Rest服务从客户端调用webservice
    android系统如何自适应屏幕大小
    使用GitHub进行版本管理
    Android中dp、sp、px的转换和区别。
    软件开发:手机应用程序开发注意事项
    学用MVC4做网站二:2.2添加用户组
    学用MVC4做网站二:2.1浏览用户组
    学用MVC4做网站二:2.4删除用户组
  • 原文地址:https://www.cnblogs.com/10087622blog/p/10818350.html
Copyright © 2011-2022 走看看