Skip to content

Commit

Permalink
Replace ring_io with file_cache
Browse files Browse the repository at this point in the history
This allows using the extra memory available on at32f435 which was not
possible with ring_io. It also has two side-goals of reducing the
diff and I/O behavior in image handlers compared to stable-v3 and
reducing overall code size.

While readahead was a core principal of ring_io, it is more of a bolt-on
for file_cache; file_cache focuses more on batched reads and writes.
File_cache tries to look more like the normal F_read, F_write, and
volume_cache with the main difference being that operations cannot span
sectors. file_cache_{read,write} could easily support multi-sector ops,
but no callers need such a thing as multi-sector reads/writes were for
batching.

file_cache still supports the "write directly to the cache" behavior
available in ring_io, but HFE and QD are the only images that make use
of it. The other images use a write buffer to avoid the read-then-write
that was required with ring_io. Those other images now do not do
reading-during-writing when their sector sizes are 512 or larger, which
matches stable-v3 behavior.

Since file_cache doesn't require read-before-write, the readahead can be
higher or lower priority than writes.
  • Loading branch information
ejona86 committed Jul 9, 2023
1 parent eec2372 commit 717bc47
Show file tree
Hide file tree
Showing 19 changed files with 928 additions and 1,006 deletions.
5 changes: 2 additions & 3 deletions Rules.mk
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,10 @@ FLAGS += -Wno-unused-value -ffunction-sections
ifeq ($(mcu),stm32f105)
FLAGS += -mcpu=cortex-m3 -DSTM32F105=1 -DMCU=1
ifeq ($(bootloader),y)
override logfile=n
endif
# Debug builds don't fit in available Flash. FIXME for main firmware.
# Debug bootloader doesn't fit in 32kB
override debug=n
override logfile=n
endif

## AT32F435
else ifeq ($(mcu),at32f435)
Expand Down
35 changes: 23 additions & 12 deletions inc/cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,40 @@
* See the file COPYING for more details, or visit <http://unlicense.org>.
*/

#if !defined(BOOTLOADER)

/* Use memory range (@start,@end) to cache data items of size @item_sz. */
struct cache *cache_init(void *start, void *end, unsigned int item_sz);
/* Use memory range (@start,@end) to cache data items of size @item_sz.
* For non-NULL return, @entry_cnt will be set to number of entries available.
*/
struct cache *cache_init(void *start, void *end, unsigned int item_sz,
unsigned int *entry_cnt);

/* Look up item @id in the cache. Return a pointer to cached data, or NULL. */
const void *cache_lookup(struct cache *c, uint32_t id);

/* Look up item @id in the cache. Return a pointer to cached data, or NULL. */
void *cache_lookup_mutable(struct cache *c, uint32_t id);

/* Returns the item id and cached data of the entry that might be evicted by
* the next cache_update. Returns NULL if no entry might be evicted. */
void *cache_lru_mutable(struct cache *c, uint32_t *id);

/* Returns the item id and cache data of the next entry that might be evicted
* after @ent. Returns NULL if @ent is the most recent entry. */
void *cache_lru_next_mutable(struct cache *c, const void* ent, uint32_t *id);

/* Returns the item id and cached data of the LRU entry, even if it is not
* nearing eviction. Returns NULL if no entries are in the cache. */
void *cache_lru_search_mutable(struct cache *c, uint32_t *id);

/* Update item @id with data @dat. Inserts the item if not present.*/
void cache_update(struct cache *c, uint32_t id, const void *dat);

/* Update @N items (@id..@id+@N-1) with data @dat. Calls cache_update(). */
void cache_update_N(struct cache *c, uint32_t id,
const void *dat, unsigned int N);

#else

#define cache_init(a,b,c) NULL
#define cache_lookup(a,b) NULL
#define cache_update(a,b,c) ((void)0)
#define cache_update_N(a,b,c,d) ((void)0)

#endif
/* Update item @id using returned pointer to item. Creates an uninitialized
* item if not present, and sets @created to true. */
void *cache_update_mutable(struct cache *c, uint32_t id, bool_t *created);

