如何替换返回 EOF 和读取字节数的 procfs 条目的读取函数?

How to replace read function for procfs entry that returned EOF and byte count read both?

我正在努力更新我们的内核驱动程序,以便在 Ubuntu 16.0.4 上使用 linux 内核 4.4.0。驱动程序最后使用 linux 内核 3.9.2。 在其中一个模块中,我们创建了一个 procfs 条目,用于 read/write 板载风扇监控值。风扇监控用于 read/write CPU 或 GPU temperature/modulation 等。值。

该模块正在使用以下 api 创建 procfs 条目:

struct proc_dir_entry *create_proc_entry(const char *name, umode_t
mode,struct proc_dir_entry *parent);

类似于:

struct proc_dir_entry * proc_entry = 
create_proc_entry("fmon_gpu_temp",0644,proc_dir);
proc_entry->read_proc = read_proc;
proc_entry->write_proc = write_proc;

现在,read_proc 是这样实现的:

static int read_value(char *buf, char **start, off_t offset, int count, int *eof, void *data) {
    int len = 0;
    int idx = (int)data;

    if(idx == TEMP_FANCTL)
        len = sprintf (buf, "%d.%02d\n", fmon_readings[idx] / TEMP_SAMPLES, 
              fmon_readings[idx] % TEMP_SAMPLES * 100 / TEMP_SAMPLES);
    else if(idx == TEMP_CPU) {
        int i;
        len = sprintf (buf, "%d", fmon_readings[idx]);
        for( i=0; i < FCTL_MAX_CPUS && fmon_cpu_temps[i]; i++ ) {
            len += sprintf (buf+len, " CPU%d=%d",i,fmon_cpu_temps[i]);
        }
        len += sprintf (buf+len, "\n");
    }
    else if(idx >= 0 && idx < READINGS_MAX)
        len = sprintf (buf, "%d\n", fmon_readings[idx]);
    *eof = 1;
    return len;
}

此读取函数绝对假定用户已提供足够的缓冲区space 来存储温度值。这在 userspace 程序中得到了正确处理。此外,对于此函数的每次调用,读取值都是完整的,因此对于相同温度值的后续读取没有 support/need。 另外,如果我在来自 shell 的这个 procfs 条目上使用 "cat" 程序,'cat' 程序会正确显示该值。我认为,这是通过将 EOF 设置为 true 和 returning 读取字节数来支持的。

新 linux 内核不再支持这个 API。

我的问题是:

如何将此 API 更改为新的 procfs API 结构,保持功能相同:每次读取都应该 return 值,程序 'cat' 也应该工作很好,不会进入无限循环?

在 Linux 上读取文件的 主用户界面read(2)。它在内核 space 中的对是 结构中的 .read 函数 file_operations.

内核中读取文件的所有其他机制 space (read_proc, seq_file, 等)实际上是 .read 函数的(参数化)实现。

The only way for kernel to return EOF indicator to user space is returning 0 as number of bytes read.

即使是 3.9 内核的 read_proc 实现实际上也将 eof 标志实现为在下次调用时返回 0。并且 cat 实际上执行 second 调用 read 以发现文件已结束。

(此外,cat 执行 超过 2 次 read 调用:第一次使用 1 作为 count,第二次使用 count 等于页面大小减 1,最后还有剩余 count.)

"one-shot" 读取实现的最简单方法是在 single_open() 模式下使用 seq_file