# HG changeset patch # User Paul Boddie # Date 1653864427 -7200 # Node ID c3b65dd2fb6a1fef00b77ab6e02a833b9d2dd195 # Parent e83d6020739b6d647c8da3a702c378c779b1a53d Added general copy-on-write behaviour for certain kinds of file access. Fixed the flags type inconsistency in the file provider, propagating the opening flags to the file pager for conversion into mapping flags. diff -r e83d6020739b -r c3b65dd2fb6a libfsserver/include/fsserver/file_pager.h --- a/libfsserver/include/fsserver/file_pager.h Sun May 29 00:58:31 2022 +0200 +++ b/libfsserver/include/fsserver/file_pager.h Mon May 30 00:47:07 2022 +0200 @@ -1,7 +1,7 @@ /* * File-specific pager functionality. * - * Copyright (C) 2021 Paul Boddie + * Copyright (C) 2021, 2022 Paul Boddie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -33,6 +33,7 @@ { protected: FileProvider *_provider; + flags_t _flags; /* Notification endpoint for event subscription. */ @@ -42,10 +43,14 @@ bool _resized = false; + /* Helper methods. */ + + bool copy_on_write(); + public: fileid_t fileid; - explicit FilePager(fileid_t fileid, FileProvider *provider, map_flags_t flags); + explicit FilePager(fileid_t fileid, FileProvider *provider, flags_t flags); virtual void close(); diff -r e83d6020739b -r c3b65dd2fb6a libfsserver/include/fsserver/file_provider.h --- a/libfsserver/include/fsserver/file_provider.h Sun May 29 00:58:31 2022 +0200 +++ b/libfsserver/include/fsserver/file_provider.h Mon May 30 00:47:07 2022 +0200 @@ -31,7 +31,6 @@ class FileProvider : public Provider { protected: - map_flags_t _flags; PageMapper *_mapper; public: @@ -42,7 +41,7 @@ virtual PageMapper *mapper(); - virtual long make_resource(map_flags_t flags, offset_t *size, + virtual long make_resource(flags_t flags, offset_t *size, object_flags_t *object_flags, Resource **resource); diff -r e83d6020739b -r c3b65dd2fb6a libfsserver/include/fsserver/pager.h --- a/libfsserver/include/fsserver/pager.h Sun May 29 00:58:31 2022 +0200 +++ b/libfsserver/include/fsserver/pager.h Mon May 30 00:47:07 2022 +0200 @@ -35,16 +35,16 @@ protected: offset_t _start, _size; GenericPageMapper *_mapper, *_mapper_base, *_mapper_masked, *_mapper_copied; - map_flags_t _flags; + map_flags_t _map_flags; public: - explicit Pager(GenericPageMapper *mapper, map_flags_t flags); + explicit Pager(GenericPageMapper *mapper, map_flags_t map_flags); virtual void close(); /* Paging methods. */ - virtual long map(offset_t offset, address_t hot_spot, map_flags_t flags, + virtual long map(offset_t offset, address_t hot_spot, map_flags_t map_flags, l4_snd_fpage_t *region); /* Limit methods. */ diff -r e83d6020739b -r c3b65dd2fb6a libfsserver/lib/files/file_pager.cc --- a/libfsserver/lib/files/file_pager.cc Sun May 29 00:58:31 2022 +0200 +++ b/libfsserver/lib/files/file_pager.cc Mon May 30 00:47:07 2022 +0200 @@ -19,18 +19,22 @@ * Boston, MA 02110-1301, USA */ +#include /* file_region_flags */ +#include + +#include "copied_page_mapper.h" #include "file_pager.h" #include "mapped_file_object_server.h" /* Initialise a pager for a file with a unique file identifier, file provider, - mapping flags and a file registry. The provider offers a shared page mapper + opening flags and a file registry. The provider offers a shared page mapper for moderating access to loaded pages. */ -FilePager::FilePager(fileid_t fileid, FileProvider *provider, map_flags_t flags) -: Pager(provider->mapper(), flags), - _provider(provider), fileid(fileid) +FilePager::FilePager(fileid_t fileid, FileProvider *provider, flags_t flags) +: Pager(provider->mapper(), file_region_flags(flags)), + _provider(provider), _flags(flags), fileid(fileid) { } @@ -96,17 +100,37 @@ { /* Set the limits of the paged region. */ - return Pager::mmap(position, length, start_visible, end_visible, start_pos, - end_pos, size); + long err = Pager::mmap(position, length, start_visible, end_visible, start_pos, + end_pos, size); + + if (err) + return err; + + /* Impose copy-on-write semantics where appropriate. */ + + if ((_mapper != _mapper_copied) && copy_on_write()) + { + _mapper_copied = new CopiedPageMapper(_mapper); + _mapper = _mapper_copied; + } + + return L4_EOK; +} + +/* Return whether the pager should employ copy-on-write semantics. */ + +bool FilePager::copy_on_write() +{ + return (_flags == O_RDONLY) && (_map_flags & L4RE_DS_F_W); } /* Generic pager operations. */ -long FilePager::map(offset_t offset, address_t hot_spot, map_flags_t flags, l4_snd_fpage_t *region) +long FilePager::map(offset_t offset, address_t hot_spot, map_flags_t map_flags, l4_snd_fpage_t *region) { - return Pager::map(offset, hot_spot, flags, region); + return Pager::map(offset, hot_spot, map_flags, region); } diff -r e83d6020739b -r c3b65dd2fb6a libfsserver/lib/files/file_provider.cc --- a/libfsserver/lib/files/file_provider.cc Sun May 29 00:58:31 2022 +0200 +++ b/libfsserver/lib/files/file_provider.cc Mon May 30 00:47:07 2022 +0200 @@ -54,7 +54,7 @@ /* Return a file pager initialised with a provider, page mapper and accessor. */ -long FileProvider::make_resource(map_flags_t flags, offset_t *size, +long FileProvider::make_resource(flags_t flags, offset_t *size, object_flags_t *object_flags, Resource **resource) { diff -r e83d6020739b -r c3b65dd2fb6a libfsserver/lib/generic/pager.cc --- a/libfsserver/lib/generic/pager.cc Sun May 29 00:58:31 2022 +0200 +++ b/libfsserver/lib/generic/pager.cc Mon May 30 00:47:07 2022 +0200 @@ -31,11 +31,11 @@ /* Initialise the pager with a page mapper and the given flags controlling access to a file. */ -Pager::Pager(GenericPageMapper *mapper, map_flags_t flags) +Pager::Pager(GenericPageMapper *mapper, map_flags_t map_flags) : _start(0), _size(0), _mapper(mapper), _mapper_base(mapper), _mapper_masked(NULL), _mapper_copied(NULL), - _flags(flags) + _map_flags(map_flags) { } @@ -113,7 +113,7 @@ /* Map a flexpage corresponding to the dataspace 'offset' involving a 'hot_spot' (flexpage offset). */ -long Pager::map(offset_t offset, address_t hot_spot, map_flags_t flags, +long Pager::map(offset_t offset, address_t hot_spot, map_flags_t map_flags, l4_snd_fpage_t *region) { offset_t file_offset = _start + offset; @@ -123,17 +123,17 @@ NOTE: Permitting executable requests here. This needs to be configured when opening the pager or by another means. */ - if (flags & (~(_flags | L4RE_DS_F_X))) + if (map_flags & (~(_map_flags | L4RE_DS_F_X))) return -L4_EACCESS; /* Obtain a flexpage from the page mapper. */ - Flexpage *flexpage = _mapper->get(file_offset, flags); + Flexpage *flexpage = _mapper->get(file_offset, map_flags); /* Issue the flexpage via the IPC system. */ long err = ipc_prepare_flexpage(flexpage, file_offset, max_offset, - hot_spot, flags, region); + hot_spot, map_flags, region); if (!err) err = complete_Dataspace_map(*region); diff -r e83d6020739b -r c3b65dd2fb6a libfsserver/lib/generic/resource_registry.cc --- a/libfsserver/lib/generic/resource_registry.cc Sun May 29 00:58:31 2022 +0200 +++ b/libfsserver/lib/generic/resource_registry.cc Mon May 30 00:47:07 2022 +0200 @@ -23,7 +23,6 @@ #include "file_pager.h" #include "resource_registry.h" -#include /* file_region_flags */ #include @@ -38,15 +37,6 @@ -/* Convert opening flags to map-compatible paging flags. */ - -map_flags_t ResourceRegistry::get_flags(flags_t flags) -{ - return file_region_flags(flags); -} - - - /* Make a directory provider. */ long ResourceRegistry::make_directory_provider(FileOpening *opening, @@ -168,7 +158,7 @@ /* Make a resource for the provider. */ - return provider->make_resource(get_flags(flags), size, object_flags, resource); + return provider->make_resource(flags, size, object_flags, resource); } /* Request the removal of a filesystem object through any active provider or