systemtap实现查找unused dentry对应文件小工具

2020-05-31 22:51:20 浏览数 (1)

工具代码中在遍历访问d_lru链表时安全起见本来应该是要加内核dcache_lru_lock锁保护的,但是由于内核未将该锁导出给模块使用,所以代码实现的时候无法加上dcache_lru_lock锁保护,因此存在因刚好访问了被删除的dentry而引起系统panic重启的风险,线上机器跑这个工具还是需要视情况谨慎评估。

# stap -L 'kernel.function("dput")'

kernel.function("dput@fs/dcache.c:641") $dentry:struct dentry*

SystemTap工具guru模式代码实现如下:

#cat dump_dentry_path.stp

#!/usr/bin/stap

%{

#include <linux/string.h>

#include <linux/mm.h>

#include <linux/fs.h>

#include <linux/file.h>

#include <linux/fs.h>

#include <asm/segment.h>

#include <asm/uaccess.h>

#include <linux/buffer_head.h>

%}

global n_limit=0

%{

static char buf[PAGE_SIZE];

static char path[PATH_MAX];

%}

function get_devname:string(dev:string)

%{

char *devname = (char *)STAP_ARG_dev;

//snprintf(STAP_RETVALUE, MAXSTRINGLEN, ""%s"",devname);

snprintf(STAP_RETVALUE, MAXSTRINGLEN, ""%s"",kread(&devname));

%}

//function get_dentry_path:long(dentry:long,path:string)

function get_dentry_path:long(dentry:long)

%{

struct file *filp = NULL;

mm_segment_t oldfs;

int ret=-1;

unsigned int offset=0,len=0;

struct super_block *sb=NULL;

char *temp=NULL;

unsigned long long dcache_referenced_nr=0;

//char *path = NULL;

struct dentry *dentry = NULL;

dentry = (struct dentry *)STAP_ARG_dentry;

// path = (char *)STAP_ARG_path;

if(!dentry /*|| !path*/)

{

goto EXIT;

}

sb=dentry->d_sb;

//printk("d_sb->s_id=%srn",sb->s_id);

oldfs = get_fs();

set_fs(get_ds());

// filp = filp_open(path, O_WRONLY|O_CREAT, 0644);

filp = filp_open("/run/dump_dentry.txt", O_WRONLY|O_CREAT, 0644);

ret=PTR_ERR(filp);

if (!IS_ERR(filp)) {

// printk("sucess to create file /run/log.txtrn");

if(!list_empty(&sb->s_dentry_lru)) {

list_for_each_entry(dentry, &sb->s_dentry_lru, d_lru) {

if(dentry->d_sb != sb)

continue;

dcache_referenced_nr ;

memset(path, 0, PATH_MAX);

temp = dentry_path_raw(dentry, path,PATH_MAX);

if (!IS_ERR(temp)) {

len = strlen(temp) sizeof("rn");

if((offset len) >= PAGE_SIZE)

{

ret=filp->f_op->write(filp, buf, offset, &filp->f_pos);

offset = 0;

memset(buf,0,PAGE_SIZE);

}

offset = snprintf(buf offset, PAGE_SIZE-offset, "%srn", temp);

}

}

if(strlen(buf))

ret=filp->f_op->write(filp, buf, offset, &filp->f_pos);

printk("total unused dentry(%s)=%lldrn",sb->s_id,dcache_referenced_nr);

}

filp_close(filp,NULL);

}

set_fs(oldfs);

EXIT:

STAP_RETVALUE=ret;

%}

probe kernel.function("dput") {

DevName=get_devname(@1) //@1为stap命令行传递的参数1

if(DevName==$dentry->d_sb->s_id$ && !n_limit && $dentry)

{

n_limit = 1

//retval=get_dentry_path($dentry,@2)

retval=get_dentry_path($dentry)

printf("retval:%drn",retval)

exit()

}

}

测试步骤:

1. mount /dev/vdb1 /mnt/

2. for(( i=0; i <5000; i ));do echo "hello" >/mnt/file$i.txt;done

3. rm /mnt/file*.txt -rf

4.stap -g -v dump_dentry_path.stp vdb1

5. systemtap代码将unused dentry对应的文件路径保存到 /run/dump_dentry.txt:

cat /run/dump_dentry.txt

因为SystemTap运行时会关闭中断,而当调用file_open打开ext3/ext4文件系统的文件时内核接口函数

__find_get_block会检查是否关闭中断,如果关闭中断就BUG_ON函数触发panic,所以这里将生成的文件保存到tmpfs文件系统文件/run/dump_dentry.txt中。

0 人点赞