Ext2 directory operations use the page cache
[akaros.git] / Documentation / vfs.txt
index d56db1e..18eb986 100644 (file)
@@ -206,6 +206,26 @@ This also applies to trying to write to a block beyond the EOF.  If the request
 hits the page cache and readpage(), it's because it was already checked and
 cleared in another part of the VFS, such as in generic_file_write().
 
+Files That End Before a Page Boundary
+--------------------------
+So what if we have a file that is only 1024 bytes.  When we read it in, we'll
+have a whole page added to the page cache, with the extra 3K 0'd.  When we go to
+write it back, it will write back the 1K, and ignore the rest.  But what if we
+extend the file later?  That page is already in the page cache, but the buffer
+heads aren't tracking the new 3K.  When that page gets evicted, only the 1K will
+write back.
+
+There are two ways to deal with this: 1) When we extend the file, check and see
+if it is in the middle of a page, and if so, alloc the blocks (all FS
+specific!), and adjust the BHs to map the new data.  2) Preallocate the
+remaining blocks and stitch up the BH mapping at readpage (which is in the
+specific FS).  This way, we reserve the blocks (but don't have to actually read
+them in - we just mark the buffer as dirty).  When we grow a file, we don't need
+to worry about any of these details.  We just make sure the page map has the
+page, and not whether or not it's a half-page that needs a FS-specific solution.
+I'm going with #2 for now.  Note that while the blocks are allocated, the file's
+size is still 1024B.
+
 Kref, Dentries, Inodes, and Files (or "I don't see why it's like X, but..."
 --------------------------
 There are multiple dentries pointing to an inode.  The dentries are (or will be)
@@ -434,9 +454,9 @@ There are a couple ways we could handle this.  We adopt the Linux approach of
 using something called a buffer head (BH), which describes the mapping from
 in-memory buffer to block device / block number.  These are slab-allocated,
 and exist for each buffer of a page.  The page itself points to the first of
-its BHs, all of which exist in a circular LL.  The maximum number of them is
-determined by PGSIZE / blocksize.  Whenever there is a page in the page cache
-(meaning, in a page_mapping), that is up to date, it will have a BH.
+its BHs, all of which exist in a LL.  The maximum number of them is determined
+by PGSIZE / blocksize.  Whenever there is a page in the page cache (meaning, in
+a page_mapping), that is up to date, it will have a BH.
 
 Another way would be to not have BHs at all, and just figure out (at
 operation-time) what the n blocks on disk are for any given page, and submit
@@ -460,15 +480,14 @@ up into separate buffers for no reason.  At the other extreme, we could get by
 without having a BH at all, though this gets back to the other issue of
 caching.  What we do (or will do) is have one BH for the entire page of
 contiguous blocks.  If the page is a "buffer page," in Linux terms (meaning it
-has separate buffers), it will have n BHs in a circular LL.  Either way, we'll
-always have the mapping handy.  We wouldn't need to re-verify the contiguous
-nature of the blocks anyways, since the fact that the page was up to date and
-didn't need a BH would mean it was contiguous.  Further benefits to using the
-one BH include: 1) we are likely to make BHs be the unit of IO *submission*,
-and having one handy will simplify that code. 2) some code paths within the
-VFS may get BHs as a return value, which they can then dirty.  Always having a
-BH makes this easier (no need to find out if it's a buffer page, then decide
-how to dirty it).
+has separate buffers), it will have n BHs in a LL.  Either way, we'll always
+have the mapping handy.  We wouldn't need to re-verify the contiguous nature of
+the blocks anyways, since the fact that the page was up to date and didn't need
+a BH would mean it was contiguous.  Further benefits to using the one BH
+include: 1) we are likely to make BHs be the unit of IO *submission*, and having
+one handy will simplify that code. 2) some code paths within the VFS may get BHs
+as a return value, which they can then dirty.  Always having a BH makes this
+easier (no need to find out if it's a buffer page, then decide how to dirty it).
 
 Another compliation with this is certain code will want a block in the middle
 of a page (very common for metadata).  That code will get the BH for the
@@ -592,3 +611,25 @@ RAM, but have the BH keep track of who is holding its reference.  Then we
 could unmap the page, which would need to get read back in on its next access.
 We'd need (or ought to have) some sort of callbacks.  This will get solved
 later when we deal with unmapping mmap'd files.
+
+x.6: What about Directories?  Inodes or metadata?
+--------------------
+Directories have inodes that have blocks scattered around the disk.  The blocks
+making up the body of a directory are not sequential, like when you read blocks
+from a bdev.  If you wanted a "page" of a directory, then you'd need to use the
+i_mapping (page cache of a file) to access it, like any other file.
+
+However, we don't want a page of a directory - at least not yet.  The main
+reason we can get away with this is due to the lack of a mmap() or a desire to
+page-remap for directory-contents IO.  It's all for the kernel's internal use.
+At no point does anyone call generic_file_read() or _write() on it.
+
+That being said, we treat the blocks of a directory as metadata blocks.  We do
+figure out which blocks they are by walking the inode (also made of metadata
+blocks), but don't bother to set up a page map for the directory itself.  We
+just use the inode to figure out which metadata blocks we want, then read them
+in (out of the blockdev's page cache).
+
+Note that userspace issues reads on the directory.  This is mostly a convenience
+thing (or an inconvenience thing), which just ends up being a wrapper around
+readdir() (via generic_dir_read()).