====== Some basic VM call documentation ======
===== Secondary cache =====
The secondary block cache is a mechanism to utilize all available system memory as a disk cache. This functionality has to be in VM because it must be able to free the cache blocks if memory is needed for anything else, without blocking on it. I.e. it cannot rely on any other process to first free memory.
It is intended to be used by filesystem processes to store blocks it evicts from its own cache, hence the name 'secondary cache' and the use of the word 'block' and most of the time.
==== Logical Interface ====
Blocks are identified by a ''(dev, dev_off)'' pair. This pair uniquely
identifies a cache block in VM. These numbers have meaning to VM too:
dev is the full device number (i.e. major together with minor) of the
device it resides on, and dev_off is the offset from the minor device.
Furthermore each block has an inode and an inode offset associated
with it. If the block is a file data block, this inode number must be a
number uniquely identifying this file. Otherwise the inode number must
be VMC_NO_INODE and the inode offset is irrelevant. The inode metadata
is informational, they needn't be unique in the VM cache.
Logically there are four operations:
- Set a block. The caller passes the virtual address of the block, its length, and its identification to VM. VM will keep that block and the metadata in its cache. This is the way to indicate a new cache block to VM, for possible later retrieval. The ''(dev, dev_off)'' pair is required and is unique; a possible existing block with that ID will be removed from the cache.
- Map a block. The caller passes the ''(dev, dev_off)'' pair to VM, together with further metadata. If the block exists, VM maps the cache block in and returns the address to the caller. VM updates its notion of the inode and inode offset of the block.
- Forget a block. The caller passes a ''(dev, dev_off)'' pair to VM, along with a block size. If the block exists, VM throws it out of the cache.
- Clear blocks. The caller passes a ''dev'' device identifier to VM, and VM removes all blocks associated with that device from its cache.
==== C Interface ====
There are four calls, ''vm_set_cacheblock'', ''vm_map_cacheblock'', ''vm_forget_cacheblock'', and ''vm_clear_cache''.
int vm_set_cacheblock(void *block, dev_t dev, off_t dev_offset,
ino_t ino, off_t ino_offset, u32_t *flags, int blocksize, int setflags);
This call indicates a new block to VM. If the block is not inode data, ino
must be VMC_NO_INODE. flags points to a 32-bit flags field that is a mask
of VMMC_* values. This is currently unused but it is to be expected that
in the future, VM will evict blocks not marked by VMMC_BLOCK_LOCKED or
VMMC_DIRTY, so callers must set these when in use or dirty, respectively.
The ''setflags'' field should generally be set to zero, but the caller may supply ''VMSC_ONCE'' to indicate that the block should be used only for immediate use to map in a mmap'ed page, and not be cached beyond that. The ''VMSC_ONCE'' flag prevents cached blocks from going stale and is used by file systems that do not have a block cache and do not track updates to file contents.
The caller has allocated memory for block and filled it with the correct
data already.
The call returns OK or an error code.
void *vm_map_cacheblock(dev_t dev, off_t dev_offset,
ino_t ino, off_t ino_offset, u32_t *flags, int blocksize);
This call requests the block identified by the device number and offset to
be mapped in. It returns an address on success or MAP_FAILED on failure (e.g.
block not found). VM updates its notion of the inode metadata with the
parameters if the block was already in the cache.
int vm_forget_cacheblock(dev_t dev, off_t dev_offset, int blocksize);
This call requests that the block identified by the device number and offset be thrown out of the VM cache. Any previous inode association for this block is therefore broken as well. The call returns OK on success, even if no matching block was found. An error code is returned if the given parameter are invalid.
int vm_clear_cache(dev_t dev);
This call requests that VM forget all blocks associated with the given device. This call should be used (directly or indirectly) by file systems when 1) they get a REQ_FLUSH request from VFS, and 2) when they successfully unmount. This ensures that no stale blocks remain in VM, which could cause corruption upon recall later.