L4Re/departure

Annotated libfsserver/lib/mapping/page_mapper.cc

554:b3eab5c45452
19 months ago Paul Boddie Moved flexpage-related IPC functions into libmem, also incorporating the invalidation of derived flexpages into the flexpage abstraction.
paul@93 1
/*
paul@93 2
 * A page mapper providing memory pages to satisfy file accesses.
paul@93 3
 *
paul@554 4
 * Copyright (C) 2021, 2022, 2023 Paul Boddie <paul@boddie.org.uk>
paul@93 5
 *
paul@93 6
 * This program is free software; you can redistribute it and/or
paul@93 7
 * modify it under the terms of the GNU General Public License as
paul@93 8
 * published by the Free Software Foundation; either version 2 of
paul@93 9
 * the License, or (at your option) any later version.
paul@93 10
 *
paul@93 11
 * This program is distributed in the hope that it will be useful,
paul@93 12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
paul@93 13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
paul@93 14
 * GNU General Public License for more details.
paul@93 15
 *
paul@93 16
 * You should have received a copy of the GNU General Public License
paul@93 17
 * along with this program; if not, write to the Free Software
paul@93 18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
paul@93 19
 * Boston, MA  02110-1301, USA
paul@93 20
 */
paul@93 21
paul@6 22
#include "page_mapper.h"
paul@6 23
paul@6 24
paul@6 25
paul@200 26
/* Provide mapped pages populated with the given 'accessor', with pages obtained
paul@200 27
   from the given 'pages' collection. */
paul@200 28
paul@72 29
PageMapper::PageMapper(Accessor *accessor, Pages *pages)
paul@197 30
: _accessor(accessor), _pages(pages)
paul@6 31
{
paul@6 32
}
paul@6 33
paul@200 34
/* Upon deallocation, purge active pages. */
paul@6 35
paul@200 36
PageMapper::~PageMapper()
paul@6 37
{
paul@200 38
    _map.purge(this, _pages);
paul@6 39
}
paul@6 40
paul@6 41
/* Interface for the pager. */
paul@6 42
paul@6 43
/* Return a flexpage providing access to the indicated file 'offset'.
paul@6 44
paul@6 45
   The returned flexpage will either be an existing, compatible flexpage or a
paul@6 46
   completely new flexpage.
paul@6 47
paul@52 48
   This method locks the mapper to prevent concurrent queries with the same
paul@52 49
   details, with the lock held until the queue operation releases the lock. */
paul@6 50
paul@121 51
Flexpage *PageMapper::get(offset_t offset, map_flags_t flags)
paul@6 52
{
paul@6 53
    _lock.lock();
paul@6 54
paul@6 55
    Flexpage *f = find(offset);
paul@6 56
paul@6 57
    if (f == NULL)
paul@6 58
        f = flexpage(offset);
paul@6 59
paul@11 60
    /* Record a new user of the flexpage and upgrade the access flags. */
paul@11 61
paul@6 62
    f->increment();
paul@11 63
    f->upgrade(flags);
paul@6 64
    return f;
paul@6 65
}
paul@6 66
paul@6 67
/* Queue the given 'flexpage' in the page collection, making it available for
paul@6 68
   eventual reuse.
paul@6 69
paul@52 70
   This method unlocks the mapper. */
