Gain greater depth of understanding of file descriptors by seeing how read uses them
read(2)
entry
Advanced reference count optimization
Reading through the virtual filesystem
SYSCALL_DEFINE3(read, ...)
Just calls ksys_read()
Only one other caller in s390 compat code
Originally there were more callers
ksys_read()
Obtain a reference to the file position or bail
Create a local copy of the file position
Perform virtual filesystem (vfs) read
If needed, update the file position
Drop any held references
fdget_pos()
CLASS(...
referencing DEFINE_CLASS(fd_pos,...)
fdget_pos()
What is this struct fd
and why might we want something more than just the struct file
?
We don't always need to have our own reference to the struct file
We need to keep track of which references need to be dropped
fd_file()
Get an unsigned long
Split it into a struct fd
#define fd_file(f) ((struct file *)((f).word & ~(FDPUT_FPUT|FDPUT_POS_UNLOCK)))
fdget_pos()
First, do we need the file lock?
Then, do we need the file position lock?
fdget()
Get a reference to a file descriptor unless it's opened in path mode
__fget_light()
If the refcount is 1, we can borrow it
Otherwise, we need our own reference
__fget_light()
Use atomic_read_acquire()
to get the current reference count
Call files_lookup_fd_raw()
directly
The unsigned long
return value will be cast
__fget_light()
In the case we cannot borrow, mark the lower bits of the pointer
fdget_pos()
Question: what is fd_file()
doing?
file_needs_f_pos_lock()
When do we need the file position lock?
Any regular file or directory has FMODE_POS_ATOMIC
set
In addition, we check the file_count and for a shared iterator
fdget_pos()
To finish up, lock and set another bit if needed
ksys_read()
First check whether the file is open with fd_empty()
Recent patchset by maintainer
Introduced fd_empty()
and fd_file()
Used to check f.file
file_ppos()
Otherwise, this just gets the address of the file position
vfs_read()
Overview:
Validate the operation and its inputs
Execute the specific read handler
Notify of completion
vfs_read()
First three checks
Make sure the file is open for reading
Make sure that the file can be read
Make sure the output buffer is a sane address
rw_verify_area()
Sanity check the file position
Verify read access
vfs_read()
Check that count isn't too big
count >= MAX_RW_COUNT
Ensures maximum value is rounded down to page boundary
vfs_read()
Call the actual read!
Call the read()
member of file operations
Otherwise, call read_iter()
vfs_read()
If we are successful:
Tell fsnotify to let others know of this access
Account for task's bytes written
Unconditionally:
ksys_read()
Last steps to wrap up
Update the file position if relevant
Drop any references we may have
Return the number of bytes read or an error
fdput_pos()
Question: When does control flow call this function?
CLASS(...
was usedfdput_pos()
If we locked the file position: __f_unlock_pos()
If we locked the file: fdput()
calls fput()
read()
doesn't need to do as much as open()
or write()
Small optimizations on file descriptor operations add up to significant performance improvements
Watch out for data storage in unexpected places like the lower bits of a pointer!
msg = (silence)
whoami = None
singularity v0.6-56-g8e52bc8 https://github.com/underground-software/singularity