Monku
Monku

Reputation: 2650

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

I am working on updating our kernel drivers to work with linux kernel 4.4.0 on Ubuntu 16.0.4. The drivers last worked with linux kernel 3.9.2. In one of the modules, we have a procfs entries created to read/write the on-board fan monitoring values. Fan monitoring is used to read/write the CPU or GPU temperature/modulation,etc. values.

The module is using the following api to create procfs entries:

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

Something like:

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;

Now, the read_proc is implemented something in this way:

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;
}

This read function definitely assumes that the user has provided enough buffer space to store the temperature value. This is correctly handled in userspace program. Also, for every call to this function the read value is in totality and therefore there is no support/need for subsequent reads for same temperature value. Plus, if I use "cat" program on this procfs entry from shell, the 'cat' program correctly displays the value. This is supported, I think, by the setting of EOF to true and returning read bytes count.

New linux kernels do not support this API anymore.

My question is:

How can I change this API to new procfs API structure keeping the functionality same as: every read should return the value, program 'cat' should also work fine and not go into infinite loop ?

Upvotes: 0

Views: 1373

Answers (1)

Tsyvarev
Tsyvarev

Reputation: 65870

The primary user interface for read files on Linux is read(2). Its pair in kernel space is .read function in struct file_operations.

Every other mechanism for read file in kernel space (read_proc, seq_file, etc.) is actually an (parametrized) implementation of .read function.

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

Even read_proc implementation you have for 3.9 kernel actually implements eof flag as returning 0 on next invocation. And cat actually perfoms the second invocation of read for find that file is end.

(Moreover, cat performs more than 2 invocations of read: first with 1 as count, second with count equal to page size minus 1, and the last with remaining count.)

The simplest way for "one-shot" read implementation is using seq_file in single_open() mode.

Upvotes: 1

Related Questions