1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libfsserver/include/fsserver/copied_page_mapper.h Sat May 28 00:59:04 2022 +0200 1.3 @@ -0,0 +1,78 @@ 1.4 +/* 1.5 + * A page mapper providing copied memory pages or deferring to another page 1.6 + * mapper to satisfy file accesses. 1.7 + * 1.8 + * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk> 1.9 + * 1.10 + * This program is free software; you can redistribute it and/or 1.11 + * modify it under the terms of the GNU General Public License as 1.12 + * published by the Free Software Foundation; either version 2 of 1.13 + * the License, or (at your option) any later version. 1.14 + * 1.15 + * This program is distributed in the hope that it will be useful, 1.16 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 1.17 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1.18 + * GNU General Public License for more details. 1.19 + * 1.20 + * You should have received a copy of the GNU General Public License 1.21 + * along with this program; if not, write to the Free Software 1.22 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, 1.23 + * Boston, MA 02110-1301, USA 1.24 + */ 1.25 + 1.26 +#pragma once 1.27 + 1.28 +#include <fsserver/access_map.h> 1.29 +#include <fsserver/generic_page_mapper.h> 1.30 +#include <mem/memory_incremental.h> 1.31 + 1.32 + 1.33 + 1.34 +/* A special flexpage class for copied flexpages. */ 1.35 + 1.36 +class CopiedFlexpage : public Flexpage 1.37 +{ 1.38 +public: 1.39 + explicit CopiedFlexpage(Region *region = NULL); 1.40 +}; 1.41 + 1.42 + 1.43 + 1.44 +/* A file mapper, associating flexpages with file regions. */ 1.45 + 1.46 +class CopiedPageMapper : public GenericPageMapper 1.47 +{ 1.48 +protected: 1.49 + GenericPageMapper *_mapper; 1.50 + offset_t _size; 1.51 + 1.52 + /* Copied page support. */ 1.53 + 1.54 + AccessMap _map; 1.55 + MemoryIncremental _memory; 1.56 + 1.57 + /* Internal flexpage retrieval methods. */ 1.58 + 1.59 + Flexpage *find(offset_t offset); 1.60 + 1.61 + Flexpage *replicate_flexpage(offset_t offset, Flexpage *flexpage); 1.62 + 1.63 +public: 1.64 + explicit CopiedPageMapper(GenericPageMapper *mapper); 1.65 + 1.66 + virtual ~CopiedPageMapper(); 1.67 + 1.68 + /* Interface for the pager, implementing GenericPageMapper. */ 1.69 + 1.70 + Flexpage *get(offset_t offset, map_flags_t flags); 1.71 + 1.72 + void queue(Flexpage *flexpage); 1.73 + 1.74 + void flush_all(offset_t start, offset_t size); 1.75 + 1.76 + offset_t get_data_size(); 1.77 + 1.78 + void set_data_size(offset_t size); 1.79 +}; 1.80 + 1.81 +// vim: tabstop=4 expandtab shiftwidth=4
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/libfsserver/include/fsserver/generic_page_mapper.h Sat May 28 00:59:04 2022 +0200 2.3 @@ -0,0 +1,47 @@ 2.4 +/* 2.5 + * A generic page mapper providing memory pages to satisfy file accesses. 2.6 + * 2.7 + * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk> 2.8 + * 2.9 + * This program is free software; you can redistribute it and/or 2.10 + * modify it under the terms of the GNU General Public License as 2.11 + * published by the Free Software Foundation; either version 2 of 2.12 + * the License, or (at your option) any later version. 2.13 + * 2.14 + * This program is distributed in the hope that it will be useful, 2.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 2.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 2.17 + * GNU General Public License for more details. 2.18 + * 2.19 + * You should have received a copy of the GNU General Public License 2.20 + * along with this program; if not, write to the Free Software 2.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, 2.22 + * Boston, MA 02110-1301, USA 2.23 + */ 2.24 + 2.25 +#pragma once 2.26 + 2.27 +#include <mem/flexpage.h> 2.28 + 2.29 + 2.30 + 2.31 +/* A generic file mapper interface, accessed by the pager, associating flexpages 2.32 + with file regions. */ 2.33 + 2.34 +class GenericPageMapper 2.35 +{ 2.36 +public: 2.37 + virtual ~GenericPageMapper(); 2.38 + 2.39 + virtual Flexpage *get(offset_t offset, map_flags_t flags); 2.40 + 2.41 + virtual void queue(Flexpage *flexpage); 2.42 + 2.43 + virtual void flush_all(offset_t start, offset_t size); 2.44 + 2.45 + virtual offset_t get_data_size(); 2.46 + 2.47 + virtual void set_data_size(offset_t size); 2.48 +}; 2.49 + 2.50 +// vim: tabstop=4 expandtab shiftwidth=4
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/libfsserver/include/fsserver/masked_page_mapper.h Sat May 28 00:59:04 2022 +0200 3.3 @@ -0,0 +1,82 @@ 3.4 +/* 3.5 + * A page mapper providing memory pages to satisfy file accesses, masking the 3.6 + * limits of a visible region of the file's contents. 3.7 + * 3.8 + * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk> 3.9 + * 3.10 + * This program is free software; you can redistribute it and/or 3.11 + * modify it under the terms of the GNU General Public License as 3.12 + * published by the Free Software Foundation; either version 2 of 3.13 + * the License, or (at your option) any later version. 3.14 + * 3.15 + * This program is distributed in the hope that it will be useful, 3.16 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 3.17 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 3.18 + * GNU General Public License for more details. 3.19 + * 3.20 + * You should have received a copy of the GNU General Public License 3.21 + * along with this program; if not, write to the Free Software 3.22 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, 3.23 + * Boston, MA 02110-1301, USA 3.24 + */ 3.25 + 3.26 +#pragma once 3.27 + 3.28 +#include <fsserver/generic_page_mapper.h> 3.29 +#include <mem/memory_incremental.h> 3.30 + 3.31 + 3.32 + 3.33 +/* A special flexpage class for masked flexpages. */ 3.34 + 3.35 +class MaskedFlexpage : public Flexpage 3.36 +{ 3.37 +public: 3.38 + explicit MaskedFlexpage(Region *region = NULL); 3.39 +}; 3.40 + 3.41 + 3.42 + 3.43 +/* A file mapper, associating flexpages with file regions. */ 3.44 + 3.45 +class MaskedPageMapper : public GenericPageMapper 3.46 +{ 3.47 +protected: 3.48 + GenericPageMapper *_mapper; 3.49 + offset_t _size; 3.50 + 3.51 + /* Masked region support. */ 3.52 + 3.53 + MemoryIncremental _memory; 3.54 + offset_t _start_visible, _end_visible; 3.55 + MaskedFlexpage _start_flexpage, _end_flexpage, _zero_flexpage; 3.56 + 3.57 + /* Internal flexpage retrieval methods. */ 3.58 + 3.59 + Flexpage *get_masked_flexpage(Flexpage *flexpage); 3.60 + 3.61 + void allocate_region(Flexpage *flexpage, Flexpage &masked); 3.62 + 3.63 + void populate_region(Flexpage *flexpage, Flexpage &masked, 3.64 + bool has_start, bool has_end); 3.65 + 3.66 +public: 3.67 + explicit MaskedPageMapper(GenericPageMapper *mapper, offset_t start_visible, 3.68 + offset_t end_visible); 3.69 + 3.70 + virtual ~MaskedPageMapper(); 3.71 + 3.72 + /* Interface for the pager, implementing GenericPageMapper. */ 3.73 + 3.74 + Flexpage *get(offset_t offset, map_flags_t flags); 3.75 + 3.76 + void queue(Flexpage *flexpage); 3.77 + 3.78 + void flush_all(offset_t start, offset_t size); 3.79 + 3.80 + offset_t get_data_size(); 3.81 + 3.82 + void set_data_size(offset_t size); 3.83 +}; 3.84 + 3.85 +// vim: tabstop=4 expandtab shiftwidth=4
4.1 --- a/libfsserver/include/fsserver/page_mapper.h Fri May 27 00:38:27 2022 +0200 4.2 +++ b/libfsserver/include/fsserver/page_mapper.h Sat May 28 00:59:04 2022 +0200 4.3 @@ -1,7 +1,7 @@ 4.4 /* 4.5 * A page mapper providing memory pages to satisfy file accesses. 4.6 * 4.7 - * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk> 4.8 + * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk> 4.9 * 4.10 * This program is free software; you can redistribute it and/or 4.11 * modify it under the terms of the GNU General Public License as 4.12 @@ -23,6 +23,7 @@ 4.13 4.14 #include <fsserver/access_map.h> 4.15 #include <fsserver/accessor.h> 4.16 +#include <fsserver/generic_page_mapper.h> 4.17 #include <fsserver/page_owner.h> 4.18 4.19 #include <mutex> 4.20 @@ -31,7 +32,7 @@ 4.21 4.22 /* A file mapper, associating flexpages with file regions. */ 4.23 4.24 -class PageMapper : public PageOwner 4.25 +class PageMapper : public GenericPageMapper, public PageOwner 4.26 { 4.27 protected: 4.28 AccessMap _map; 4.29 @@ -56,7 +57,7 @@ 4.30 Accessor *accessor() 4.31 { return _accessor; } 4.32 4.33 - /* Interface for the pager. */ 4.34 + /* Interface for the pager, implementing GenericPageMapper. */ 4.35 4.36 Flexpage *get(offset_t offset, map_flags_t flags); 4.37
5.1 --- a/libfsserver/include/fsserver/pager.h Fri May 27 00:38:27 2022 +0200 5.2 +++ b/libfsserver/include/fsserver/pager.h Sat May 28 00:59:04 2022 +0200 5.3 @@ -23,9 +23,8 @@ 5.4 5.5 #include <systypes/base.h> 5.6 5.7 -#include <fsserver/page_mapper.h> 5.8 +#include <fsserver/generic_page_mapper.h> 5.9 #include <fsserver/resource.h> 5.10 -#include <mem/memory_incremental.h> 5.11 5.12 5.13 5.14 @@ -35,33 +34,11 @@ 5.15 { 5.16 protected: 5.17 offset_t _start, _size; 5.18 - PageMapper *_mapper; 5.19 + GenericPageMapper *_mapper, *_mapper_base, *_mapper_masked, *_mapper_copied; 5.20 map_flags_t _flags; 5.21 5.22 - /* Support for masked regions and replicated flexpages. */ 5.23 - 5.24 - MemoryIncremental _memory; 5.25 - 5.26 - /* Masked region support. */ 5.27 - 5.28 - bool _is_masked; 5.29 - offset_t _start_visible, _end_visible; 5.30 - Flexpage _start_flexpage, _end_flexpage, _zero_flexpage; 5.31 - 5.32 - Flexpage *get_masked_flexpage(Flexpage *flexpage); 5.33 - 5.34 - void allocate_region(Flexpage *flexpage, Flexpage &masked); 5.35 - 5.36 - void populate_region(Flexpage *flexpage, Flexpage &masked, 5.37 - bool has_start, bool has_end); 5.38 - 5.39 - /* Replicated flexpage support. */ 5.40 - 5.41 - AccessMap _map; 5.42 - Flexpage *get_replicated_flexpage(Flexpage *flexpage, map_flags_t flags); 5.43 - 5.44 public: 5.45 - explicit Pager(PageMapper *mapper, map_flags_t flags); 5.46 + explicit Pager(GenericPageMapper *mapper, map_flags_t flags); 5.47 5.48 virtual void close(); 5.49
6.1 --- a/libfsserver/lib/Makefile Fri May 27 00:38:27 2022 +0200 6.2 +++ b/libfsserver/lib/Makefile Sat May 28 00:59:04 2022 +0200 6.3 @@ -76,7 +76,10 @@ 6.4 generic/resource_server.cc \ 6.5 generic/simple_pager.cc \ 6.6 mapping/access_map.cc \ 6.7 + mapping/copied_page_mapper.cc \ 6.8 + mapping/generic_page_mapper.cc \ 6.9 mapping/ipc.cc \ 6.10 + mapping/masked_page_mapper.cc \ 6.11 mapping/page_mapper.cc \ 6.12 pages/page_queue.cc \ 6.13 pages/page_queue_partitioned.cc \
7.1 --- a/libfsserver/lib/generic/pager.cc Fri May 27 00:38:27 2022 +0200 7.2 +++ b/libfsserver/lib/generic/pager.cc Sat May 28 00:59:04 2022 +0200 7.3 @@ -23,16 +23,19 @@ 7.4 #include "ipc.h" 7.5 #include "pager.h" 7.6 7.7 -#include <string.h> 7.8 +#include "copied_page_mapper.h" 7.9 +#include "masked_page_mapper.h" 7.10 7.11 7.12 7.13 /* Initialise the pager with a page mapper and the given flags controlling 7.14 access to a file. */ 7.15 7.16 -Pager::Pager(PageMapper *mapper, map_flags_t flags) 7.17 -: _start(0), _size(0), _mapper(mapper), _flags(flags), 7.18 - _is_masked(false), _start_visible(0), _end_visible(0) 7.19 +Pager::Pager(GenericPageMapper *mapper, map_flags_t flags) 7.20 +: _start(0), _size(0), 7.21 + _mapper(mapper), _mapper_base(mapper), _mapper_masked(NULL), 7.22 + _mapper_copied(NULL), 7.23 + _flags(flags) 7.24 { 7.25 } 7.26 7.27 @@ -40,7 +43,17 @@ 7.28 7.29 void Pager::close() 7.30 { 7.31 - /* NOTE: Need to deallocate any allocated regions and flexpages. */ 7.32 + if (_mapper_masked != NULL) 7.33 + { 7.34 + delete _mapper_masked; 7.35 + _mapper_masked = NULL; 7.36 + } 7.37 + 7.38 + if (_mapper_copied != NULL) 7.39 + { 7.40 + delete _mapper_copied; 7.41 + _mapper_copied = NULL; 7.42 + } 7.43 } 7.44 7.45 /* Flush data to the file. */ 7.46 @@ -78,18 +91,21 @@ 7.47 7.48 *start_pos = _start; 7.49 *end_pos = _start + _size; 7.50 - *size = _mapper->get_data_size(); 7.51 + *size = _mapper_base->get_data_size(); 7.52 7.53 /* Permit masking of mapped regions. */ 7.54 7.55 - if (start_visible || end_visible) 7.56 + if ((start_visible || end_visible) && 7.57 + ((*start_pos != start_visible) || (*end_pos != end_visible))) 7.58 { 7.59 - _start_visible = start_visible; 7.60 - _end_visible = end_visible; 7.61 - _is_masked = (*start_pos != _start_visible) || (*end_pos != _end_visible); 7.62 + /* Introduce the masked page and copied page mappers. */ 7.63 + 7.64 + _mapper_masked = new MaskedPageMapper(_mapper_base, start_visible, end_visible); 7.65 + _mapper_copied = new CopiedPageMapper(_mapper_masked); 7.66 + _mapper = _mapper_copied; 7.67 } 7.68 else 7.69 - _is_masked = false; 7.70 + _mapper = _mapper_base; 7.71 7.72 return L4_EOK; 7.73 } 7.74 @@ -110,43 +126,22 @@ 7.75 if (flags & (~(_flags | L4RE_DS_F_X))) 7.76 return -L4_EACCESS; 7.77 7.78 - Flexpage *issued_flexpage = NULL, *obtained_flexpage = NULL; 7.79 - 7.80 - /* Obtain any replicated flexpage. 7.81 - NOTE: An additional condition should be introduced to test for the 7.82 - relevance of replicated flexpages. */ 7.83 - 7.84 - if (flags & L4RE_DS_F_W) 7.85 - issued_flexpage = _map.find(file_offset); 7.86 - 7.87 - /* Without any replicated flexpage, obtain one for the shared, underlying 7.88 - file data. */ 7.89 + /* Obtain a flexpage from the page mapper. */ 7.90 7.91 - if (issued_flexpage == NULL) 7.92 - { 7.93 - obtained_flexpage = _mapper->get(file_offset, flags); 7.94 - 7.95 - /* Determine if the flexpage should be masked. */ 7.96 - 7.97 - issued_flexpage = get_masked_flexpage(obtained_flexpage); 7.98 - 7.99 - /* Determine if the flexpage should be replicated. */ 7.100 - 7.101 - issued_flexpage = get_replicated_flexpage(issued_flexpage, flags); 7.102 - } 7.103 + Flexpage *flexpage = _mapper->get(file_offset, flags); 7.104 7.105 /* Issue the flexpage via the IPC system. */ 7.106 7.107 - long err = ipc_prepare_flexpage(issued_flexpage, file_offset, max_offset, 7.108 + long err = ipc_prepare_flexpage(flexpage, file_offset, max_offset, 7.109 hot_spot, flags, region); 7.110 7.111 if (!err) 7.112 err = complete_Dataspace_map(*region); 7.113 7.114 - /* After the obtained flexpage is issued, it is queued for future reuse. */ 7.115 + /* After the obtained flexpage is issued, it is queued for future reuse, if 7.116 + appropriate for the mapper concerned. */ 7.117 7.118 - if (obtained_flexpage != NULL) 7.119 - _mapper->queue(obtained_flexpage); 7.120 + _mapper->queue(flexpage); 7.121 7.122 if (err) 7.123 return err; 7.124 @@ -161,116 +156,4 @@ 7.125 return _mapper->get_data_size(); 7.126 } 7.127 7.128 -/* Detect flexpages with masked content, introducing separate flexpages 7.129 - offering masked content from the same region. */ 7.130 - 7.131 -Flexpage *Pager::get_masked_flexpage(Flexpage *flexpage) 7.132 -{ 7.133 - /* If not masking content, return the original flexpage. */ 7.134 - 7.135 - if (!_is_masked) 7.136 - return flexpage; 7.137 - 7.138 - /* Determine whether the flexpage involves the limits of the visible 7.139 - region or is beyond such limits. */ 7.140 - 7.141 - bool has_start = flexpage->supports_position(_start_visible) && 7.142 - flexpage->base_offset != _start_visible; 7.143 - bool has_end = flexpage->supports_position(_end_visible); 7.144 - bool has_zero = (flexpage->base_offset >= _end_visible) || 7.145 - (flexpage->base_offset + flexpage->size < _start_visible); 7.146 - 7.147 - /* Return the original flexpage within the visible limits. */ 7.148 - 7.149 - if (!has_start && !has_end && !has_zero) 7.150 - return flexpage; 7.151 - 7.152 - /* Allocate and populate a region in one of the preallocated flexpages for 7.153 - masked content. */ 7.154 - 7.155 - Flexpage &masked = has_start ? _start_flexpage : 7.156 - has_end ? _end_flexpage : 7.157 - _zero_flexpage; 7.158 - 7.159 - allocate_region(flexpage, masked); 7.160 - populate_region(flexpage, masked, has_start, has_end); 7.161 - 7.162 - /* Associate the preallocated flexpage with the original flexpage. */ 7.163 - 7.164 - flexpage->associate(&masked); 7.165 - 7.166 - return &masked; 7.167 -} 7.168 - 7.169 -void Pager::allocate_region(Flexpage *flexpage, Flexpage &masked) 7.170 -{ 7.171 - offset_t needed = flexpage->region->size(); 7.172 - 7.173 - /* Attempt to re-use an existing region. */ 7.174 - 7.175 - if (masked.region != NULL) 7.176 - { 7.177 - if (masked.region->size() == needed) 7.178 - return; 7.179 - else 7.180 - _memory.release(masked.region); 7.181 - } 7.182 - 7.183 - /* Set the region in the flexpage. */ 7.184 - 7.185 - masked.set_region(_memory.region(needed)); 7.186 - masked.reset(flexpage->base_offset); 7.187 -} 7.188 - 7.189 -void Pager::populate_region(Flexpage *flexpage, Flexpage &masked, 7.190 - bool has_start, bool has_end) 7.191 -{ 7.192 - /* Without any limits involved, provide a zero flexpage. */ 7.193 - 7.194 - if (!has_start && !has_end) 7.195 - { 7.196 - memset((void *) masked.region->start, 0, masked.size); 7.197 - return; 7.198 - } 7.199 - 7.200 - /* Determine the content limits given start and/or end offsets. */ 7.201 - 7.202 - offset_t start_offset = has_start ? _start_visible - masked.base_offset : 0; 7.203 - offset_t end_offset = has_end ? _end_visible - masked.base_offset : masked.size; 7.204 - 7.205 - if (has_start) 7.206 - memset((void *) masked.region->start, 0, start_offset); 7.207 - 7.208 - memcpy((void *) (masked.region->start + start_offset), 7.209 - (const void *) (flexpage->region->start + start_offset), 7.210 - end_offset - start_offset); 7.211 - 7.212 - if (has_end) 7.213 - memset((void *) (masked.region->start + end_offset), 0, masked.size - end_offset); 7.214 -} 7.215 - 7.216 -/* Detect flexpages with replicated content, introducing separate flexpages 7.217 - offering replicated content from the same region. */ 7.218 - 7.219 -Flexpage *Pager::get_replicated_flexpage(Flexpage *flexpage, map_flags_t flags) 7.220 -{ 7.221 - /* NOTE: An additional condition should be introduced to test for the 7.222 - relevance of replicated flexpages. For now, detect copy-on-write 7.223 - situations. */ 7.224 - 7.225 - if (_is_masked && (flags & L4RE_DS_F_W)) 7.226 - { 7.227 - Region *region = _memory.region(flexpage->size); 7.228 - Flexpage *replicated = new Flexpage(region); 7.229 - 7.230 - replicated->reset(flexpage->base_offset); 7.231 - 7.232 - memcpy((void *) region->start, (const void *) flexpage->region->start, flexpage->size); 7.233 - _map.insert(replicated); 7.234 - return replicated; 7.235 - } 7.236 - else 7.237 - return flexpage; 7.238 -} 7.239 - 7.240 // vim: tabstop=4 expandtab shiftwidth=4
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/libfsserver/lib/mapping/copied_page_mapper.cc Sat May 28 00:59:04 2022 +0200 8.3 @@ -0,0 +1,154 @@ 8.4 +/* 8.5 + * A page mapper providing copied memory pages or deferring to another page 8.6 + * mapper to satisfy file accesses. 8.7 + * 8.8 + * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk> 8.9 + * 8.10 + * This program is free software; you can redistribute it and/or 8.11 + * modify it under the terms of the GNU General Public License as 8.12 + * published by the Free Software Foundation; either version 2 of 8.13 + * the License, or (at your option) any later version. 8.14 + * 8.15 + * This program is distributed in the hope that it will be useful, 8.16 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 8.17 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 8.18 + * GNU General Public License for more details. 8.19 + * 8.20 + * You should have received a copy of the GNU General Public License 8.21 + * along with this program; if not, write to the Free Software 8.22 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, 8.23 + * Boston, MA 02110-1301, USA 8.24 + */ 8.25 + 8.26 +#include <l4/re/c/dataspace.h> 8.27 + 8.28 +#include <string.h> 8.29 + 8.30 +#include "copied_page_mapper.h" 8.31 + 8.32 + 8.33 + 8.34 +/* Provide mapped pages populated with the given 'mapper', with pages obtained 8.35 + from the given 'pages' collection. */ 8.36 + 8.37 +CopiedPageMapper::CopiedPageMapper(GenericPageMapper *mapper) 8.38 +: _mapper(mapper) 8.39 +{ 8.40 + _size = _mapper->get_data_size(); 8.41 +} 8.42 + 8.43 +/* Upon deallocation, purge active pages. */ 8.44 + 8.45 +CopiedPageMapper::~CopiedPageMapper() 8.46 +{ 8.47 +} 8.48 + 8.49 +/* Interface for the pager. */ 8.50 + 8.51 +/* Return a flexpage providing access to the indicated file 'offset'. 8.52 + 8.53 + The returned flexpage will either provide direct access to the underlying 8.54 + file content or be a completely new flexpage modified through writes to 8.55 + memory. */ 8.56 + 8.57 +Flexpage *CopiedPageMapper::get(offset_t offset, map_flags_t flags) 8.58 +{ 8.59 + Flexpage *f = find(offset); 8.60 + 8.61 + /* Defer to the underlying page mapper if no flexpage was found. */ 8.62 + 8.63 + if (f == NULL) 8.64 + { 8.65 + f = _mapper->get(offset, flags); 8.66 + 8.67 + /* Replicate the underlying flexpage if writing. */ 8.68 + 8.69 + if (flags & L4RE_DS_F_W) 8.70 + { 8.71 + Flexpage *rf = replicate_flexpage(offset, f); 8.72 + _mapper->queue(f); 8.73 + f = rf; 8.74 + } 8.75 + } 8.76 + 8.77 + /* Upgrade the access flags. */ 8.78 + 8.79 + f->upgrade(flags); 8.80 + return f; 8.81 +} 8.82 + 8.83 +/* Queue the given 'flexpage'. */ 8.84 + 8.85 +void CopiedPageMapper::queue(Flexpage *flexpage) 8.86 +{ 8.87 + if (dynamic_cast<CopiedFlexpage *>(flexpage) == NULL) 8.88 + _mapper->queue(flexpage); 8.89 +} 8.90 + 8.91 +/* Flush pages in the given range from 'start' with 'size'. */ 8.92 + 8.93 +void CopiedPageMapper::flush_all(offset_t start, offset_t size) 8.94 +{ 8.95 + /* NOTE: This might be superfluous since copy-on-write regions should not 8.96 + update content. */ 8.97 + 8.98 + _mapper->flush_all(start, size); 8.99 +} 8.100 + 8.101 +/* Return the maximum extent of the mapped resource. */ 8.102 + 8.103 +offset_t CopiedPageMapper::get_data_size() 8.104 +{ 8.105 + return _size; 8.106 +} 8.107 + 8.108 +/* Set the maximum extent of the mapped resource. */ 8.109 + 8.110 +void CopiedPageMapper::set_data_size(offset_t size) 8.111 +{ 8.112 + _size = size; 8.113 +} 8.114 + 8.115 +/* Internal flexpage retrieval methods. */ 8.116 + 8.117 +/* Find an existing flexpage for 'offset'. */ 8.118 + 8.119 +Flexpage *CopiedPageMapper::find(offset_t offset) 8.120 +{ 8.121 + return _map.find(offset); 8.122 +} 8.123 + 8.124 +/* Replicate an underlying flexpage for the file 'offset' using the given 8.125 + 'flexpage'. */ 8.126 + 8.127 +Flexpage *CopiedPageMapper::replicate_flexpage(offset_t offset, Flexpage *flexpage) 8.128 +{ 8.129 + /* Obtain a new memory region and a new flexpage. */ 8.130 + 8.131 + Region *region = _memory.region(flexpage->size); 8.132 + Flexpage *replicated = new CopiedFlexpage(region); 8.133 + 8.134 + /* Configure the flexpage for the file region. */ 8.135 + 8.136 + replicated->reset(offset); 8.137 + 8.138 + /* Copy the contents of the underlying flexpage. */ 8.139 + 8.140 + memcpy((void *) region->start, (const void *) flexpage->region->start, flexpage->size); 8.141 + 8.142 + /* Register the flexpage for future accesses. */ 8.143 + 8.144 + _map.insert(replicated); 8.145 + return replicated; 8.146 +} 8.147 + 8.148 + 8.149 + 8.150 +/* Copied flexpage constructor. */ 8.151 + 8.152 +CopiedFlexpage::CopiedFlexpage(Region *region) 8.153 +: Flexpage(region) 8.154 +{ 8.155 +} 8.156 + 8.157 +// vim: tabstop=4 expandtab shiftwidth=4
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 9.2 +++ b/libfsserver/lib/mapping/generic_page_mapper.cc Sat May 28 00:59:04 2022 +0200 9.3 @@ -0,0 +1,30 @@ 9.4 +/* 9.5 + * A generic page mapper providing memory pages to satisfy file accesses. 9.6 + * 9.7 + * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk> 9.8 + * 9.9 + * This program is free software; you can redistribute it and/or 9.10 + * modify it under the terms of the GNU General Public License as 9.11 + * published by the Free Software Foundation; either version 2 of 9.12 + * the License, or (at your option) any later version. 9.13 + * 9.14 + * This program is distributed in the hope that it will be useful, 9.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 9.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9.17 + * GNU General Public License for more details. 9.18 + * 9.19 + * You should have received a copy of the GNU General Public License 9.20 + * along with this program; if not, write to the Free Software 9.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, 9.22 + * Boston, MA 02110-1301, USA 9.23 + */ 9.24 + 9.25 +#include "generic_page_mapper.h" 9.26 + 9.27 + 9.28 + 9.29 +GenericPageMapper::~GenericPageMapper() 9.30 +{ 9.31 +} 9.32 + 9.33 +// vim: tabstop=4 expandtab shiftwidth=4
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 10.2 +++ b/libfsserver/lib/mapping/masked_page_mapper.cc Sat May 28 00:59:04 2022 +0200 10.3 @@ -0,0 +1,195 @@ 10.4 +/* 10.5 + * A page mapper providing memory pages to satisfy file accesses, masking the 10.6 + * limits of a visible region of the file's contents. 10.7 + * 10.8 + * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk> 10.9 + * 10.10 + * This program is free software; you can redistribute it and/or 10.11 + * modify it under the terms of the GNU General Public License as 10.12 + * published by the Free Software Foundation; either version 2 of 10.13 + * the License, or (at your option) any later version. 10.14 + * 10.15 + * This program is distributed in the hope that it will be useful, 10.16 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 10.17 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10.18 + * GNU General Public License for more details. 10.19 + * 10.20 + * You should have received a copy of the GNU General Public License 10.21 + * along with this program; if not, write to the Free Software 10.22 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, 10.23 + * Boston, MA 02110-1301, USA 10.24 + */ 10.25 + 10.26 +#include <string.h> 10.27 + 10.28 +#include "masked_page_mapper.h" 10.29 + 10.30 + 10.31 + 10.32 +/* Provide mapped pages populated using the given 'mapper', with a visible 10.33 + region defined that causes the limits of this region to be masked. */ 10.34 + 10.35 +MaskedPageMapper::MaskedPageMapper(GenericPageMapper *mapper, 10.36 + offset_t start_visible, offset_t end_visible) 10.37 +: _mapper(mapper), _start_visible(start_visible), _end_visible(end_visible) 10.38 +{ 10.39 + _size = _mapper->get_data_size(); 10.40 +} 10.41 + 10.42 +MaskedPageMapper::~MaskedPageMapper() 10.43 +{ 10.44 + if (_start_flexpage.region != NULL) 10.45 + _memory.release(_start_flexpage.region); 10.46 + 10.47 + if (_end_flexpage.region != NULL) 10.48 + _memory.release(_end_flexpage.region); 10.49 + 10.50 + if (_zero_flexpage.region != NULL) 10.51 + _memory.release(_zero_flexpage.region); 10.52 +} 10.53 + 10.54 +/* Interface for the pager. */ 10.55 + 10.56 +/* Return a flexpage providing access to the indicated file 'offset'. 10.57 + 10.58 + The returned flexpage will either provide direct access to the underlying 10.59 + file content or be a completely new flexpage containing masked content. */ 10.60 + 10.61 +Flexpage *MaskedPageMapper::get(offset_t offset, map_flags_t flags) 10.62 +{ 10.63 + Flexpage *f = _mapper->get(offset, flags); 10.64 + Flexpage *mf = get_masked_flexpage(f); 10.65 + 10.66 + if (f != mf) 10.67 + _mapper->queue(f); 10.68 + 10.69 + return mf; 10.70 +} 10.71 + 10.72 +/* Queue the given 'flexpage'. */ 10.73 + 10.74 +void MaskedPageMapper::queue(Flexpage *flexpage) 10.75 +{ 10.76 + if (dynamic_cast<MaskedFlexpage *>(flexpage) == NULL) 10.77 + _mapper->queue(flexpage); 10.78 +} 10.79 + 10.80 +/* Flush pages in the given range from 'start' with 'size'. */ 10.81 + 10.82 +void MaskedPageMapper::flush_all(offset_t start, offset_t size) 10.83 +{ 10.84 + /* NOTE: This might be superfluous since masked regions probably should be 10.85 + read-only or copy-on-write. */ 10.86 + 10.87 + _mapper->flush_all(start, size); 10.88 +} 10.89 + 10.90 +/* Return the maximum extent of the mapped resource. */ 10.91 + 10.92 +offset_t MaskedPageMapper::get_data_size() 10.93 +{ 10.94 + return _size; 10.95 +} 10.96 + 10.97 +/* Set the maximum extent of the mapped resource. */ 10.98 + 10.99 +void MaskedPageMapper::set_data_size(offset_t size) 10.100 +{ 10.101 + _size = size; 10.102 +} 10.103 + 10.104 +/* Internal flexpage retrieval methods. */ 10.105 + 10.106 +/* Detect flexpages with masked content, introducing separate flexpages 10.107 + offering masked content from the same region. */ 10.108 + 10.109 +Flexpage *MaskedPageMapper::get_masked_flexpage(Flexpage *flexpage) 10.110 +{ 10.111 + /* Determine whether the flexpage involves the limits of the visible 10.112 + region or is beyond such limits. */ 10.113 + 10.114 + bool has_start = flexpage->supports_position(_start_visible) && 10.115 + flexpage->base_offset != _start_visible; 10.116 + bool has_end = flexpage->supports_position(_end_visible); 10.117 + bool has_zero = (flexpage->base_offset >= _end_visible) || 10.118 + (flexpage->base_offset + flexpage->size < _start_visible); 10.119 + 10.120 + /* Return the original flexpage within the visible limits. */ 10.121 + 10.122 + if (!has_start && !has_end && !has_zero) 10.123 + return flexpage; 10.124 + 10.125 + /* Allocate and populate a region in one of the preallocated flexpages for 10.126 + masked content. */ 10.127 + 10.128 + Flexpage &masked = has_start ? _start_flexpage : 10.129 + has_end ? _end_flexpage : 10.130 + _zero_flexpage; 10.131 + 10.132 + allocate_region(flexpage, masked); 10.133 + populate_region(flexpage, masked, has_start, has_end); 10.134 + 10.135 + /* Associate the preallocated flexpage with the original flexpage. */ 10.136 + 10.137 + flexpage->associate(&masked); 10.138 + 10.139 + return &masked; 10.140 +} 10.141 + 10.142 +void MaskedPageMapper::allocate_region(Flexpage *flexpage, Flexpage &masked) 10.143 +{ 10.144 + offset_t needed = flexpage->region->size(); 10.145 + 10.146 + /* Attempt to re-use an existing region. */ 10.147 + 10.148 + if (masked.region != NULL) 10.149 + { 10.150 + if (masked.region->size() == needed) 10.151 + return; 10.152 + else 10.153 + _memory.release(masked.region); 10.154 + } 10.155 + 10.156 + /* Set the region in the flexpage. */ 10.157 + 10.158 + masked.set_region(_memory.region(needed)); 10.159 + masked.reset(flexpage->base_offset); 10.160 +} 10.161 + 10.162 +void MaskedPageMapper::populate_region(Flexpage *flexpage, Flexpage &masked, 10.163 + bool has_start, bool has_end) 10.164 +{ 10.165 + /* Without any limits involved, provide a zero flexpage. */ 10.166 + 10.167 + if (!has_start && !has_end) 10.168 + { 10.169 + memset((void *) masked.region->start, 0, masked.size); 10.170 + return; 10.171 + } 10.172 + 10.173 + /* Determine the content limits given start and/or end offsets. */ 10.174 + 10.175 + offset_t start_offset = has_start ? _start_visible - masked.base_offset : 0; 10.176 + offset_t end_offset = has_end ? _end_visible - masked.base_offset : masked.size; 10.177 + 10.178 + if (has_start) 10.179 + memset((void *) masked.region->start, 0, start_offset); 10.180 + 10.181 + memcpy((void *) (masked.region->start + start_offset), 10.182 + (const void *) (flexpage->region->start + start_offset), 10.183 + end_offset - start_offset); 10.184 + 10.185 + if (has_end) 10.186 + memset((void *) (masked.region->start + end_offset), 0, masked.size - end_offset); 10.187 +} 10.188 + 10.189 + 10.190 + 10.191 +/* Masked flexpage constructor. */ 10.192 + 10.193 +MaskedFlexpage::MaskedFlexpage(Region *region) 10.194 +: Flexpage(region) 10.195 +{ 10.196 +} 10.197 + 10.198 +// vim: tabstop=4 expandtab shiftwidth=4
11.1 --- a/libmem/include/mem/flexpage.h Fri May 27 00:38:27 2022 +0200 11.2 +++ b/libmem/include/mem/flexpage.h Sat May 28 00:59:04 2022 +0200 11.3 @@ -21,6 +21,8 @@ 11.4 11.5 #pragma once 11.6 11.7 +#include <l4/re/c/dataspace.h> 11.8 + 11.9 #include <list> 11.10 11.11 #include <mem/memory_utils.h> 11.12 @@ -77,6 +79,8 @@ 11.13 { 11.14 } 11.15 11.16 + virtual ~Flexpage(); 11.17 + 11.18 void set_region(Region *region); 11.19 11.20 void reset(offset_t offset);
12.1 --- a/libmem/lib/src/flexpage.cc Fri May 27 00:38:27 2022 +0200 12.2 +++ b/libmem/lib/src/flexpage.cc Sat May 28 00:59:04 2022 +0200 12.3 @@ -19,14 +19,18 @@ 12.4 * Boston, MA 02110-1301, USA 12.5 */ 12.6 12.7 -#include <l4/re/c/dataspace.h> 12.8 - 12.9 #include <algorithm> 12.10 12.11 #include "flexpage.h" 12.12 12.13 12.14 12.15 +/* Virtual destructor required for introspection. */ 12.16 + 12.17 +Flexpage::~Flexpage() 12.18 +{ 12.19 +} 12.20 + 12.21 /* Reset the flexpage using 'offset', being the file offset. */ 12.22 12.23 void Flexpage::reset(offset_t offset)