/*
* Local variables:
Expand Down
2 changes: 1 addition & 1 deletion inc/decls.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@
#include "spi.h"
#include "timer.h"
#include "thread.h"
#include "file_cache.h"
#include "fs.h"
#include "fs_async.h"
#include "ring_io.h"
#include "floppy.h"
#include "volume.h"
#include "config.h"
Expand Down
74 changes: 74 additions & 0 deletions inc/file_cache.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* file_cache.h
*
* Caching I/O for a single file.
*
* Written & released by Keir Fraser <keir.xen@gmail.com> and Eric Anderson
* <ejona86@gmail.com>
*
* This is free and unencumbered software released into the public domain.
* See the file COPYING for more details, or visit <http://unlicense.org>.
*/

/* The cache is a write-back cache and uses an I/O scheduler to schedule reads
* and writes, with preference given to reads. Cache tracking is per-sector of
* 512 bytes.
*
* The cache tries to batch reads and writes into batches of maximum size
* 'batch_secs'. The file is split into aligned groups of batch_secs, and
* batching cannot cross the boundary of groups. A read batch starts from the
* sector requested and ends at the first already-read sector or end of the
* group. Writes are not delayed to form a batch, but batches form if there are
* delays due to reads or slow writes.
*
* In addition to batch reads, readahead can be enabled via
* file_cache_readahead(). Reads and writes within the provided region will
* cause the scheduler to read additional sectors, wrapping around when getting
* to the end of the region.
*/

struct file_cache;

struct file_cache *file_cache_init(FIL *fp, uint8_t batch_secs,
void *start, void *end);
/* Waits until written data is flushed and synced to storage. */
void file_cache_sync_wait(struct file_cache *fcache);
/* Stops scheduling I/O and waits for outstanding I/O to complete. To ensure
* data is not lost, use file_cache_sync_wait() first. */
void file_cache_shutdown(struct file_cache *fcache);
/* Run the I/O scheduler without requesting new I/O. Necessary for periods
* without I/O operations for writing and readahead. */
void file_cache_progress(struct file_cache *fcache);
/* Limit I/O operation size potentially below that of batch_sec. 0 disables the
* limit. */
void file_cache_io_limit(struct file_cache *fcache, uint8_t io_max);
/* Enable readahead for I/O ops within the specified region. @prio bytes are
* higher priority than writes. */
void file_cache_readahead(
struct file_cache *fcache, FSIZE_t ofs, UINT btr, UINT prio);

/* Read within a sector. Will block until data is read. */
void file_cache_read(struct file_cache *fcache, void *buf, FSIZE_t ofs,
UINT btr);
/* Read within a sector. If FALSE, try again later. */
bool_t file_cache_try_read(struct file_cache *fcache, void *buf, FSIZE_t ofs,
UINT btr);
/* Read 512 bytes at sector-aligned @ofs. Returns NULL if read is not yet
* available. */
const void *file_cache_peek_read(struct file_cache *fcache, FSIZE_t ofs);

/* Write within a sector. May block waiting on cache space, or if a partial
* sector is being written and the sector data is not already cached. */
void file_cache_write(struct file_cache *fcache, const void *buf,
FSIZE_t ofs, UINT btw);
/* Write within a sector. If FALSE, try again later. */
bool_t file_cache_try_write(struct file_cache *fcache, const void *buf,
FSIZE_t ofs, UINT btw);
/* Read 512 bytes at sector-aligned @ofs . Returns NULL if
* the write is not yet possible. If the return is non-NULL, data written to
* the buffer is observed by the next write or file_cache_sync(). Reads are
* not permitted until the written data is observed. */
void *file_cache_peek_write(struct file_cache *fcache, FSIZE_t ofs);

/* Flush filesystem cached data for file. Does not wait for it to complete. */
void file_cache_sync(struct file_cache *fcache);
48 changes: 21 additions & 27 deletions inc/floppy.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,46 +46,32 @@ struct image_buf {
uint32_t prod, cons;
};

