1

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

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Steve Summit
  • 45,437
  • 7
  • 70
  • 103
  • Traditionally seq files are used for read only purposes and are quite lazy about the size of files, for examples look at `ls -l /proc/sys/kernel` to see all the zero length files. Is your file reporting a non-zero size? –  Nov 28 '16 at 02:35
  • @icarus Mine's zero, like all the rest. But giving it a size is a good suggestion. Thanks. – Steve Summit Nov 29 '16 at 03:08
  • Yes, the point is that if a file is opened in append mode then it sets the offset to the current size. The size being zero would explain why you see the offset as being zero. –  Nov 29 '16 at 04:37
  • @icarus are you sure? Two writers with O_APPEND will get interleaved writes rather than overlapping writes; data is always written to the current end of file, not to the current file seek position. – roaima Nov 29 '16 at 23:41
  • Right. (An explicit seek to the end on append was what happened long, long ago, before O_APPEND was invented, like in V7 days.) I'm currently investigating `file->f_flags` and `file->f_mode` to see if I can find any trace of the O_APPEND flag. – Steve Summit Nov 30 '16 at 01:38
  • duplicate https://stackoverflow.com/questions/20268627/why-the-operator-doesnt-work-with-my-char-device – TingQian LI May 10 '19 at 07:13

1 Answers1

1

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.

TingQian LI
  • 660
  • 8
  • 13
  • Thanks for the belated answer! I had figured out (a couple days after posting the question) that I needed to check `O_APPEND`, but I guess I never updated the post. Thanks again! – Steve Summit May 10 '19 at 17:11