31#include <aquila/errno.h>
35#define SECTOR_SIZE 512
37#define BLK_SIZE (BLK_SECTORS * SECTOR_SIZE)
41#define CACHE_BLOCKS 2048
42#define CACHE_BUCKETS 1024
49#define DIRTY_MAX (CACHE_BLOCKS / 2)
50#define DIRTY_AGE 5000000000ULL
86 return ((1U << n) - 1) << first;
99 if (b->owner ==
owner && b->nr ==
nr)
205 volatile char *p = buf, *end = (
char *) buf + size;
214 if (
write) end[-1] = c;
222 size_t *first,
size_t *n,
size_t *off)
229 *off = start - sector;
249 if (!tmp)
return -ENOMEM;
264 for (
size_t i = 0; i < run; ++i)
273 if (!(mask & (1 << s))) {
279 while (s + n <
BLK_SECTORS && (mask & (1 << (s + n))))
301 return err < 0 ? err : 0;
372 size_t first, n, off;
383 overlap(
nr, sector, count, &first, &n, &off);
386 if (b && (b->
valid & need) == need) {
395 while (
nr + run <= last && run <
RUN_MAX) {
399 overlap(
nr + run, sector, count, &f, &k, &o);
411 if (nsectors && start + sectors > nsectors)
412 sectors = start < nsectors ? nsectors - start : 0;
430 for (
size_t i = 0; i < run; ++i) {
434 overlap(
nr + i, sector, count, &first, &n, &off);
436 if (first + n > have) {
451 for (
size_t s = 0; s < have; ++s) {
452 if (!(r->
valid & (1 << s))) {
488 size_t first, n, off;
500 overlap(
nr, sector, count, &first, &n, &off);
540 return err < 0 ? err : 0;
static struct blk * buckets[CACHE_BUCKETS]
static struct blk * oldest
static int flush_block(struct blk *b)
Writes the dirty sectors of b to the disk (with the wholly dirty blocks right after it,...
static char * blk_data(struct blk *b)
Returns a block's data.
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,...
static void flush_old(void)
Writes the dirty blocks to the disk if the oldest one is old enough (DIRTY_AGE).
static uint8_t sector_mask(size_t first, size_t n)
Returns the mask of n sectors from sector first of a block.
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.
static void touch(struct blk *b)
Marks a block as just used.
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.
static struct blk ** bucket(void *owner, uint64_t nr)
Returns the hash chain that block nr of owner is on.
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 int full_dirty(struct blk *b)
Returns whether a block exists and all its sectors are dirty.
static void make_clean(struct blk *b, uint8_t mask)
Marks sectors of a block clean.
static struct blk blks[CACHE_BLOCKS]
static struct blk * newest
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.
int blkcache_flush(void)
Writes every dirty block of the cache to its disk.
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 l...
static void lru_unlink(struct blk *b)
Takes a block off the list of blocks by use.
static uint64_t dirty_since
static struct blk * lookup(void *owner, uint64_t nr)
Returns block nr of owner, or NULL if it isn't cached.
static void evict(struct blk *b)
Takes a clean block out of the cache.
static void lru_push(struct blk *b)
Puts a block at the head of the list: the most recently used.
ssize_t(*) blkcache_io(void *owner, uint64_t sector, size_t count, void *buf)
#define MALLOC_DEFINE(type, _name, _desc)
void * kmalloc(size_t size, struct malloc_type *type, int flags)
Allocates memory for one of the kernel's structures.
void kfree(void *)
Frees an object that kmalloc() gave.
void * memcpy(void *dst, const void *src, size_t n)
Copies n bytes; dst and src must not overlap.
unsigned long long int uint64_t
uint64_t arch_rtime_ns(void)
Reads the monotonic clock, which starts at boot.