1 /* 2 * General functionality supporting file paging. 3 * 4 * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License as 8 * published by the Free Software Foundation; either version 2 of 9 * the License, or (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA 20 */ 21 22 #include "file_pager.h" 23 #include "file_paging.h" 24 25 #include <systypes/fcntl.h> 26 27 28 29 /* The file paging coordinator provides a memory page collection to the page 30 mappers it creates. */ 31 32 FilePaging::FilePaging(Pages *pages) 33 : _pages(pages) 34 { 35 } 36 37 38 39 /* Return any registered provider for the given 'fileid' or NULL if no such 40 provider is registered. */ 41 42 Accountable *FilePaging::get(fileid_t fileid) 43 { 44 FileMapping::iterator entry = _providers.find(fileid); 45 Accountable *provider; 46 47 if (entry == _providers.end()) 48 provider = NULL; 49 else 50 provider = entry->second; 51 52 return provider; 53 } 54 55 /* Remove a provider and its resources for the given 'fileid'. */ 56 57 void FilePaging::remove(fileid_t fileid, Accountable *provider) 58 { 59 _providers.erase(fileid); 60 delete provider; 61 } 62 63 /* Register a 'provider' for the given 'fileid'. */ 64 65 void FilePaging::set(fileid_t fileid, Accountable *provider) 66 { 67 FileMapping::iterator entry = _providers.find(fileid); 68 69 if (entry != _providers.end()) 70 return; 71 72 _providers[fileid] = provider; 73 } 74 75 76 77 /* Convert opening flags to map-compatible paging flags. */ 78 79 map_flags_t FilePaging::get_flags(flags_t flags) 80 { 81 return flags & (O_WRONLY | O_RDWR) ? L4RE_DS_MAP_FLAG_RW : L4RE_DS_MAP_FLAG_RO; 82 } 83 84 85 86 /* Obtain a provider for the 'fileid' or register a new one in the 87 paging object. */ 88 89 long FilePaging::get_provider(FileOpening *opening, const char *path, flags_t flags, fileid_t fileid, FileProvider **file_provider) 90 { 91 /* Obtain any registered provider. */ 92 93 Accountable *provider = get(fileid); 94 95 if (provider != NULL) 96 { 97 /* Distinguish between file providers and other objects that may be 98 registered. For files specifically, a file provider is needed 99 because it will provide a page mapper. */ 100 101 *file_provider = dynamic_cast<FileProvider *>(provider); 102 103 if ((*file_provider) != NULL) 104 return L4_EOK; 105 else 106 return -L4_EIO; 107 } 108 109 /* Make an accessor, page mapper, and a provider to encapsulate them. */ 110 111 Accessor *accessor; 112 long err = opening->make_accessor(path, flags, fileid, &accessor); 113 114 if (err) 115 return err; 116 117 PageMapper *mapper = new PageMapper(accessor, _pages); 118 *file_provider = new FileProvider(mapper); 119 120 /* Register the provider. */ 121 122 set(fileid, *file_provider); 123 return L4_EOK; 124 } 125 126 127 128 /* Return a pager initialised with a provider, page mapper and accessor. */ 129 130 long FilePaging::get_pager(FileOpening *opening, const char *path, flags_t flags, fileid_t fileid, Pager **pager) 131 { 132 std::lock_guard<std::mutex> guard(_lock); 133 134 /* Obtain any existing provider registered for the file, or make a new 135 provider. */ 136 137 FileProvider *provider; 138 long err = get_provider(opening, path, flags, fileid, &provider); 139 140 if (err) 141 return err; 142 143 /* Initialise the pager with the provider and a reference to this object for 144 closing the provider, mapper and accessor. */ 145 146 provider->attach(); 147 *pager = new FilePager(fileid, provider, get_flags(flags), this); 148 return L4_EOK; 149 } 150 151 /* Detach a pager, potentially removing its resources. */ 152 153 void FilePaging::detach_pager(fileid_t fileid, Accountable *provider) 154 { 155 std::lock_guard<std::mutex> guard(_lock); 156 157 if (!provider->detach()) 158 remove(fileid, provider); 159 } 160 161 // vim: tabstop=4 expandtab shiftwidth=4