Skip to content

Commit

Permalink
TFS: inflate existing file extents, eliminate extent size maximum
Browse files Browse the repository at this point in the history
When file data is being written beyond the range of an existing
file extent, if the storage space adjacent to the extent is free,
the extent can be extended to cover additional storage space,
instead of creating a new extent; this keeps the amount of file
metadata down and minimizes the number of disk I/O requests being
used to transfer a given amount of data.
The existing maximum limit of 1 MB on extent creation is no longer
necessary and is being removed. Since allocations from the storage
space are aligned to the allocation size, requesting large extents
can create large unallocated ranges in the storage space; in order
to be able to fill these ranges when requesting a new extent that
does not fit into a single contiguous storage area, the
create_extent() function upon allocation failure retries an
allocation with a smaller size (down to a 1MB limit); the code that
calls this function has been amended to properly handle the cases
where the size of a created extent is smaller than requested.
  • Loading branch information
francescolavra committed Aug 31, 2022
1 parent dc9fe3c commit 65434ad
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 17 deletions.
61 changes: 45 additions & 16 deletions src/tfs/tfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -584,8 +584,8 @@ static fs_status filesystem_truncate_locked(filesystem fs, fsfile f, u64 len)
The life an extent depends on a particular allocation of contiguous
storage space. The extent is tied to this allocated area (nominally
page size). Only the extent data length may be updated; the file
offset, block start and allocation size are immutable. As an
page size). Only the extent data length and allocation size may be
updated; the file offset and block start are immutable. As an
optimization, adjacent extents on the disk could be joined into
larger extents with only a meta update.
Expand All @@ -603,6 +603,12 @@ static fs_status create_extent(filesystem fs, range blocks, boolean uninited, ex
return FS_STATUS_NOSPACE;

u64 start_block = filesystem_allocate_storage(fs, nblocks);
while (start_block == u64_from_pointer(INVALID_ADDRESS)) {
if (nblocks <= (MIN_EXTENT_ALLOC_SIZE >> fs->blocksize_order))
break;
nblocks /= 2;
start_block = filesystem_allocate_storage(fs, nblocks);
}
if (start_block == u64_from_pointer(INVALID_ADDRESS))
return FS_STATUS_NOSPACE;

Expand Down Expand Up @@ -687,19 +693,12 @@ static fs_status add_extents(filesystem fs, range i, rangemap rm)
{
extent ex;
fs_status fss;
while (range_span(i) >= MAX_EXTENT_SIZE) {
range r = {.start = i.start, .end = i.start + MAX_EXTENT_SIZE};
fss = create_extent(fs, r, true, &ex);
if (fss != FS_STATUS_OK)
return fss;
assert(rangemap_insert(rm, &ex->node));
i.start += MAX_EXTENT_SIZE;
}
if (range_span(i)) {
while (range_span(i)) {
fss = create_extent(fs, i, true, &ex);
if (fss != FS_STATUS_OK)
return fss;
assert(rangemap_insert(rm, &ex->node));
i.start = ex->node.r.end;
}
return FS_STATUS_OK;
}
Expand Down Expand Up @@ -836,13 +835,12 @@ static u64 write_extent(fsfile f, extent ex, sg_list sg, range blocks, merge m)

static fs_status fill_gap(fsfile f, sg_list sg, range blocks, merge m, u64 *edge)
{
blocks = irangel(blocks.start, MIN(MAX_EXTENT_SIZE >> f->fs->blocksize_order,
range_span(blocks)));
tfs_debug(" %s: writing new extent blocks %R\n", __func__, blocks);
extent ex;
fs_status fss = create_extent(f->fs, blocks, false, &ex);
if (fss != FS_STATUS_OK)
return fss;
blocks = ex->node.r;
fss = add_extent_to_file(f, ex);
if (fss != FS_STATUS_OK) {
destroy_extent(f->fs, ex);
Expand All @@ -854,12 +852,11 @@ static fs_status fill_gap(fsfile f, sg_list sg, range blocks, merge m, u64 *edge
return FS_STATUS_OK;
}

static fs_status update_extent_length(fsfile f, extent ex, u64 new_length)
static fs_status update_extent(fsfile f, extent ex, symbol l, u64 val)
{
if (f->md) {
assert(ex->md);
value v = value_from_u64(f->fs->h, new_length);
symbol l = sym(length);
value v = value_from_u64(f->fs->h, val);
fs_status s = filesystem_write_eav(f->fs, ex->md, l, v);
if (s != FS_STATUS_OK)
return s;
Expand All @@ -869,6 +866,24 @@ static fs_status update_extent_length(fsfile f, extent ex, u64 new_length)
set(ex->md, l, v);
f->status |= FSF_DIRTY_DATASYNC;
}
return FS_STATUS_OK;
}

static fs_status update_extent_allocated(fsfile f, extent ex, u64 allocated)
{
fs_status s = update_extent(f, ex, sym(allocated), allocated);
if (s != FS_STATUS_OK)
return s;
tfs_debug(" %s: was 0x%lx, now 0x%lx\n", __func__, ex->allocated, allocated);
ex->allocated = allocated;
return FS_STATUS_OK;
}

static fs_status update_extent_length(fsfile f, extent ex, u64 new_length)
{
fs_status s = update_extent(f, ex, sym(length), new_length);
if (s != FS_STATUS_OK)
return s;

/* TODO cheating; should be reinsert - update rangemap interface? */
tfs_debug(" %s: was %R\n", __func__, ex->node.r);
Expand All @@ -881,6 +896,20 @@ static fs_status extend(fsfile f, extent ex, sg_list sg, range blocks, merge m,
{
u64 free = ex->allocated - range_span(ex->node.r);
range r = irangel(ex->node.r.end, free);
if (blocks.end > r.end) {
filesystem fs = f->fs;
range new = irange(ex->start_block + ex->allocated,
MIN(ex->start_block + blocks.end, fs->size >> fs->blocksize_order));
if (range_span(new) && filesystem_reserve_storage(fs, new)) {
fs_status s = update_extent_allocated(f, ex, ex->allocated + range_span(new));
if (s == FS_STATUS_OK) {
r.end = blocks.end;
free = r.end - ex->node.r.end;
} else {
filesystem_free_storage(fs, new);
}
}
}
range i = range_intersection(r, blocks);
tfs_debug(" %s: node %R, free 0x%lx (%R), i %R\n", __func__, ex->node.r, free, r, i);
if (range_span(i) == 0) {
Expand Down
2 changes: 1 addition & 1 deletion src/tfs/tfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pagecache_node fsfile_get_cachenode(fsfile f);
extern io_status_handler ignore_io_status;

#define MIN_EXTENT_SIZE PAGESIZE
#define MAX_EXTENT_SIZE (1 * MB)
#define MIN_EXTENT_ALLOC_SIZE (1 * MB)

boolean filesystem_probe(u8 *first_sector, u8 *uuid, char *label);
const char *filesystem_get_label(filesystem fs);
Expand Down

0 comments on commit 65434ad

Please sign in to comment.