L4Re/departure

Annotated libfsserver/lib/files/file_pager.cc

548:2dd97d71e627
19 months ago Paul Boddie Removed the indicated notifier from unsubscribe operations since it cannot be trivially compared to any subscribed notifier. Thus, only a single notifier can be used with any given file, pipe, directory or process endpoint.
paul@93 1
/*
paul@93 2
 * File-specific pager functionality.
paul@93 3
 *
paul@475 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@346 22
#include <fsclient/file.h>  /* file_region_flags */
paul@535 23
#include <resource/resource_server.h>
paul@346 24
#include <systypes/fcntl.h>
paul@346 25
paul@346 26
#include "copied_page_mapper.h"
paul@8 27
#include "file_pager.h"
paul@10 28
#include "mapped_file_object_server.h"
paul@8 29
paul@93 30
paul@93 31
paul@200 32
/* Initialise a pager for a file with a unique file identifier, file provider,
paul@346 33
   opening flags and a file registry. The provider offers a shared page mapper
paul@202 34
   for moderating access to loaded pages. */
paul@8 35
paul@346 36
FilePager::FilePager(fileid_t fileid, FileProvider *provider, flags_t flags)
paul@346 37
: Pager(provider->mapper(), file_region_flags(flags)),
paul@346 38
  _provider(provider), _flags(flags), fileid(fileid)
paul@8 39
{
paul@8 40
}
paul@8 41
paul@459 42
ipc_server_default_config_type FilePager::config()
paul@10 43
{
paul@459 44
    return config_MappedFileObject;
paul@10 45
}
paul@10 46
paul@78 47
paul@78 48
paul@201 49
/* Close the pager, removing the provider from the registry if appropriate. */
paul@79 50
paul@79 51
void FilePager::close()
paul@79 52
{
paul@386 53
    /* Notify other users of the file and unsubscribe. */
paul@141 54
paul@485 55
    _provider->notify_others(_notifier, NOTIFY_PEER_CLOSED, NOTIFY_VALUES_NULL);
paul@548 56
    unsubscribe();
paul@193 57
paul@200 58
    /* Detach the pager, potentially removing the file provider. */
paul@200 59
paul@222 60
    _provider->registry()->detach(fileid, _provider);
paul@79 61
}
paul@79 62
paul@79 63
paul@79 64
paul@78 65
/* File-specific operations. */
paul@78 66
paul@53 67
long FilePager::flush(offset_t populated_size, offset_t *size)
paul@53 68
{
paul@141 69
    long err = Pager::flush(populated_size, size);
paul@141 70
paul@141 71
    if (_resized)
paul@141 72
    {
paul@485 73
        _provider->notify_others(_notifier, NOTIFY_CONTENT_AVAILABLE, NOTIFY_VALUES_NULL);
paul@141 74
        _resized = false;
paul@141 75
    }
paul@141 76
paul@141 77
    return err;
paul@53 78
}
paul@53 79
paul@475 80
long FilePager::reopen(flags_t flags, offset_t *size, l4_cap_idx_t *file,
paul@475 81
                       object_flags_t *object_flags)
paul@475 82
{
paul@475 83
    Resource *resource;
paul@475 84
    long err = _provider->make_resource(flags, size, object_flags, &resource);
paul@475 85
paul@475 86
    if (err)
paul@475 87
        return err;
paul@475 88
paul@484 89
    _provider->notify_all(NOTIFY_FILE_OPENED, NOTIFY_VALUES_NULL);
paul@475 90
paul@475 91
    return ResourceServer(resource).start_thread(file);
paul@475 92
}
paul@475 93
paul@55 94
long FilePager::resize(offset_t *size)
paul@55 95
{
paul@141 96
    offset_t old_size = get_data_size();
paul@141 97
    long err = Pager::resize(size);
paul@141 98
paul@141 99
    /* If the size has changed, notify other users, but only after data has been
paul@141 100
       flushed. */
paul@141 101
paul@141 102
    if (old_size < get_data_size())
paul@141 103
        _resized = true;
paul@141 104
paul@141 105
    return err;
paul@55 106
}
paul@55 107
paul@339 108
long FilePager::mmap(offset_t position, offset_t length,
paul@339 109
                     offset_t start_visible, offset_t end_visible,
paul@332 110
                     offset_t *start_pos, offset_t *end_pos, offset_t *size)
paul@8 111
{
paul@8 112
    /* Set the limits of the paged region. */
paul@8 113
paul@346 114
    long err = Pager::mmap(position, length, start_visible, end_visible, start_pos,
paul@346 115
                           end_pos, size);
paul@346 116
paul@346 117
    if (err)
paul@346 118
        return err;
paul@346 119
paul@346 120
    /* Impose copy-on-write semantics where appropriate. */
paul@346 121
paul@346 122
    if ((_mapper != _mapper_copied) && copy_on_write())
paul@346 123
    {
paul@346 124
        _mapper_copied = new CopiedPageMapper(_mapper);
paul@346 125
        _mapper = _mapper_copied;
paul@346 126
    }
paul@346 127
paul@346 128
    return L4_EOK;
paul@346 129
}
paul@346 130
paul@346 131
/* Return whether the pager should employ copy-on-write semantics. */
paul@346 132
paul@346 133
bool FilePager::copy_on_write()
paul@346 134
{
paul@346 135
    return (_flags == O_RDONLY) && (_map_flags & L4RE_DS_F_W);
paul@8 136
}
paul@8 137
paul@78 138
paul@78 139
paul@78 140
/* Generic pager operations. */
paul@78 141
paul@410 142
long FilePager::map(offset_t offset, map_address_t hot_spot, map_flags_t map_flags, l4_snd_fpage_t *region)
paul@16 143
{
paul@346 144
    return Pager::map(offset, hot_spot, map_flags, region);
paul@16 145
}
paul@16 146
paul@141 147
paul@141 148
paul@488 149
/* Subscribe to notifications.
paul@488 150
   Readers can subscribe to new data (flush) and file closed events.
paul@488 151
   Writers can subscribe to file closed events. */
paul@141 152
paul@290 153
long FilePager::subscribe(l4_cap_idx_t notifier, notify_flags_t flags)
paul@141 154
{
paul@488 155
    /* A single notifier is recorded so that it may be unsubscribed when the
paul@488 156
       file is closed. */
paul@488 157
paul@548 158
    unsubscribe();
paul@141 159
paul@485 160
    _notifier = notifier;
paul@548 161
    return _provider->subscribe(_notifier, flags);
paul@290 162
}
paul@290 163
paul@290 164
/* Unsubscribe from notifications. */
paul@290 165
paul@548 166
long FilePager::unsubscribe()
paul@290 167
{
paul@548 168
    if (l4_is_valid_cap(_notifier))
paul@548 169
    {
paul@548 170
        long err = _provider->unsubscribe(_notifier);
paul@548 171
        _notifier = L4_INVALID_CAP;
paul@548 172
        return err;
paul@548 173
    }
paul@548 174
    else
paul@548 175
        return L4_EOK;
paul@141 176
}
paul@141 177
paul@8 178
// vim: tabstop=4 expandtab shiftwidth=4