文档章节

一个seq_file的小问题

o
 osc_1ee7cxmx
发布于 2018/08/06 17:32
字数 1086
阅读 0
收藏 0

精选30+云产品,助力企业轻松上云!>>>

在修改一个内核模块的时候,我们使用seq_file来打印我们的数据,结果非常出人意料。

static void flowinfo_seq_printf_stats(struct seq_file *seq, struct xxx *pxxx)
{
    seq_printf(seq, "\nflow alloc info in cpuindex %d:\n", cpuindex);
    if ( dump_flow >= 0) 
    {
          dump_flow =-1;
          其他的很多seq_printf
.......
}
还有很多seq_printf
}
dump_flow 是一个全局变量,初始化为-1.

使用echo方式修改 dump_flow 。

但是当我使用echo 赋值 dump_flow =1之后,我使用cat还能查看到 dump_flow 的值修改为1了,也就是确认了这个值已经按要求修改为了预期的值。

接下来,我执行 cat 动作来触发 flowinfo_seq_show 函数的调用
static const struct seq_operations flowinfo_seq_ops = {
    .start = flowinfo_seq_start,
    .next  = flowinfo_seq_next,
    .stop  = flowinfo_seq_stop,
    .show  = flowinfo_seq_show,


static int flowinfo_seq_show(struct seq_file *seq, void *v)
{
    if (v == SEQ_START_TOKEN)
        flowinfo_seq_printf_stats(seq, v);
    else {}
    return 0;
}

  static int flowinfo_seq_open(struct inode *inode, struct file *file)
  {
        return seq_open(file, &flowinfo_seq_ops);;
  }

  static const struct file_operations flowinfo_seq_fops = {
    .owner = THIS_MODULE,
    .open = flowinfo_seq_open,
    .read = seq_read,
    .llseek = seq_lseek,
    .release = flowinfo_seq_release,

  

很悲剧的是,我并没有看到我原本在if条件里面应该输出的 seq里面的内容。

很确定的是,flowinfo_seq_show  肯定是调用了,为啥没看到内容呢?

我修改一下我的show函数:

static void flowinfo_seq_printf_stats(struct seq_file *seq, struct witdriver *witdriver)
{
   printk("dump_flow =%d\n",dump_flow);
    seq_printf(seq, "\nflow alloc info in cpuindex %d:\n", cpuindex);
    if ( dump_flow >= 0) 
    {
          dump_flow =-1;
          其他的很多seq_printf
....... }
更多的seq_printf 调用。。。。。。。。
}  

 

结果看到,dmesg中的内容如下:

dump_flow=1
dump_flow=-1
dump_flow=-1
dump_flow=-1

 dump_flow被打印了四次,我只执行了一次cat,为啥show函数会执行四次呢?

最终通过走查代码,发现密码是存在于:seq_read 函数中。

ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
	struct seq_file *m = file->private_data;
	size_t copied = 0;
	loff_t pos;
	size_t n;
	void *p;
	int err = 0;

	mutex_lock(&m->lock);

	/*
	 * seq_file->op->..m_start/m_stop/m_next may do special actions
	 * or optimisations based on the file->f_version, so we want to
	 * pass the file->f_version to those methods.
	 *
	 * seq_file->version is just copy of f_version, and seq_file
	 * methods can treat it simply as file version.
	 * It is copied in first and copied out after all operations.
	 * It is convenient to have it as  part of structure to avoid the
	 * need of passing another argument to all the seq_file methods.
	 */
	m->version = file->f_version;

	/*
	 * if request is to read from zero offset, reset iterator to first
	 * record as it might have been already advanced by previous requests
	 */
	if (*ppos == 0)
		m->index = 0;

	/* Don't assume *ppos is where we left it */
	if (unlikely(*ppos != m->read_pos)) {
		while ((err = traverse(m, *ppos)) == -EAGAIN)
			;
		if (err) {
			/* With prejudice... */
			m->read_pos = 0;
			m->version = 0;
			m->index = 0;
			m->count = 0;
			goto Done;
		} else {
			m->read_pos = *ppos;
		}
	}

	/* grab buffer if we didn't have one */
	if (!m->buf) {
		m->buf = seq_buf_alloc(m->size = PAGE_SIZE);
		if (!m->buf)
			goto Enomem;
	}
	/* if not empty - flush it first */
	if (m->count) {
		n = min(m->count, size);
		err = copy_to_user(buf, m->buf + m->from, n);
		if (err)
			goto Efault;
		m->count -= n;
		m->from += n;
		size -= n;
		buf += n;
		copied += n;
		if (!m->count)
			m->index++;
		if (!size)
			goto Done;
	}
	/* we need at least one record in buffer */
	pos = m->index;
	p = m->op->start(m, &pos);-------------这里开始
	while (1) {
		err = PTR_ERR(p);
		if (!p || IS_ERR(p))
			break;
		err = m->op->show(m, p);------------show函数调用,但是此时没有fill到用户态
		if (err < 0)
			break;
		if (unlikely(err))
			m->count = 0;
		if (unlikely(!m->count)) {
			p = m->op->next(m, p, &pos);
			m->index = pos;
			continue;
		}
		if (m->count < m->size)------------由于这个条件不满足,所以依然不会fill
			goto Fill;
		m->op->stop(m, p);-----------------m->count >=m->size,将执行stop,
		seq_buf_free(m->buf);--------------释放原本的buf
		m->count = 0;
		m->buf = seq_buf_alloc(m->size <<= 1);----再次申请m->size ,size扩大一倍
		if (!m->buf)
			goto Enomem;
		m->version = 0;
		pos = m->index;
		p = m->op->start(m, &pos);---------重新来过,再次循环
	}
	m->op->stop(m, p);
	m->count = 0;
	goto Done;
Fill:
	/* they want more? let's try to get some more */
	while (m->count < size) {
		size_t offs = m->count;
		loff_t next = pos;
		p = m->op->next(m, p, &next);
		if (!p || IS_ERR(p)) {
			err = PTR_ERR(p);
			break;
		}
		err = m->op->show(m, p);
		if (seq_has_overflowed(m) || err) {
			m->count = offs;
			if (likely(err <= 0))
				break;
		}
		pos = next;
	}
	m->op->stop(m, p);
	n = min(m->count, size);
	err = copy_to_user(buf, m->buf, n);
	if (err)
		goto Efault;
	copied += n;
	m->count -= n;
	if (m->count)
		m->from = n;
	else
		pos++;
	m->index = pos;
Done:
	if (!copied)
		copied = err;
	else {
		*ppos += copied;
		m->read_pos += copied;
	}
	file->f_version = m->version;
	mutex_unlock(&m->lock);
	return copied;
Enomem:
	err = -ENOMEM;
	goto Done;
Efault:
	err = -EFAULT;
	goto Done;
}

 由于seq要打印内容过多,所以会导致我们填充到m->buf的数据并没有fill到用户态,而是释放掉buf,然后扩大buf到原来的两倍,直到能够满足我们seq要输出的内容为止。

所以,我的show函数调用了好几遍,当第二遍之后,我的 dump_flow  已经被改成了-1,由于buf还是不够,又来了第三遍,第四遍,不过后面的几遍中,if条件之内的内容不会打印了。因为条件已经不满足了。

 

 
o
粉丝 0
博文 500
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。

暂无文章

如何将div放置在其容器的底部? - How can I position my div at the bottom of its container?

问题: Given the following HTML: 鉴于以下HTML: <div id="container"> <!-- Other elements here --> <div id="copyright"> Copyright Foo web designs </div> </div> I would like #cop......

富含淀粉
31分钟前
10
0
unity列表控件Horizontal/Vertical/Grid Layout Group用法介绍

1. Grid Layout Group 为Panel控件添加Grid Layout Group,子控件为四个按钮,分别为Grid,Calendar,Gear,User: 默认属性为 为方便演示,按钮的底色为控件自带image,按钮上面的图标为其子...

路过暴风
56分钟前
19
0
Distinct()与lambda? - Distinct() with lambda?

问题: Right, so I have an enumerable and wish to get distinct values from it. 是的,所以我有一个可枚举的,并希望从中获得不同的值。 Using System.Linq , there's of course an ext......

法国红酒甜
今天
8
0
学习编写编译器[关闭] - Learning to write a compiler [closed]

问题: Preferred languages : C/C++, Java, and Ruby. 首选语言 :C / C ++,Java和Ruby。 I am looking for some helpful books/tutorials on how to write your own compiler simply for......

技术盛宴
今天
17
0
OSChina 周一乱弹 —— 毛巾又怎么样?!我在乎的是大姐姐温柔的怀抱!

Osc乱弹歌单(2020)请戳(这里) 【今日歌曲】 @薛定谔的兄弟 :分享洛神有语创建的歌单「我喜欢的音乐」: 《雨 因你而下,于你而止》- Seto 手机党少年们想听歌,请使劲儿戳(这里) @Dan...

小小编辑
今天
43
1

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部