AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
blkcache.c File Reference

The block cache: what the disks read and write, kept in 4 KiB blocks. More...

#include <core/system.h>
#include <core/string.h>
#include <core/arch.h>
#include <mm/mm.h>
#include <dev/blkcache.h>
#include <aquila/errno.h>

Go to the source code of this file.

Data Structures

struct  blk
 A block of the cache. More...

Macros

#define SECTOR_SIZE   512
#define BLK_SECTORS   8
#define BLK_SIZE   (BLK_SECTORS * SECTOR_SIZE)
#define BLK_ALL   0xFF
#define CACHE_BLOCKS   2048
#define CACHE_BUCKETS   1024
#define RUN_MAX   16
#define DIRTY_MAX   (CACHE_BLOCKS / 2)
#define DIRTY_AGE   5000000000ULL

Functions

static char * blk_data (struct blk *b)
 Returns a block's data.
static uint8_t sector_mask (size_t first, size_t n)
 Returns the mask of n sectors from sector first of a block.
static struct blk ** bucket (void *owner, uint64_t nr)
 Returns the hash chain that block nr of owner is on.
static struct blk * lookup (void *owner, uint64_t nr)
 Returns block nr of owner, or NULL if it isn't cached.
static void lru_unlink (struct blk *b)
 Takes a block off the list of blocks by use.
static void lru_push (struct blk *b)
 Puts a block at the head of the list: the most recently used.
static void touch (struct blk *b)
 Marks a block as just used.
static void evict (struct blk *b)
 Takes a clean block out of the cache.
static void make_dirty (struct blk *b, uint8_t mask, blkcache_io write)
 Marks sectors of a block dirty, to be written with write.
static void make_clean (struct blk *b, uint8_t mask)
 Marks sectors of a block clean.
static struct blk * block_new (void *owner, uint64_t nr)
 Takes a block for block nr of owner, with nothing valid in it: a free slot, or the clean block used least recently.
static void prefault (void *buf, size_t size, int write)
 Maps every page of a buffer, by touching them: a process's buffer isn't mapped until it is used.
static void overlap (uint64_t nr, uint64_t sector, size_t count, size_t *first, size_t *n, size_t *off)
 Finds the sectors of block nr that are in the request [sector, sector + count): n of them, from sector first of the block, at sector off of the request.
static int full_dirty (struct blk *b)
 Returns whether a block exists and all its sectors are dirty.
static int flush_block (struct blk *b)
 Writes the dirty sectors of b to the disk (with the wholly dirty blocks right after it, in one command), and marks them clean.
int blkcache_flush (void)
 Writes every dirty block of the cache to its disk.
static void flush_old (void)
 Writes the dirty blocks to the disk if the oldest one is old enough (DIRTY_AGE).
ssize_t blkcache_read (void *owner, uint64_t sector, size_t count, void *buf, uint64_t nsectors, blkcache_io read)
 Reads sectors of a disk through the cache.
ssize_t blkcache_write (void *owner, uint64_t sector, size_t count, void *buf, blkcache_io write)
 Writes sectors of a disk through the cache: they stay dirty in it until it is flushed.

Variables

static struct blk blks [CACHE_BLOCKS]
static char * arena
static struct blk * buckets [CACHE_BUCKETS]
static struct blk * newest
static struct blk * oldest
static size_t used
static size_t dirty
static uint64_t dirty_since
static uint64_t writes

Detailed Description

The block cache: what the disks read and write, kept in 4 KiB blocks.

Writes stay in the cache (write back) until blkcache_flush() writes them to the disk: for sync(), before restarting or powering off, when too much was written (DIRTY_MAX), or at the next use of the cache once a write is old enough (DIRTY_AGE). Each sector of a block is either valid (it has the disk's data, or newer) or not, and either dirty (newer than the disk's) or not, so a write doesn't need to read the rest of its block. When the cache is full, the clean block used least recently makes room.

