# HG changeset patch # User Paul Boddie # Date 1616025595 -3600 # Node ID 0073e2ca6c75cf24c2093d5624deb2da4f63c67b # Parent 108c08c35100d171114ae0260d28ebb531bb8f54 Introduced initial support for resizing files. diff -r 108c08c35100 -r 0073e2ca6c75 dstest_block_client.cc --- a/dstest_block_client.cc Wed Mar 17 00:10:47 2021 +0100 +++ b/dstest_block_client.cc Thu Mar 18 00:59:55 2021 +0100 @@ -33,6 +33,24 @@ +static void show(file_t *file, unsigned long step, unsigned long sample) +{ + /* Allocate a buffer for sampling from the file. */ + + char buf[sample + 1]; + + for (unsigned long offset = 0; offset < file_populated_span(file); offset += step) + { + unsigned long remaining = file_populated_span(file) - offset; + unsigned long sample_remaining = remaining < sample ? remaining : sample; + + printf("%ld bytes from %p...\n", sample_remaining, (file->memory + offset)); + strncpy(buf, (file->memory + offset), sample_remaining); + buf[sample_remaining] = '\0'; + printf("%s\n", buf); + } +} + int main(int argc, char *argv[]) { if (argc < 4) @@ -47,10 +65,6 @@ unsigned long step = atoi(argv[2]); unsigned long sample = atoi(argv[3]); - /* Allocate a buffer for sampling from the file. */ - - char buf[sample + 1]; - /* Obtain access to the filesystem. */ l4_cap_idx_t server = l4re_env_get_cap("server"); @@ -76,16 +90,39 @@ return 1; } + show(&file, step, sample); + + /* Resizing must occur before writing beyond the end of file. Otherwise, the + data may get discarded if the supporting flexpage needs to be flushed. */ + + offset_t new_region = round(file_populated_span(&file), page(1)); + + printf("Resize to %ld...\n", new_region + file_populated_span(&file)); + + err = file_resize(&file, new_region + file_populated_span(&file)); + + if (err) + { + printf("Could not resize file: %s\n", l4sys_errtostr(err)); + return 1; + } + + printf("Resized file...\n"); + + /* Copy the sampled data to another file region. */ + + printf("Copy data to %ld...\n", new_region); + for (unsigned long offset = 0; offset < file_populated_span(&file); offset += step) { - unsigned long remaining = file_populated_span(&file) - offset; - unsigned long sample_remaining = remaining < sample ? remaining : sample; + memcpy(file.memory + new_region + offset, file.memory + offset, sample); + if (step > sample) + memset(file.memory + new_region + offset + sample, 0, step - sample); + } - printf("%ld bytes from %p...\n", sample_remaining, (file.memory + offset)); - strncpy(buf, (file.memory + offset), sample_remaining); - buf[sample_remaining] = '\0'; - printf("%s\n", buf); - } + show(&file, step, sample); + + printf("File shown.\n"); return 0; } diff -r 108c08c35100 -r 0073e2ca6c75 file.cc --- a/file.cc Wed Mar 17 00:10:47 2021 +0100 +++ b/file.cc Thu Mar 18 00:59:55 2021 +0100 @@ -25,6 +25,7 @@ #include #include "dataspace_client.h" +#include "file_client.h" #include "opener_client.h" #include "opener_context_client.h" #include "mapped_file_client.h" @@ -128,6 +129,33 @@ return ipc_attach_dataspace(file->ref, file_span(file), (void **) &file->memory); } +/* Resize a file. */ + +long file_resize(file_t *file, offset_t size) +{ + client_File _file(file->ref); + offset_t file_size = size; + long err = _file.resize(&file_size); + + if (!err) + { + /* Determine the extent of the file in this region. */ + + if (file_size > file->end_pos) + file->data_end = file_span(file); + else + file->data_end = file_size - file->start_pos; + + /* Update the file size locally. */ + + file->size = file_size; + } + + return err; +} + + + /* Return the amount of data in the mapped region for the given file. */ offset_t file_populated_span(file_t *file) diff -r 108c08c35100 -r 0073e2ca6c75 file.h --- a/file.h Wed Mar 17 00:10:47 2021 +0100 +++ b/file.h Thu Mar 18 00:59:55 2021 +0100 @@ -63,9 +63,13 @@ long file_context_open(file_t *file, file_t *context); void file_init(file_t *file); -/* File access region operations. */ +/* File and region operations. */ long file_mmap(file_t *file, offset_t position, offset_t length); +long file_resize(file_t *file, offset_t size); + +/* File and region properties. */ + offset_t file_populated_span(file_t *file); offset_t file_span(file_t *file); diff -r 108c08c35100 -r 0073e2ca6c75 file_pager.cc --- a/file_pager.cc Wed Mar 17 00:10:47 2021 +0100 +++ b/file_pager.cc Thu Mar 18 00:59:55 2021 +0100 @@ -24,6 +24,11 @@ return Pager::flush(populated_size, size); } +long FilePager::resize(offset_t *size) +{ + return Pager::resize(size); +} + long FilePager::mmap(offset_t position, offset_t length, offset_t *start_pos, offset_t *end_pos, offset_t *data_end) { /* Set the limits of the paged region. */ diff -r 108c08c35100 -r 0073e2ca6c75 file_pager.h --- a/file_pager.h Wed Mar 17 00:10:47 2021 +0100 +++ b/file_pager.h Thu Mar 18 00:59:55 2021 +0100 @@ -25,6 +25,8 @@ virtual long flush(offset_t populated_size, offset_t *size); + virtual long resize(offset_t *size); + /* Pager and mapped file methods. */ virtual long map(unsigned long offset, l4_addr_t hot_spot, flags_t flags, l4_snd_fpage_t *region); diff -r 108c08c35100 -r 0073e2ca6c75 files/block_file_accessor.cc --- a/files/block_file_accessor.cc Wed Mar 17 00:10:47 2021 +0100 +++ b/files/block_file_accessor.cc Thu Mar 18 00:59:55 2021 +0100 @@ -45,13 +45,44 @@ fclose(fp); } +/* Update the size of the file. */ + +void BlockFileAccessor::set_size(offset_t size) +{ + void *new_data = realloc(_data, size); + + if (new_data != NULL) + { + _data = (char *) new_data; + + if (size > _size) + memset(_data + _size, 0, size - _size); + + Accessor::set_size(size); + } +} + /* Data transfer methods. */ void BlockFileAccessor::fill(Flexpage *flexpage) { offset_t filepos = flexpage->base_offset; offset_t addr = flexpage->base_addr; - offset_t populated_size = std::min(flexpage->size, _size - filepos); + offset_t populated_size; + + /* Filling completely beyond the end of file should produce an empty + flexpage. This could potentially be a shared read-only flexpage that + would be replaced by an independent writable flexpage if ever written. */ + + if (filepos > _size) + { + memset((void *) addr, 0, flexpage->size); + return; + } + + /* Otherwise, fill the populated portion of a flexpage. */ + + populated_size = std::min(flexpage->size, _size - filepos); /* Tag the region with file state. */ @@ -71,7 +102,17 @@ { offset_t addr = flexpage->base_addr; offset_t filepos = flexpage->base_offset; - offset_t populated_size = std::min(flexpage->size, _size - filepos); + offset_t populated_size; + + /* Flushing completely beyond the end of file should discard the + flexpage. */ + + if (filepos > _size) + return; + + /* Otherwise, only the populated portion of a flexpage should be flushed. */ + + populated_size = std::min(flexpage->size, _size - filepos); /* Remove the file state tag from the region. */ diff -r 108c08c35100 -r 0073e2ca6c75 files/block_file_accessor.h --- a/files/block_file_accessor.h Wed Mar 17 00:10:47 2021 +0100 +++ b/files/block_file_accessor.h Thu Mar 18 00:59:55 2021 +0100 @@ -13,6 +13,8 @@ public: explicit BlockFileAccessor(const char *path, fileid_t fileid); + virtual void set_size(offset_t size); + /* Data transfer methods. */ virtual void fill(Flexpage *flexpage); diff -r 108c08c35100 -r 0073e2ca6c75 pager.cc --- a/pager.cc Wed Mar 17 00:10:47 2021 +0100 +++ b/pager.cc Thu Mar 18 00:59:55 2021 +0100 @@ -19,19 +19,19 @@ long Pager::flush(offset_t populated_size, offset_t *size) { - offset_t limit = _start + populated_size; - offset_t file_size = _mapper->get_data_size(); + _mapper->flush_all(_start, populated_size); - /* Extend the file if the populated size of the region goes beyond the - current size. */ + *size = _mapper->get_data_size(); + return L4_EOK; +} - if (limit > file_size) - { - file_size = limit; - _mapper->set_data_size(file_size); - } +/* Resize the underlying file. */ - *size = file_size; +long Pager::resize(offset_t *size) +{ + _mapper->set_data_size(*size); + + *size = _mapper->get_data_size(); return L4_EOK; } diff -r 108c08c35100 -r 0073e2ca6c75 pager.h --- a/pager.h Wed Mar 17 00:10:47 2021 +0100 +++ b/pager.h Thu Mar 18 00:59:55 2021 +0100 @@ -33,6 +33,8 @@ virtual long flush(offset_t populated_size, offset_t *size); + virtual long resize(offset_t *size); + /* Mapped file methods. */ virtual long mmap(offset_t position, offset_t length, offset_t *start_pos, offset_t *end_pos, offset_t *data_end);