Program Listing for File open_file_map.cpp
↰ Return to documentation for file (src/client/open_file_map.cpp
)
/*
Copyright 2018-2024, Barcelona Supercomputing Center (BSC), Spain
Copyright 2015-2024, Johannes Gutenberg Universitaet Mainz, Germany
This software was partially supported by the
EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu).
This software was partially supported by the
ADA-FS project under the SPPEXA project funded by the DFG.
This file is part of GekkoFS' POSIX interface.
GekkoFS' POSIX interface is free software: you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of the License,
or (at your option) any later version.
GekkoFS' POSIX interface is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with GekkoFS' POSIX interface. If not, see
<https://www.gnu.org/licenses/>.
SPDX-License-Identifier: LGPL-3.0-or-later
*/
#include <client/open_file_map.hpp>
#include <client/open_dir.hpp>
#include <client/preload.hpp>
#include <client/preload_util.hpp>
#include <client/logging.hpp>
extern "C" {
#include <fcntl.h>
}
using namespace std;
namespace gkfs::filemap {
OpenFile::OpenFile(const string& path, const int flags, FileType type)
: type_(type), path_(path) {
// set flags to OpenFile
if(flags & O_CREAT)
flags_[gkfs::utils::to_underlying(OpenFile_flags::creat)] = true;
if(flags & O_APPEND)
flags_[gkfs::utils::to_underlying(OpenFile_flags::append)] = true;
if(flags & O_TRUNC)
flags_[gkfs::utils::to_underlying(OpenFile_flags::trunc)] = true;
if(flags & O_RDONLY)
flags_[gkfs::utils::to_underlying(OpenFile_flags::rdonly)] = true;
if(flags & O_WRONLY)
flags_[gkfs::utils::to_underlying(OpenFile_flags::wronly)] = true;
if(flags & O_RDWR)
flags_[gkfs::utils::to_underlying(OpenFile_flags::rdwr)] = true;
pos_ = 0; // If O_APPEND flag is used, it will be used before each write.
}
OpenFileMap::OpenFileMap() : fd_idx(10000), fd_validation_needed(false) {}
string
OpenFile::path() const {
return path_;
}
void
OpenFile::path(const string& path) {
OpenFile::path_ = path;
}
unsigned long
OpenFile::pos() {
lock_guard<mutex> lock(pos_mutex_);
return pos_;
}
void
OpenFile::pos(unsigned long pos) {
lock_guard<mutex> lock(pos_mutex_);
OpenFile::pos_ = pos;
}
bool
OpenFile::get_flag(OpenFile_flags flag) {
lock_guard<mutex> lock(pos_mutex_);
return flags_[gkfs::utils::to_underlying(flag)];
}
void
OpenFile::set_flag(OpenFile_flags flag, bool value) {
lock_guard<mutex> lock(flag_mutex_);
flags_[gkfs::utils::to_underlying(flag)] = value;
}
FileType
OpenFile::type() const {
return type_;
}
// OpenFileMap starts here
shared_ptr<OpenFile>
OpenFileMap::get(int fd) {
lock_guard<recursive_mutex> lock(files_mutex_);
auto f = files_.find(fd);
if(f == files_.end()) {
return nullptr;
} else {
return f->second;
}
}
shared_ptr<OpenDir>
OpenFileMap::get_dir(int dirfd) {
auto f = get(dirfd);
if(f == nullptr || f->type() != FileType::directory) {
return nullptr;
}
return static_pointer_cast<OpenDir>(f);
}
bool
OpenFileMap::exist(const int fd) {
lock_guard<recursive_mutex> lock(files_mutex_);
auto f = files_.find(fd);
return !(f == files_.end());
}
int
OpenFileMap::safe_generate_fd_idx_() {
auto fd = generate_fd_idx();
/*
* Check if fd is still in use and generate another if yes
* Note that this can only happen once the all fd indices within the int has
* been used to the int::max Once this limit is exceeded, we set fd_idx back
* to 3 and begin anew. Only then, if a file was open for a long time will
* we have to generate another index.
*
* This situation can only occur when all fd indices have been given away
* once and we start again, in which case the fd_validation_needed flag is
* set. fd_validation is set to false, if
*/
if(fd_validation_needed) {
while(exist(fd)) {
fd = generate_fd_idx();
}
}
return fd;
}
int
OpenFileMap::add(std::shared_ptr<OpenFile> open_file) {
auto fd = safe_generate_fd_idx_();
lock_guard<recursive_mutex> lock(files_mutex_);
files_.insert(make_pair(fd, open_file));
return fd;
}
bool
OpenFileMap::remove(const int fd) {
lock_guard<recursive_mutex> lock(files_mutex_);
auto f = files_.find(fd);
if(f == files_.end()) {
return false;
}
files_.erase(fd);
if(fd_validation_needed && files_.empty()) {
fd_validation_needed = false;
LOG(DEBUG, "fd_validation flag reset");
}
return true;
}
int
OpenFileMap::dup(const int oldfd) {
lock_guard<recursive_mutex> lock(files_mutex_);
auto open_file = get(oldfd);
if(open_file == nullptr) {
errno = EBADF;
return -1;
}
auto newfd = safe_generate_fd_idx_();
files_.insert(make_pair(newfd, open_file));
return newfd;
}
int
OpenFileMap::dup2(const int oldfd, const int newfd) {
lock_guard<recursive_mutex> lock(files_mutex_);
auto open_file = get(oldfd);
if(open_file == nullptr) {
errno = EBADF;
return -1;
}
if(oldfd == newfd)
return newfd;
// remove newfd if exists in filemap silently
if(exist(newfd)) {
remove(newfd);
}
// to prevent duplicate fd idx in the future. First three fd are reservered
// by os streams that we do not overwrite
if(get_fd_idx() < newfd && newfd != 0 && newfd != 1 && newfd != 2)
fd_validation_needed = true;
files_.insert(make_pair(newfd, open_file));
return newfd;
}
int
OpenFileMap::generate_fd_idx() {
// We need a mutex here for thread safety
std::lock_guard<std::mutex> inode_lock(fd_idx_mutex);
if(fd_idx == std::numeric_limits<int>::max()) {
LOG(WARNING,
"File descriptor index exceeded ints max value. Setting it back to 100000");
/*
* Setting fd_idx back to 3 could have the effect that fd are given
* twice for different path. This must not happen. Instead a flag is set
* which tells can tell the OpenFileMap that it should check if this fd
* is really safe to use.
*/
fd_idx = 100000;
fd_validation_needed = true;
}
return fd_idx++;
}
int
OpenFileMap::get_fd_idx() {
std::lock_guard<std::mutex> inode_lock(fd_idx_mutex);
return fd_idx;
}
} // namespace gkfs::filemap