1.1 --- a/libfsserver/lib/generic/pager.cc Fri May 27 00:38:27 2022 +0200
1.2 +++ b/libfsserver/lib/generic/pager.cc Sat May 28 00:59:04 2022 +0200
1.3 @@ -23,16 +23,19 @@
1.4 #include "ipc.h"
1.5 #include "pager.h"
1.6
1.7 -#include <string.h>
1.8 +#include "copied_page_mapper.h"
1.9 +#include "masked_page_mapper.h"
1.10
1.11
1.12
1.13 /* Initialise the pager with a page mapper and the given flags controlling
1.14 access to a file. */
1.15
1.16 -Pager::Pager(PageMapper *mapper, map_flags_t flags)
1.17 -: _start(0), _size(0), _mapper(mapper), _flags(flags),
1.18 - _is_masked(false), _start_visible(0), _end_visible(0)
1.19 +Pager::Pager(GenericPageMapper *mapper, map_flags_t flags)
1.20 +: _start(0), _size(0),
1.21 + _mapper(mapper), _mapper_base(mapper), _mapper_masked(NULL),
1.22 + _mapper_copied(NULL),
1.23 + _flags(flags)
1.24 {
1.25 }
1.26
1.27 @@ -40,7 +43,17 @@
1.28
1.29 void Pager::close()
1.30 {
1.31 - /* NOTE: Need to deallocate any allocated regions and flexpages. */
1.32 + if (_mapper_masked != NULL)
1.33 + {
1.34 + delete _mapper_masked;
1.35 + _mapper_masked = NULL;
1.36 + }
1.37 +
1.38 + if (_mapper_copied != NULL)
1.39 + {
1.40 + delete _mapper_copied;
1.41 + _mapper_copied = NULL;
1.42 + }
1.43 }
1.44
1.45 /* Flush data to the file. */
1.46 @@ -78,18 +91,21 @@
1.47
1.48 *start_pos = _start;
1.49 *end_pos = _start + _size;
1.50 - *size = _mapper->get_data_size();
1.51 + *size = _mapper_base->get_data_size();
1.52
1.53 /* Permit masking of mapped regions. */
1.54
1.55 - if (start_visible || end_visible)
1.56 + if ((start_visible || end_visible) &&
1.57 + ((*start_pos != start_visible) || (*end_pos != end_visible)))
1.58 {
1.59 - _start_visible = start_visible;
1.60 - _end_visible = end_visible;
1.61 - _is_masked = (*start_pos != _start_visible) || (*end_pos != _end_visible);
1.62 + /* Introduce the masked page and copied page mappers. */
1.63 +
1.64 + _mapper_masked = new MaskedPageMapper(_mapper_base, start_visible, end_visible);
1.65 + _mapper_copied = new CopiedPageMapper(_mapper_masked);
1.66 + _mapper = _mapper_copied;
1.67 }
1.68 else
1.69 - _is_masked = false;
1.70 + _mapper = _mapper_base;
1.71
1.72 return L4_EOK;
1.73 }
1.74 @@ -110,43 +126,22 @@
1.75 if (flags & (~(_flags | L4RE_DS_F_X)))
1.76 return -L4_EACCESS;
1.77
1.78 - Flexpage *issued_flexpage = NULL, *obtained_flexpage = NULL;
1.79 -
1.80 - /* Obtain any replicated flexpage.
1.81 - NOTE: An additional condition should be introduced to test for the
1.82 - relevance of replicated flexpages. */
1.83 -
1.84 - if (flags & L4RE_DS_F_W)
1.85 - issued_flexpage = _map.find(file_offset);
1.86 -
1.87 - /* Without any replicated flexpage, obtain one for the shared, underlying
1.88 - file data. */
1.89 + /* Obtain a flexpage from the page mapper. */
1.90
1.91 - if (issued_flexpage == NULL)
1.92 - {
1.93 - obtained_flexpage = _mapper->get(file_offset, flags);
1.94 -
1.95 - /* Determine if the flexpage should be masked. */
1.96 -
1.97 - issued_flexpage = get_masked_flexpage(obtained_flexpage);
1.98 -
1.99 - /* Determine if the flexpage should be replicated. */
1.100 -
1.101 - issued_flexpage = get_replicated_flexpage(issued_flexpage, flags);
1.102 - }
1.103 + Flexpage *flexpage = _mapper->get(file_offset, flags);
1.104
1.105 /* Issue the flexpage via the IPC system. */
1.106
1.107 - long err = ipc_prepare_flexpage(issued_flexpage, file_offset, max_offset,
1.108 + long err = ipc_prepare_flexpage(flexpage, file_offset, max_offset,
1.109 hot_spot, flags, region);
1.110
1.111 if (!err)
1.112 err = complete_Dataspace_map(*region);
1.113
1.114 - /* After the obtained flexpage is issued, it is queued for future reuse. */
1.115 + /* After the obtained flexpage is issued, it is queued for future reuse, if
1.116 + appropriate for the mapper concerned. */
1.117
1.118 - if (obtained_flexpage != NULL)
1.119 - _mapper->queue(obtained_flexpage);
1.120 + _mapper->queue(flexpage);
1.121
1.122 if (err)
1.123 return err;
1.124 @@ -161,116 +156,4 @@
1.125 return _mapper->get_data_size();
1.126 }
1.127
1.128 -/* Detect flexpages with masked content, introducing separate flexpages
1.129 - offering masked content from the same region. */
1.130 -
1.131 -Flexpage *Pager::get_masked_flexpage(Flexpage *flexpage)
1.132 -{
1.133 - /* If not masking content, return the original flexpage. */
1.134 -
1.135 - if (!_is_masked)
1.136 - return flexpage;
1.137 -
1.138 - /* Determine whether the flexpage involves the limits of the visible
1.139 - region or is beyond such limits. */
1.140 -
1.141 - bool has_start = flexpage->supports_position(_start_visible) &&
1.142 - flexpage->base_offset != _start_visible;
1.143 - bool has_end = flexpage->supports_position(_end_visible);
1.144 - bool has_zero = (flexpage->base_offset >= _end_visible) ||
1.145 - (flexpage->base_offset + flexpage->size < _start_visible);
1.146 -
1.147 - /* Return the original flexpage within the visible limits. */
1.148 -
1.149 - if (!has_start && !has_end && !has_zero)
1.150 - return flexpage;
1.151 -
1.152 - /* Allocate and populate a region in one of the preallocated flexpages for
1.153 - masked content. */
1.154 -
1.155 - Flexpage &masked = has_start ? _start_flexpage :
1.156 - has_end ? _end_flexpage :
1.157 - _zero_flexpage;
1.158 -
1.159 - allocate_region(flexpage, masked);
1.160 - populate_region(flexpage, masked, has_start, has_end);
1.161 -
1.162 - /* Associate the preallocated flexpage with the original flexpage. */
1.163 -
1.164 - flexpage->associate(&masked);
1.165 -
1.166 - return &masked;
1.167 -}
1.168 -
1.169 -void Pager::allocate_region(Flexpage *flexpage, Flexpage &masked)
1.170 -{
1.171 - offset_t needed = flexpage->region->size();
1.172 -
1.173 - /* Attempt to re-use an existing region. */
1.174 -
1.175 - if (masked.region != NULL)
1.176 - {
1.177 - if (masked.region->size() == needed)
1.178 - return;
1.179 - else
1.180 - _memory.release(masked.region);
1.181 - }
1.182 -
1.183 - /* Set the region in the flexpage. */
1.184 -
1.185 - masked.set_region(_memory.region(needed));
1.186 - masked.reset(flexpage->base_offset);
1.187 -}
1.188 -
1.189 -void Pager::populate_region(Flexpage *flexpage, Flexpage &masked,
1.190 - bool has_start, bool has_end)
1.191 -{
1.192 - /* Without any limits involved, provide a zero flexpage. */
1.193 -
1.194 - if (!has_start && !has_end)
1.195 - {
1.196 - memset((void *) masked.region->start, 0, masked.size);
1.197 - return;
1.198 - }
1.199 -
1.200 - /* Determine the content limits given start and/or end offsets. */
1.201 -
1.202 - offset_t start_offset = has_start ? _start_visible - masked.base_offset : 0;
1.203 - offset_t end_offset = has_end ? _end_visible - masked.base_offset : masked.size;
1.204 -
1.205 - if (has_start)
1.206 - memset((void *) masked.region->start, 0, start_offset);
1.207 -
1.208 - memcpy((void *) (masked.region->start + start_offset),
1.209 - (const void *) (flexpage->region->start + start_offset),
1.210 - end_offset - start_offset);
1.211 -
1.212 - if (has_end)
1.213 - memset((void *) (masked.region->start + end_offset), 0, masked.size - end_offset);
1.214 -}
1.215 -
1.216 -/* Detect flexpages with replicated content, introducing separate flexpages
1.217 - offering replicated content from the same region. */
1.218 -
1.219 -Flexpage *Pager::get_replicated_flexpage(Flexpage *flexpage, map_flags_t flags)
1.220 -{
1.221 - /* NOTE: An additional condition should be introduced to test for the
1.222 - relevance of replicated flexpages. For now, detect copy-on-write
1.223 - situations. */
1.224 -
1.225 - if (_is_masked && (flags & L4RE_DS_F_W))
1.226 - {
1.227 - Region *region = _memory.region(flexpage->size);
1.228 - Flexpage *replicated = new Flexpage(region);
1.229 -
1.230 - replicated->reset(flexpage->base_offset);
1.231 -
1.232 - memcpy((void *) region->start, (const void *) flexpage->region->start, flexpage->size);
1.233 - _map.insert(replicated);
1.234 - return replicated;
1.235 - }
1.236 - else
1.237 - return flexpage;
1.238 -}
1.239 -
1.240 // vim: tabstop=4 expandtab shiftwidth=4