this is just useful to know about how the fs layer works in general

A seq_file implementation that is formatting firewall rules from a
table, for example, could provide a simple iterator that interprets
position N as the Nth rule in the chain. A seq_file implementation
that presents the content of a, potentially volatile, linked list
might record a pointer into that list, providing that can be done
without risk of the current location being removed.

Positioning can thus be done in whatever way makes the most sense for
the generator of the data, which need not be aware of how a position
translates to an offset in the virtual file. The one obvious exception
is that a position of zero should indicate the beginning of the file.

this documentation is so good lol. being honest about historical issues is so refreshing

The next() function should set *pos to a value that start() can use
to find the new location in the sequence. When the iterator is being
stored in the private data area, rather than being reinitialized on each
start(), it might seem sufficient to simply set *pos to any non-zero
value (zero always tells start() to restart the sequence). This is not
sufficient due to historical problems.

Historically, many next() functions have not updated *pos at
end-of-file. If the value is then used by start() to initialise the
iterator, this can result in corner cases where the last entry in the
sequence is reported twice in the file. In order to discourage this bug
from being resurrected, the core seq_file code now produces a warning if
a next() function does not change the value of *pos. Consequently a
next() function must change the value of *pos, and of course must
set it to a non-zero value.

literally it's good

It's worth noting that the iterator value returned by start() and
manipulated by the other functions is considered to be completely opaque by
the seq_file code. It can thus be anything that is useful in stepping
through the data to be output. Counters can be useful, but it could also be
a direct pointer into an array or linked list. Anything goes, as long as
the programmer is aware that things can happen between calls to the
iterator function. However, the seq_file code (by design) will not sleep
between the calls to start() and stop(), so holding a lock during that time
is a reasonable thing to do. The seq_file code will also avoid taking any
other locks while the iterator is active.

~65 more replies (not shown)
Documentation/filesystems/locking.rst has some fantastic description of when a lock is held

->llseek() locking has moved from llseek to the individual llseek
implementations. If your fs is not using generic_file_llseek, you
need to acquire and release the appropriate locks in your ->llseek().
For many filesystems, it is probably safe to acquire the inode
mutex or just to use i_size_read() instead.
Note: this does not protect the file->f_pos against concurrent modifications
since this is something the userspace has to take care about.

always wondered how copy_file_range() handled concurrent modifications

->copy_file_range and ->remap_file_range implementations need to serialize
against modifications of file data while the operation is running. For
blocking changes through write(2) and similar operations inode->i_rwsem can be
used. To block changes to file contents via a memory mapping during the
operation, the filesystem must take mapping->invalidate_lock to coordinate
with ->page_mkwrite.

one interesting thing about not having non-local returns like exceptions mean you have all control flow explicit. i think RAII is the right way to answer this and is strictly more powerful than what C gives you with neither non-local returns or RAII but it's kind of nice to read code that won't return early unless you tell it to with a highlighted return statement

would be a ridiculously overengineered sort of thing to do in general compared to what the rust ignore crate does which is use an efficient regex engine in userspace but the idea here would be to establish a general RPC-like interface for directory traversal none of this module is gonna be shipped anywhere i think it's just fun

honestly it might be better implementing this as a set of syscalls........the procfs abstraction is getting way too strained. stuff like user_path_at() expects a const char __user *name i.e. it needs to have the whole pointer in a single go and writes may be arbitrarily split. this also makes locking much easier. now i'll have to learn how to make a syscall but i think that's supposed to be not too hard

ooooh this is actually pretty cool. when defining a hash table you always define the number of bits as well


/**
* hash_init - initialize a hash table
* @hashtable: hashtable to be initialized
*
* Calculates the size of the hashtable from the given parameter, otherwise
* same as hash_init_size.
*
* This has to be a macro since HASH_BITS() will not work on pointers since
* it calculates the size during preprocessing.
*/
#define hash_init(hashtable) __hash_init(hashtable, HASH_SIZE(hashtable))