Drivers use the cache with absolute sector numbers, after adding the partition's offset, so a sector is cached once, whichever device node it was read through. The blocks that a read needs and the cache doesn't have are read with one command, and adjacent dirty blocks are written with one.

The device's transfers are always to and from the cache's own buffers, never the caller's. The caller's buffer may be a process's, which isn't mapped until it is touched, and mapping it may read the disk: the driver would wait for itself. The caller's buffer is only used once its pages are mapped.

Definition in file blkcache.c.

Macro Definition Documentation

◆ BLK_ALL

#define BLK_ALL   0xFF

Definition at line 38 of file blkcache.c.

Referenced by flush_block(), and full_dirty().

◆ BLK_SECTORS

#define BLK_SECTORS   8

Definition at line 36 of file blkcache.c.

Referenced by blkcache_read(), blkcache_write(), flush_block(), and overlap().

◆ BLK_SIZE

#define BLK_SIZE   (BLK_SECTORS * SECTOR_SIZE)

Definition at line 37 of file blkcache.c.

Referenced by blk_data(), blkcache_read(), block_new(), and flush_block().

◆ CACHE_BLOCKS

#define CACHE_BLOCKS   2048

Definition at line 41 of file blkcache.c.

Referenced by blkcache_flush(), and block_new().

◆ CACHE_BUCKETS

#define CACHE_BUCKETS   1024

Definition at line 42 of file blkcache.c.

Referenced by bucket().

◆ DIRTY_AGE

#define DIRTY_AGE   5000000000ULL

Definition at line 50 of file blkcache.c.

Referenced by flush_old().

◆ DIRTY_MAX

#define DIRTY_MAX   (CACHE_BLOCKS / 2)

Definition at line 49 of file blkcache.c.

Referenced by blkcache_write().

◆ RUN_MAX

#define RUN_MAX   16

Definition at line 45 of file blkcache.c.

Referenced by blkcache_flush(), blkcache_read(), and flush_block().

◆ SECTOR_SIZE

#define SECTOR_SIZE   512

Definition at line 35 of file blkcache.c.

Referenced by blkcache_read(), blkcache_write(), and flush_block().

Function Documentation

◆ blk_data()

char * blk_data ( struct blk * b)
inlinestatic

Returns a block's data.

Definition at line 78 of file blkcache.c.

References arena, blk_data(), BLK_SIZE, and blks.

Referenced by blk_data(), blkcache_read(), blkcache_write(), and flush_block().

◆ blkcache_flush()

int blkcache_flush ( void )

Writes every dirty block of the cache to its disk.

Returns
0, or a negative errno if a write failed

Definition at line 309 of file blkcache.c.

References blkcache_flush(), blks, CACHE_BLOCKS, blk::dirty, dirty, flush_block(), full_dirty(), lookup(), blk::nr, blk::owner, RUN_MAX, and blk::write.

Referenced by blkcache_flush(), blkcache_write(), flush_old(), and kdev_sync().

◆ blkcache_read()

ssize_t blkcache_read ( void * owner,
uint64_t sector,
size_t count,
void * buf,
uint64_t nsectors,
blkcache_io read )

Reads sectors of a disk through the cache.

The sectors the cache doesn't have are read with read, and cached.

