前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >systemtap实现查找unused dentry对应文件小工具

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

原创
作者头像
cdh
修改2020-05-31 22:51:20
1.7K1
修改2020-05-31 22:51:20
举报
文章被收录于专栏:笔记+笔记+

工具代码中在遍历访问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=%s\r\n",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.txt\r\n");

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("\r\n");

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, "%s\r\n", temp);

}

}

if(strlen(buf))

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

printk("total unused dentry(%s)=%lld\r\n",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:%d\r\n",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中。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档