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 FilePaging::FilePaging(Pages *pages) 30 : _pages(pages) 31 { 32 } 33 34 35 36 /* Return any registered page mapper for the given 'fileid' or NULL if no such 37 mapper is registered. */ 38 39 PageMapper *FilePaging::get(fileid_t fileid) 40 { 41 FileMapping::iterator entry = _mappers.find(fileid); 42 PageMapper *mapper; 43 44 if (entry == _mappers.end()) 45 mapper = NULL; 46 else 47 mapper = entry->second; 48 49 return mapper; 50 } 51 52 /* Remove a notification manager for the given 'fileid'. */ 53 54 void FilePaging::remove(fileid_t fileid, FileNotification *notifier) 55 { 56 _notifiers.erase(fileid); 57 delete notifier; 58 } 59 60 /* Remove a page mapper and its resources for the given 'fileid'. */ 61 62 void FilePaging::remove(fileid_t fileid, PageMapper *mapper) 63 { 64 _mappers.erase(fileid); 65 delete mapper->accessor(); 66 delete mapper; 67 } 68 69 /* Register a page 'mapper' and a notification manager for the given 'fileid'. */ 70 71 void FilePaging::set(fileid_t fileid, PageMapper *mapper) 72 { 73 FileMapping::iterator entry = _mappers.find(fileid); 74 75 if (entry != _mappers.end()) 76 return; 77 78 _mappers[fileid] = mapper; 79 80 FileNotification *notifier = new FileNotification; 81 82 _notifiers[fileid] = notifier; 83 notifier->attach(); 84 } 85 86 87 88 /* Convert opening flags to map-compatible paging flags. */ 89 90 map_flags_t FilePaging::get_flags(flags_t flags) 91 { 92 return flags & (O_WRONLY | O_RDWR) ? L4RE_DS_MAP_FLAG_RW : L4RE_DS_MAP_FLAG_RO; 93 } 94 95 96 97 /* Obtain a page mapper for the 'fileid' or register a new one in the 98 paging object. */ 99 100 long FilePaging::get_mapper(FileOpening *opening, const char *path, flags_t flags, fileid_t fileid, PageMapper **mapper) 101 { 102 /* Obtain any registered page mapper. */ 103 104 *mapper = get(fileid); 105 106 if (*mapper != NULL) 107 return L4_EOK; 108 109 /* Make an accessor and page mapper, registering the mapper. */ 110 111 Accessor *accessor; 112 long err = opening->make_accessor(path, flags, fileid, &accessor); 113 114 if (err) 115 return err; 116 117 *mapper = new PageMapper(accessor, _pages); 118 119 set(fileid, *mapper); 120 121 return L4_EOK; 122 } 123 124 /* Obtain a file-specific notification manager. */ 125 126 FileNotification *FilePaging::get_notifier(fileid_t file) 127 { 128 FileNotifiers::iterator entry = _notifiers.find(file); 129 130 if (entry != _notifiers.end()) 131 return _notifiers[file]; 132 else 133 return NULL; 134 } 135 136 137 138 /* Return a pager initialised with a page mapper. */ 139 140 long FilePaging::get_pager(FileOpening *opening, const char *path, flags_t flags, fileid_t fileid, Pager **pager) 141 { 142 std::lock_guard<std::mutex> guard(_lock); 143 144 /* Obtain any existing page mapper registered for the file, or make a new 145 page mapper. */ 146 147 PageMapper *mapper; 148 long err = get_mapper(opening, path, flags, fileid, &mapper); 149 150 if (err) 151 return err; 152 153 /* Initialise the pager with the mapper and a reference to this object for 154 closing the mapper and accessor. */ 155 156 *pager = new FilePager(fileid, mapper, get_flags(flags), this); 157 return L4_EOK; 158 } 159 160 /* Detach a pager, potentially removing its resources. */ 161 162 void FilePaging::detach_pager(fileid_t fileid, PageMapper *mapper) 163 { 164 std::lock_guard<std::mutex> guard(_lock); 165 166 if (!mapper->detach()) 167 remove(fileid, mapper); 168 169 FileNotification *notifier = get_notifier(fileid); 170 171 if ((notifier != NULL) && (!notifier->detach())) 172 remove(fileid, notifier); 173 } 174 175 /* Obtain a file-specific notification manager. */ 176 177 FileNotification *FilePaging::notifier(fileid_t file) 178 { 179 std::lock_guard<std::mutex> guard(_lock); 180 181 return get_notifier(file); 182 } 183 184 // vim: tabstop=4 expandtab shiftwidth=4