go `fmt: Fscan`可能无法在tracefs "id"文件上工作,

piv4azn7  于 6个月前  发布在  Go
关注(0)|答案(5)|浏览(52)

你正在使用哪个版本的Go( go version )?

$ go version
go version go1.11 linux/amd64

这个问题在最新版本中是否会重现?

使用 fmt.Fscan 在 tracefs 文件上。例如
/sys/kernel/debug/tracing/events/tcp/tcp_set_state/id

你正在使用什么操作系统和处理器架构( go env )?

go env 输出

$ go env
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/elazar/.cache/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/elazar/go"
GOPROXY=""
GORACE=""
GOROOT="/usr/local/go"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build929178475=/tmp/go-build -gno-record-gcc-switches"

你做了什么?

https://play.golang.org/p/sKRnsBHZ6Gc

你期望看到什么?

当我 cat 该文件时看到的相同的事件ID。

你看到了什么?

只有第一个数字, 1
记录一下,tracefs中的"id"并不是由 seq_file 实现的:

static ssize_t
event_id_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
{
	int id = (long)event_file_data(filp);
	char buf[32];
	int len;

	// Elazar: This is probably the culprit. Can be removed, simple_read_from_buf handles it.
	if (*ppos)
		return 0;

	if (unlikely(!id))
		return -ENODEV;

	len = sprintf(buf, "%d\n", id);

	return simple_read_from_buffer(ubuf, cnt, ppos, buf, len);
}

master 分支中仍然相关
似乎 simple_read_from_buffer 在某种程度上无法跟踪 ppos ,尽管它应该可以。
例如

#include <stdio.h>
#include <stdint.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc, char **argv) {
  if (argc < 2)
    return 1;
  int fd = open(argv[1], O_RDONLY);
  char c;
  read(fd, &c, 1);
  printf("Got %c\n", c);
  read(fd, &c, 1);
  printf("Got %c\n", c);
}
// output:
// Got 1
// Got 1

虽然这可能是一个内核bug,但有人可能会考虑一个解决方法,因为它非常普遍。

pkbketx9

pkbketx91#

这不是一个内核bug,请参考我类似的关注here
您希望用缓冲区 Package fp,所以:

n, err := fmt.Fscan(bufio.NewReaderSize(fp, 16), &num)

将起作用。

oipij1gg

oipij1gg2#

这是个不错的解决方法,但我不想使用未知大小的缓冲区。(在我看来,这确实是个内核bug,但这不是主要问题。不跟踪seek位置有什么好处?)

dgiusagp

dgiusagp3#

你可以使用合理的缓冲区来处理数字。我认为这是优化的,因为结果不应该是文本。

cyej8jka

cyej8jka5#

我并不认为我们能在Go工具链中解决这个问题。如果Linux内核不支持在文件上连续调用read,那么你需要一次性读取整个文件。如果你想让fmt.Fscan像C语言的fscanf那样工作,那么你需要像@Gnouc建议的那样使用bufio.NewReader
我们当然不会修改Go库,专门检查跟踪文件并以不同方式处理它们。

相关问题