paul@6 71
paul@6 72
void PageMapper::queue(Flexpage *flexpage)
paul@6 73
{
paul@6 74
    _pages->queue(this, flexpage);
paul@6 75
paul@6 76
    _lock.unlock();
paul@6 77
}
paul@6 78
paul@6 79
/* Flush pages in the given range from 'start' with 'size'. */
paul@6 80
paul@6 81
void PageMapper::flush_all(offset_t start, offset_t size)
paul@6 82
{
paul@6 83
    std::lock_guard<std::mutex> guard(_lock);
paul@6 84
paul@6 85
    _map.flush_all(start, size, this, _pages);
paul@6 86
}
paul@6 87
paul@6 88
/* Return the maximum extent of the mapped resource. */
paul@6 89
paul@6 90
offset_t PageMapper::get_data_size()
paul@6 91
{
paul@6 92
    return _accessor->get_size();
paul@6 93
}
paul@6 94
paul@53 95
/* Set the maximum extent of the mapped resource. */
paul@53 96
paul@53 97
void PageMapper::set_data_size(offset_t size)
paul@53 98
{
paul@53 99
    _accessor->set_size(size);
paul@53 100
}
paul@53 101
paul@6 102
/* Internal flexpage retrieval methods. */
paul@6 103
paul@6 104
/* Find an existing flexpage for 'offset'. Where the accessor has registered a
paul@6 105
   compatible flexpage, an attempt is made to reserve it in the page collection;
paul@6 106
   if this succeeds, the flexpage is returned. Otherwise, NULL is returned. */
paul@6 107
paul@6 108
Flexpage *PageMapper::find(offset_t offset)
paul@6 109
{
paul@6 110
    Flexpage *flexpage = _map.find(offset);
paul@6 111
paul@6 112
    /* Between finding and reserving a flexpage, there is a possibility that
paul@6 113
       another accessor might acquire the flexpage, issue it, and even purge
paul@6 114
       it. */
paul@6 115
paul@6 116
    if ((flexpage != NULL) && _pages->reserve(this, flexpage))
paul@6 117
        return flexpage;
paul@6 118
    else
paul@6 119
        return NULL;
paul@6 120
}
paul@6 121
paul@6 122
/* Obtain a new flexpage for the file 'offset'. If the page collection is unable
paul@6 123
   to obtain a completely new flexpage, an existing flexpage is requested from
paul@6 124
   the page collection and recycled.
paul@6 125
paul@6 126
   The obtained flexpage is filled with content. */
paul@6 127
paul@6 128
Flexpage *PageMapper::flexpage(offset_t offset)
paul@6 129
{
paul@6 130
    Flexpage *flexpage = _pages->flexpage();
paul@6 131
paul@6 132
    flexpage->reset(offset);
paul@6 133
paul@6 134
    fill(flexpage);
paul@6 135
    _map.insert(flexpage);
paul@6 136
    return flexpage;
paul@6 137
}
paul@6 138
paul@6 139
/* Interface for the page collection. */
paul@6 140
paul@6 141
/* Remove the record of 'flexpage' in this accessor, flushing its content. */
paul@6 142
paul@6 143
void PageMapper::remove(Flexpage *flexpage)
paul@6 144
{
paul@6 145
    _map.remove(this, flexpage);
paul@6 146
}
paul@6 147
paul@6 148
/* Data transfer methods. */
paul@6 149
paul@6 150
void PageMapper::fill(Flexpage *flexpage)
paul@6 151
{
paul@6 152
    _accessor->fill(flexpage);
paul@6 153
}
paul@6 154
paul@6 155
void PageMapper::flush(Flexpage *flexpage, bool purge)
paul@6 156
{
paul@6 157
    if (flexpage->decrement() || purge)
paul@6 158
    {
paul@332 159
        /* NOTE: Derived flexpages might potentially support their contents
paul@332 160
                 being merged into the flushed data, although this is a
paul@332 161
                 non-trivial problem. */
paul@332 162
paul@115 163
        if (flexpage->modified())
paul@115 164
            _accessor->flush(flexpage);
paul@115 165
paul@332 166
        /* Unmap the flexpage, requiring users of its memory to request another
paul@554 167
           flexpage in future. This also unmaps all derived flexpages, since
paul@554 168
           these rely on the underlying file contents. */
paul@332 169
paul@554 170
        flexpage->invalidate();
paul@6 171
    }
paul@6 172
}
paul@6 173
paul@6 174
// vim: tabstop=4 expandtab shiftwidth=4