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...
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.