struct image_bufs {
/* Buffering for bitcells being written to disk. */
struct image_buf write_bc;
/* Buffering for bitcells we generate from read_data. */
struct image_buf read_bc;
/* Staging area for writeout to mass storage. */
struct image_buf write_data;
/* Read buffer for track data to be used for generating flux pattern. */
struct image_buf read_data;
};

struct adf_image {
struct ring_io ring_io;
struct file_cache *fcache;
uint32_t trk_off;
uint32_t sec_idx;
int32_t decode_pos;
uint32_t pre_idx_gap_bc;
uint32_t nr_secs;
uint32_t written_secs;
uint16_t trash_bc; /* Number of bitcells to throw away. */
uint8_t sec_map[2][22];
struct image_buf write_buffer;
uint16_t *write_offsets; /* File offset of each 512 byte buffer segment */
FOP write_op;
uint8_t write_cnt;
uint8_t sync_state;
bool_t ring_io_inited;
};

struct hfe_image {
struct ring_io ring_io;
struct file_cache *fcache;
uint16_t tlut_base;
uint16_t trk_len;
uint16_t trk_off;
uint16_t trk_pos, trk_len;
bool_t is_v3, double_step, fresh_seek;
uint8_t next_index_pulses_pos;
};

struct qd_image {
struct ring_io ring_io;
struct file_cache *fcache;
uint16_t tb;
uint32_t trk_len;
uint32_t trk_off;
uint32_t trk_pos, trk_len;
uint32_t win_start, win_end;
};

Expand All @@ -108,6 +94,7 @@ struct raw_trk {
};

struct img_image {
struct file_cache *fcache;
uint32_t trk_off, base_off;
/* Length on-disk that encompases all track data. May contain other data
* (e.g., the other side of the cylinder). */
Expand All @@ -127,18 +114,14 @@ struct img_image {
/* Delay start of track this many bitcells past index. */
uint32_t track_delay_bc;
uint16_t gap_4;
uint8_t shadow;
uint16_t trash_bc; /* Number of bitcells to throw away. */
uint32_t idx_sz, idam_sz;
uint16_t dam_sz_pre, dam_sz_post;
void *heap_bottom;
struct image_buf track_data;
struct ring_io ring_io;
};

struct dsk_image {
struct ring_io ring_io;
struct image_buf track_data;
struct file_cache *fcache;
uint32_t trk_off;
uint16_t trk_pos;
uint16_t rd_sec_pos;
Expand Down Expand Up @@ -168,6 +151,17 @@ struct directaccess {
bool_t lba_set;
};

struct image_bufs {
/* Buffering for bitcells being written to disk. */
struct image_buf write_bc;
/* Buffering for bitcells we generate from read_data. */
struct image_buf read_bc;
/* Staging area for writeout to mass storage. */
struct image_buf write_data;
/* Read buffer for track data to be used for generating flux pattern. */
struct image_buf read_data;
};

#define MAX_CUSTOM_PULSES 34 /* 33+1 for minor track misalignment */

struct image {
Expand Down
2 changes: 1 addition & 1 deletion inc/list.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ static inline void list_remove(struct list_head *ent)
ent->prev->next = ent->next;
}

static inline bool_t list_is_empty(struct list_head *head)
static inline bool_t list_is_empty(const struct list_head *head)
{
return head->next == head;
}
Expand Down
88 changes: 0 additions & 88 deletions inc/ring_io.h

This file was deleted.

2 changes: 1 addition & 1 deletion src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ OBJS += config.o
OBJS += crc.o
OBJS += flash_cfg.o
OBJS += vectors.o
OBJS += file_cache.o
OBJS += fpec_$(mcu).o
OBJS += fs.o
OBJS += fs_async.o
OBJS += ring_io.o
OBJS += sd_spi.o
OBJS += spi.o
OBJS += string.o
Expand Down
Loading

0 comments on commit 717bc47

Please sign in to comment.