L4Re/departure

libfsserver/lib/mapping/masked_page_mapper.cc

618:7123a7307a82
8 months ago Paul Boddie Introduced some debugging output control.
     1 /*     2  * A page mapper providing memory pages to satisfy file accesses, masking the     3  * limits of a visible region of the file's contents.     4  *     5  * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk>     6  *     7  * This program is free software; you can redistribute it and/or     8  * modify it under the terms of the GNU General Public License as     9  * published by the Free Software Foundation; either version 2 of    10  * the License, or (at your option) any later version.    11  *    12  * This program is distributed in the hope that it will be useful,    13  * but WITHOUT ANY WARRANTY; without even the implied warranty of    14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    15  * GNU General Public License for more details.    16  *    17  * You should have received a copy of the GNU General Public License    18  * along with this program; if not, write to the Free Software    19  * Foundation, Inc., 51 Franklin Street, Fifth Floor,    20  * Boston, MA  02110-1301, USA    21  */    22     23 #include <string.h>    24     25 #include "masked_page_mapper.h"    26     27     28     29 /* Provide mapped pages populated using the given 'mapper', with a visible    30    region defined that causes the limits of this region to be masked. */    31     32 MaskedPageMapper::MaskedPageMapper(GenericPageMapper *mapper,    33                                    offset_t start_visible, offset_t end_visible)    34 : _mapper(mapper), _start_visible(start_visible), _end_visible(end_visible)    35 {    36     _size = _mapper->get_data_size();    37 }    38     39 MaskedPageMapper::~MaskedPageMapper()    40 {    41     if (_start_flexpage.region != NULL)    42         _memory.release(_start_flexpage.region);    43     44     if (_end_flexpage.region != NULL)    45         _memory.release(_end_flexpage.region);    46     47     if (_zero_flexpage.region != NULL)    48         _memory.release(_zero_flexpage.region);    49 }    50     51 /* Interface for the pager. */    52     53 /* Return a flexpage providing access to the indicated file 'offset'.    54     55    The returned flexpage will either provide direct access to the underlying    56    file content or be a completely new flexpage containing masked content. */    57     58 Flexpage *MaskedPageMapper::get(offset_t offset, map_flags_t flags)    59 {    60     Flexpage *f = _mapper->get(offset, flags);    61     Flexpage *mf = get_masked_flexpage(f);    62     63     if (f != mf)    64         _mapper->queue(f);    65     66     return mf;    67 }    68     69 /* Queue the given 'flexpage'. */    70     71 void MaskedPageMapper::queue(Flexpage *flexpage)    72 {    73     if (dynamic_cast<MaskedFlexpage *>(flexpage) == NULL)    74         _mapper->queue(flexpage);    75 }    76     77 /* Flush pages in the given range from 'start' with 'size'. */    78     79 void MaskedPageMapper::flush_all(offset_t start, offset_t size)    80 {    81     /* NOTE: This might be superfluous since masked regions probably should be    82              read-only or copy-on-write. */    83     84     _mapper->flush_all(start, size);    85 }    86     87 /* Return the maximum extent of the mapped resource. */    88     89 offset_t MaskedPageMapper::get_data_size()    90 {    91     return _size;    92 }    93     94 /* Set the maximum extent of the mapped resource. */    95     96 void MaskedPageMapper::set_data_size(offset_t size)    97 {    98     _size = size;    99 }   100    101 /* Internal flexpage retrieval methods. */   102    103 /* Detect flexpages with masked content, introducing separate flexpages   104    offering masked content from the same region. */   105    106 Flexpage *MaskedPageMapper::get_masked_flexpage(Flexpage *flexpage)   107 {   108     /* Determine whether the flexpage involves the limits of the visible   109        region or is beyond such limits. */   110    111     bool has_start = flexpage->supports_position(_start_visible) &&   112                      flexpage->base_offset != _start_visible;   113     bool has_end = flexpage->supports_position(_end_visible);   114     bool has_zero = (flexpage->base_offset >= _end_visible) ||   115                     (flexpage->base_offset + flexpage->size < _start_visible);   116    117     /* Return the original flexpage within the visible limits. */   118    119     if (!has_start && !has_end && !has_zero)   120         return flexpage;   121    122     /* Allocate and populate a region in one of the preallocated flexpages for   123        masked content. */   124    125     Flexpage &masked = has_start ? _start_flexpage :   126                        has_end ? _end_flexpage :   127                                  _zero_flexpage;   128    129     allocate_region(flexpage, masked);   130     populate_region(flexpage, masked, has_start, has_end);   131    132     /* Associate the preallocated flexpage with the original flexpage. */   133    134     flexpage->associate(&masked);   135    136     return &masked;   137 }   138    139 void MaskedPageMapper::allocate_region(Flexpage *flexpage, Flexpage &masked)   140 {   141     offset_t needed = flexpage->region->size();   142    143     /* Attempt to re-use an existing region. */   144    145     if (masked.region != NULL)   146     {   147         if (masked.region->size() == needed)   148             return;   149         else   150             _memory.release(masked.region);   151     }   152    153     /* Set the region in the flexpage. */   154    155     masked.set_region(_memory.region(needed));   156     masked.reset(flexpage->base_offset);   157 }   158    159 void MaskedPageMapper::populate_region(Flexpage *flexpage, Flexpage &masked,   160                             bool has_start, bool has_end)   161 {   162     /* Without any limits involved, provide a zero flexpage. */   163    164     if (!has_start && !has_end)   165     {   166         memset((void *) masked.region->start, 0, masked.size);   167         return;   168     }   169    170     /* Determine the content limits given start and/or end offsets. */   171    172     offset_t start_offset = has_start ? _start_visible - masked.base_offset : 0;   173     offset_t end_offset = has_end ? _end_visible - masked.base_offset : masked.size;   174    175     if (has_start)   176         memset((void *) masked.region->start, 0, start_offset);   177    178     memcpy((void *) (masked.region->start + start_offset),   179            (const void *) (flexpage->region->start + start_offset),   180            end_offset - start_offset);   181    182     if (has_end)   183         memset((void *) (masked.region->start + end_offset), 0, masked.size - end_offset);   184 }   185    186    187    188 /* Masked flexpage constructor. */   189    190 MaskedFlexpage::MaskedFlexpage(Region *region)   191 : Flexpage(region)   192 {   193 }   194    195 // vim: tabstop=4 expandtab shiftwidth=4