Line data Source code
1 : /* 2 : Copyright 2018-2024, Barcelona Supercomputing Center (BSC), Spain 3 : Copyright 2015-2024, Johannes Gutenberg Universitaet Mainz, Germany 4 : 5 : This software was partially supported by the 6 : EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu). 7 : 8 : This software was partially supported by the 9 : ADA-FS project under the SPPEXA project funded by the DFG. 10 : 11 : This file is part of GekkoFS' POSIX interface. 12 : 13 : GekkoFS' POSIX interface is free software: you can redistribute it and/or 14 : modify it under the terms of the GNU Lesser General Public License as 15 : published by the Free Software Foundation, either version 3 of the License, 16 : or (at your option) any later version. 17 : 18 : GekkoFS' POSIX interface is distributed in the hope that it will be useful, 19 : but WITHOUT ANY WARRANTY; without even the implied warranty of 20 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 : GNU Lesser General Public License for more details. 22 : 23 : You should have received a copy of the GNU Lesser General Public License 24 : along with GekkoFS' POSIX interface. If not, see 25 : <https://www.gnu.org/licenses/>. 26 : 27 : SPDX-License-Identifier: LGPL-3.0-or-later 28 : */ 29 : 30 : #include <client/open_file_map.hpp> 31 : #include <client/open_dir.hpp> 32 : #include <client/preload.hpp> 33 : #include <client/preload_util.hpp> 34 : #include <client/logging.hpp> 35 : 36 : extern "C" { 37 : #include <fcntl.h> 38 : } 39 : 40 : using namespace std; 41 : 42 : namespace gkfs::filemap { 43 : 44 1143 : OpenFile::OpenFile(const string& path, const int flags, FileType type) 45 1143 : : type_(type), path_(path) { 46 : // set flags to OpenFile 47 1143 : if(flags & O_CREAT) 48 1039 : flags_[gkfs::utils::to_underlying(OpenFile_flags::creat)] = true; 49 1143 : if(flags & O_APPEND) 50 4 : flags_[gkfs::utils::to_underlying(OpenFile_flags::append)] = true; 51 1143 : if(flags & O_TRUNC) 52 1005 : flags_[gkfs::utils::to_underlying(OpenFile_flags::trunc)] = true; 53 1143 : if(flags & O_RDONLY) 54 : flags_[gkfs::utils::to_underlying(OpenFile_flags::rdonly)] = true; 55 1143 : if(flags & O_WRONLY) 56 1073 : flags_[gkfs::utils::to_underlying(OpenFile_flags::wronly)] = true; 57 1143 : if(flags & O_RDWR) 58 2 : flags_[gkfs::utils::to_underlying(OpenFile_flags::rdwr)] = true; 59 : 60 1143 : pos_ = 0; // If O_APPEND flag is used, it will be used before each write. 61 1143 : } 62 : 63 248 : OpenFileMap::OpenFileMap() : fd_idx(10000), fd_validation_needed(false) {} 64 : 65 : string 66 1120 : OpenFile::path() const { 67 1120 : return path_; 68 : } 69 : 70 : void 71 0 : OpenFile::path(const string& path) { 72 0 : OpenFile::path_ = path; 73 0 : } 74 : 75 : unsigned long 76 97 : OpenFile::pos() { 77 97 : lock_guard<mutex> lock(pos_mutex_); 78 97 : return pos_; 79 : } 80 : 81 : void 82 67 : OpenFile::pos(unsigned long pos) { 83 67 : lock_guard<mutex> lock(pos_mutex_); 84 67 : OpenFile::pos_ = pos; 85 67 : } 86 : 87 : bool 88 45 : OpenFile::get_flag(OpenFile_flags flag) { 89 45 : lock_guard<mutex> lock(pos_mutex_); 90 45 : return flags_[gkfs::utils::to_underlying(flag)]; 91 : } 92 : 93 : void 94 2 : OpenFile::set_flag(OpenFile_flags flag, bool value) { 95 2 : lock_guard<mutex> lock(flag_mutex_); 96 2 : flags_[gkfs::utils::to_underlying(flag)] = value; 97 2 : } 98 : 99 : FileType 100 105 : OpenFile::type() const { 101 105 : return type_; 102 : } 103 : 104 : // OpenFileMap starts here 105 : 106 : shared_ptr<OpenFile> 107 142 : OpenFileMap::get(int fd) { 108 142 : lock_guard<recursive_mutex> lock(files_mutex_); 109 142 : auto f = files_.find(fd); 110 142 : if(f == files_.end()) { 111 0 : return nullptr; 112 : } else { 113 284 : return f->second; 114 : } 115 : } 116 : 117 : shared_ptr<OpenDir> 118 32 : OpenFileMap::get_dir(int dirfd) { 119 64 : auto f = get(dirfd); 120 32 : if(f == nullptr || f->type() != FileType::directory) { 121 1 : return nullptr; 122 : } 123 95 : return static_pointer_cast<OpenDir>(f); 124 : } 125 : 126 : bool 127 370968 : OpenFileMap::exist(const int fd) { 128 370968 : lock_guard<recursive_mutex> lock(files_mutex_); 129 370968 : auto f = files_.find(fd); 130 370968 : return !(f == files_.end()); 131 : } 132 : 133 : int 134 1143 : OpenFileMap::safe_generate_fd_idx_() { 135 1143 : auto fd = generate_fd_idx(); 136 : /* 137 : * Check if fd is still in use and generate another if yes 138 : * Note that this can only happen once the all fd indices within the int has 139 : * been used to the int::max Once this limit is exceeded, we set fd_idx back 140 : * to 3 and begin anew. Only then, if a file was open for a long time will 141 : * we have to generate another index. 142 : * 143 : * This situation can only occur when all fd indices have been given away 144 : * once and we start again, in which case the fd_validation_needed flag is 145 : * set. fd_validation is set to false, if 146 : */ 147 1143 : if(fd_validation_needed) { 148 0 : while(exist(fd)) { 149 0 : fd = generate_fd_idx(); 150 : } 151 : } 152 1143 : return fd; 153 : } 154 : 155 : int 156 1140 : OpenFileMap::add(std::shared_ptr<OpenFile> open_file) { 157 1140 : auto fd = safe_generate_fd_idx_(); 158 1140 : lock_guard<recursive_mutex> lock(files_mutex_); 159 2280 : files_.insert(make_pair(fd, open_file)); 160 2280 : return fd; 161 : } 162 : 163 : bool 164 1006 : OpenFileMap::remove(const int fd) { 165 1006 : lock_guard<recursive_mutex> lock(files_mutex_); 166 1006 : auto f = files_.find(fd); 167 1006 : if(f == files_.end()) { 168 : return false; 169 : } 170 1006 : files_.erase(fd); 171 1006 : if(fd_validation_needed && files_.empty()) { 172 0 : fd_validation_needed = false; 173 0 : LOG(DEBUG, "fd_validation flag reset"); 174 : } 175 : return true; 176 : } 177 : 178 : int 179 3 : OpenFileMap::dup(const int oldfd) { 180 6 : lock_guard<recursive_mutex> lock(files_mutex_); 181 6 : auto open_file = get(oldfd); 182 3 : if(open_file == nullptr) { 183 0 : errno = EBADF; 184 0 : return -1; 185 : } 186 3 : auto newfd = safe_generate_fd_idx_(); 187 6 : files_.insert(make_pair(newfd, open_file)); 188 3 : return newfd; 189 : } 190 : 191 : int 192 1 : OpenFileMap::dup2(const int oldfd, const int newfd) { 193 2 : lock_guard<recursive_mutex> lock(files_mutex_); 194 2 : auto open_file = get(oldfd); 195 1 : if(open_file == nullptr) { 196 0 : errno = EBADF; 197 0 : return -1; 198 : } 199 1 : if(oldfd == newfd) 200 : return newfd; 201 : // remove newfd if exists in filemap silently 202 1 : if(exist(newfd)) { 203 1 : remove(newfd); 204 : } 205 : // to prevent duplicate fd idx in the future. First three fd are reservered 206 : // by os streams that we do not overwrite 207 1 : if(get_fd_idx() < newfd && newfd != 0 && newfd != 1 && newfd != 2) 208 0 : fd_validation_needed = true; 209 2 : files_.insert(make_pair(newfd, open_file)); 210 1 : return newfd; 211 : } 212 : 213 : /** 214 : * Generate new file descriptor index to be used as an fd within one process 215 : * @return fd_idx 216 : */ 217 : int 218 1143 : OpenFileMap::generate_fd_idx() { 219 : // We need a mutex here for thread safety 220 1143 : std::lock_guard<std::mutex> inode_lock(fd_idx_mutex); 221 1143 : if(fd_idx == std::numeric_limits<int>::max()) { 222 0 : LOG(WARNING, 223 0 : "File descriptor index exceeded ints max value. Setting it back to 100000"); 224 : /* 225 : * Setting fd_idx back to 3 could have the effect that fd are given 226 : * twice for different path. This must not happen. Instead a flag is set 227 : * which tells can tell the OpenFileMap that it should check if this fd 228 : * is really safe to use. 229 : */ 230 0 : fd_idx = 100000; 231 0 : fd_validation_needed = true; 232 : } 233 2286 : return fd_idx++; 234 : } 235 : 236 : int 237 1 : OpenFileMap::get_fd_idx() { 238 1 : std::lock_guard<std::mutex> inode_lock(fd_idx_mutex); 239 1 : return fd_idx; 240 : } 241 : 242 : } // namespace gkfs::filemap