Parameters
ownerthe disk (the driver's, for its sectors)
sectorthe first sector, absolute on the disk
counthow many sectors
bufwhere to put them
nsectorsthe disk's size in sectors, or 0 if it isn't known
readhow the driver reads sectors
Returns
0, or a negative errno (-EIO past the disk's end)

Definition at line 367 of file blkcache.c.

References blk_data(), BLK_SECTORS, BLK_SIZE, blkcache_read(), block_new(), flush_old(), kfree(), kmalloc(), lookup(), memcpy(), MIN, blk::nr, overlap(), blk::owner, prefault(), RUN_MAX, sector_mask(), SECTOR_SIZE, touch(), blk::valid, and writes.

Referenced by ata_read(), and blkcache_read().

◆ blkcache_write()

ssize_t blkcache_write ( void * owner,
uint64_t sector,
size_t count,
void * buf,
blkcache_io write )

Writes sectors of a disk through the cache: they stay dirty in it until it is flushed.

If the cache has no room even after flushing, they go straight to the disk.

Parameters
ownerthe disk (the driver's, for its sectors)
sectorthe first sector, absolute on the disk
counthow many sectors
bufthe sectors' data
writehow the driver writes sectors
Returns
0, or a negative errno

Definition at line 484 of file blkcache.c.

References blk_data(), BLK_SECTORS, blkcache_flush(), blkcache_write(), block_new(), dirty, DIRTY_MAX, flush_old(), kfree(), kmalloc(), lookup(), make_dirty(), memcpy(), blk::nr, overlap(), blk::owner, prefault(), sector_mask(), SECTOR_SIZE, touch(), blk::valid, blk::write, and writes.

Referenced by ata_write(), and blkcache_write().

◆ block_new()

struct blk * block_new ( void * owner,
uint64_t nr )
static

Takes a block for block nr of owner, with nothing valid in it: a free slot, or the clean block used least recently.

Returns NULL if every block is dirty, or there is no memory for the cache.

Definition at line 166 of file blkcache.c.

References arena, BLK_SIZE, blks, block_new(), bucket(), CACHE_BLOCKS, blk::dirty, evict(), blk::hnext, kmalloc(), lru_push(), blk::newer, blk::nr, NULL, oldest, blk::owner, used, and blk::valid.

Referenced by blkcache_read(), blkcache_write(), and block_new().

◆ bucket()

struct blk ** bucket ( void * owner,
uint64_t nr )
inlinestatic

Returns the hash chain that block nr of owner is on.

Definition at line 90 of file blkcache.c.

References bucket(), buckets, CACHE_BUCKETS, blk::nr, and blk::owner.

Referenced by block_new(), bucket(), evict(), and lookup().

◆ evict()

void evict ( struct blk * b)
static

Takes a clean block out of the cache.

Definition at line 133 of file blkcache.c.

References bucket(), evict(), blk::hnext, lru_unlink(), blk::nr, NULL, blk::owner, and used.

Referenced by block_new(), and evict().

◆ flush_block()

int flush_block ( struct blk * b)
static

Writes the dirty sectors of b to the disk (with the wholly dirty blocks right after it, in one command), and marks them clean.

Returns 0 or a negative errno; sectors whose write failed stay dirty.

Definition at line 241 of file blkcache.c.

References BLK_ALL, blk_data(), BLK_SECTORS, BLK_SIZE, blk::dirty, flush_block(), full_dirty(), kfree(), kmalloc(), lookup(), make_clean(), make_dirty(), memcpy(), blk::nr, blk::owner, RUN_MAX, sector_mask(), SECTOR_SIZE, and blk::write.

Referenced by blkcache_flush(), and flush_block().

◆ flush_old()

void flush_old ( void )
static

Writes the dirty blocks to the disk if the oldest one is old enough (DIRTY_AGE).

Definition at line 344 of file blkcache.c.

References arch_rtime_ns(), blkcache_flush(), dirty, DIRTY_AGE, dirty_since, and flush_old().

Referenced by blkcache_read(), blkcache_write(), and flush_old().

◆ full_dirty()

int full_dirty ( struct blk * b)
inlinestatic

Returns whether a block exists and all its sectors are dirty.

Definition at line 233 of file blkcache.c.

References BLK_ALL, blk::dirty, and full_dirty().

Referenced by blkcache_flush(), flush_block(), and full_dirty().

◆ lookup()

struct blk * lookup ( void * owner,
uint64_t nr )
static

Returns block nr of owner, or NULL if it isn't cached.

Definition at line 96 of file blkcache.c.

References bucket(), blk::hnext, lookup(), blk::nr, NULL, and blk::owner.

Referenced by blkcache_flush(), blkcache_read(), blkcache_write(), flush_block(), and lookup().

◆ lru_push()

void lru_push ( struct blk * b)
static

Puts a block at the head of the list: the most recently used.

Definition at line 114 of file blkcache.c.

References lru_push(), blk::newer, newest, NULL, blk::older, and oldest.

Referenced by block_new(), lru_push(), and touch().

◆ lru_unlink()

void lru_unlink ( struct blk * b)
static

Takes a block off the list of blocks by use.

Definition at line 106 of file blkcache.c.

References lru_unlink(), blk::newer, newest, NULL, blk::older, and oldest.

Referenced by evict(), lru_unlink(), and touch().

◆ make_clean()

void make_clean ( struct blk * b,
uint8_t mask )
static

Marks sectors of a block clean.

Definition at line 157 of file blkcache.c.

References blk::dirty, dirty, and make_clean().

Referenced by flush_block(), and make_clean().

◆ make_dirty()

void make_dirty ( struct blk * b,
uint8_t mask,
blkcache_io write )
static

Marks sectors of a block dirty, to be written with write.

Definition at line 147 of file blkcache.c.

References arch_rtime_ns(), blk::dirty, dirty, dirty_since, make_dirty(), and blk::write.

Referenced by blkcache_write(), flush_block(), and make_dirty().

◆ overlap()

void overlap ( uint64_t nr,
uint64_t sector,
size_t count,
size_t * first,
size_t * n,
size_t * off )
static

Finds the sectors of block nr that are in the request [sector, sector + count): n of them, from sector first of the block, at sector off of the request.

Definition at line 221 of file blkcache.c.

References BLK_SECTORS, MAX, MIN, blk::nr, and overlap().

Referenced by blkcache_read(), blkcache_write(), and overlap().

◆ prefault()

void prefault ( void * buf,
size_t size,
int write )
static

Maps every page of a buffer, by touching them: a process's buffer isn't mapped until it is used.

It is done before the cache is looked at, because mapping a page may read the disk and change the cache.

Definition at line 203 of file blkcache.c.

References PAGE_ALIGN, PAGE_SIZE, prefault(), and blk::write.

Referenced by blkcache_read(), blkcache_write(), and prefault().

◆ sector_mask()

uint8_t sector_mask ( size_t first,
size_t n )
inlinestatic

Returns the mask of n sectors from sector first of a block.

Definition at line 84 of file blkcache.c.

References sector_mask().

Referenced by blkcache_read(), blkcache_write(), flush_block(), and sector_mask().

◆ touch()

void touch ( struct blk * b)
static

Marks a block as just used.

Definition at line 124 of file blkcache.c.

References lru_push(), lru_unlink(), newest, and touch().

Referenced by blkcache_read(), blkcache_write(), and touch().

Variable Documentation

◆ arena

char* arena
static

Definition at line 64 of file blkcache.c.

Referenced by blk_data(), and block_new().

◆ blks

struct blk blks[CACHE_BLOCKS]
static

Definition at line 63 of file blkcache.c.

Referenced by blk_data(), blkcache_flush(), and block_new().

◆ buckets

struct blk* buckets[CACHE_BUCKETS]
static

Definition at line 66 of file blkcache.c.

Referenced by bucket(), and hashmap_grow().

◆ dirty

size_t dirty
static

Definition at line 68 of file blkcache.c.

Referenced by blkcache_flush(), blkcache_write(), flush_old(), make_clean(), and make_dirty().

◆ dirty_since

uint64_t dirty_since
static

Definition at line 71 of file blkcache.c.

Referenced by flush_old(), and make_dirty().

◆ newest

struct blk* newest
static

Definition at line 67 of file blkcache.c.

Referenced by lru_push(), lru_unlink(), and touch().

◆ oldest

struct blk * oldest
static

Definition at line 67 of file blkcache.c.

Referenced by block_new(), lru_push(), and lru_unlink().

◆ used

size_t used
static

Definition at line 68 of file blkcache.c.

Referenced by arp_update(), block_new(), and evict().

◆ writes

uint64_t writes
static

Definition at line 75 of file blkcache.c.

Referenced by blkcache_read(), and blkcache_write().