Search code examples
linuxlinux-kernelprocfs

Append to a file in the /proc file system


I'm implementing a file in /proc which I'd like to be a little more file-like than usual. In particular, I'd like to detect that someone is appending to the file and handle that correctly -- that is, I'd like to distinguish between someone doing

echo value > /proc/my_proc_file

and

echo value >> /proc/my_proc_file

Like all write functions, mine is handed an offset as its fourth argument:

ssize_t my_proc_write(struct file *file, const char __user *buf,
                                      size_t count, loff_t *offs)

But *offs is always 0.

When I set up my proc file, I'm specifying seq_lseek as the lseek function:

struct file_operations my_proc_fops = {
    .open     = my_proc_open,
    .read     = seq_read,
    .write    = my_proc_write,
    .llseek   = seq_lseek,
};

Inspecting the source (in fs/seq_file.c), it looks like seq_lseek maintains file->f_pos appropriately, but when I look at file->f_pos in my write function, it's always 0, too. (This may not be surprising, since appending usually means opening with O_APPEND which doesn't result in any explicit calls to lseek.)

Anyway, is there a way to do this? Presumably these write functions wouldn't have been set up with offset pointer arguments if they weren't going to pass in useful, nonzero values from time to time...


Solution

  • first, from user perspective, file opened with O_APPEND will ALWAYS append data when you call write(), no matter where the f_pos is set by llseek(). but f_pos is still effective for read().

    second, kernel framework dosn't know the file length unless it calls your llseek to find out, but that's not gonna happen because it will mess up f_pos,so kernel expect your driver, which is the only one who knows where is the true "end of the file", to act accordingly when (file->f_flags & O_APPEND) is true. basically, your driver needs to check that flag when write() is called and ignore the offs param and do the append.