dev: implement reading from block devices

reading from block devices is done using the block cache (bcache).
This cache stores sectors from a block device in pages of memory
marked as 'cached', which will allow them to be reclaimed when
memory pressure is high (TODO).

while block device drivers implement callbacks allowing reading/writing
at block-granularity, the device subsystem uses the block cache to
implement reading/writing at byte-granularity in a driver-agnostic way.

block drivers can disable the block cache for their devices, but this
will require that any clients communicate with the devices at
block-granularity.

also added an offset parameter to device and object read/write functions/callbacks.
This commit is contained in:
2023-07-09 21:58:40 +01:00
parent 53440653f2
commit 3233169f25
14 changed files with 435 additions and 52 deletions

View File

@@ -5,6 +5,8 @@
#include <socks/types.h>
#include <socks/status.h>
#include <socks/queue.h>
#include <socks/btree.h>
#include <socks/bitmap.h>
#include <socks/locks.h>
#include <socks/machine/vm.h>
@@ -12,6 +14,8 @@
extern "C" {
#endif
struct bcache;
/* maximum number of NUMA nodes */
#define VM_MAX_NODES 64
/* maximum number of memory zones per node */
@@ -21,6 +25,11 @@ extern "C" {
/* maximum number of sparse memory sectors */
#define VM_MAX_SECTORS 1024
/* maximum number of disk sectors that can be stored in a single
page. AKA the number of bits in the sector bitmap.
used by the block cache */
#define VM_MAX_SECTORS_PER_PAGE 32
#define VM_CHECK_ALIGN(p, mask) ((((p) & (mask)) == (p)) ? 1 : 0)
#define VM_CACHE_INITIALISED(c) ((c)->c_obj_count != 0)
@@ -108,6 +117,8 @@ enum vm_page_flags {
VM_PAGE_HEAD = 0x04u,
/* page is part of a huge-page */
VM_PAGE_HUGE = 0x08u,
/* page is holding cached data from secondary storage, and can be freed if necessary (and not dirty). */
VM_PAGE_CACHE = 0x10u,
};
enum vm_memory_region_status {
@@ -210,18 +221,40 @@ struct vm_page {
uint32_t p_flags;
/* multi-purpose list.
/* owner-specific pointer */
union {
struct vm_slab *p_slab;
struct bcache *p_bcache;
void *p_priv0;
};
/* multi-purpose list/tree entry.
the owner of the page can decide what to do with this.
some examples:
- the buddy allocator uses this to maintain its per-zone free-page lists.
- the block cache uses this to maintain a tree of pages keyed by block number.
*/
struct queue_entry p_list;
/* owner-specific data */
union {
struct vm_slab *p_slab;
struct queue_entry p_list;
struct btree_node p_bnode;
/* btree_node contains three pointers, so provide three pointer-sized integers for
use if p_bnode isn't needed. */
uintptr_t priv1[3];
};
union {
/* used by bcache when sector size is < page size. bitmap of present/missing sectors */
DECLARE_BITMAP(p_blockbits, VM_MAX_SECTORS_PER_PAGE);
uint32_t p_priv2;
};
union {
/* sector address, used by bcache */
sectors_t p_blockid;
uint32_t p_priv3[2];
};
} __attribute__((aligned(2 * sizeof(unsigned long))));
/* represents a sector of memory, containing its own array of vm_pages.