//------------------------------------------------------------------------------ //! @file FmdAttr.hh //! @author Abhishek Lekshmanan - CERN //------------------------------------------------------------------------------ /************************************************************************ * EOS - the CERN Disk Storage System * * Copyright (C) 2022 CERN/Switzerland * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program 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 General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* ************************************************************************/ #include "FmdAttr.hh" #include "FmdHandler.hh" #include "fst/io/local/FsIo.hh" #include "fst/XrdFstOfs.hh" #include "fst/utils/FTSWalkTree.hh" #include "fst/utils/FSPathHandler.hh" #include "fst/utils/TransformAttr.hh" #include EOSFSTNAMESPACE_BEGIN //------------------------------------------------------------------------------ // Constructor //------------------------------------------------------------------------------ FmdAttrHandler::FmdAttrHandler(std::unique_ptr&& _FSPathHandler) : mFSPathHandler(std::move(_FSPathHandler)) {} //------------------------------------------------------------------------------ // Low level Fmd retrieve method //------------------------------------------------------------------------------ std::pair FmdAttrHandler::LocalRetrieveFmd(eos::common::FileId::fileid_t fid, eos::common::FileSystem::fsid_t fsid, const std::string& path) { if (path.empty()) { return LocalRetrieveFmd(mFSPathHandler->GetPath(fid, fsid)); } else { return LocalRetrieveFmd(path); } } //------------------------------------------------------------------------------ // Low level Fmd retrieve method by path //------------------------------------------------------------------------------ std::pair FmdAttrHandler::LocalRetrieveFmd(const std::string& path) { FsIo localIo {path}; std::string attrval; int result = localIo.attrGet(gFmdAttrName, attrval); if (result != 0) { eos_debug("msg=\"failed to retrieve fmd attribute\" path=\"%s\" errno=%d", path.c_str(), errno); return {false, eos::common::FmdHelper{}}; } eos::common::FmdHelper fmd; bool status = fmd.mProtoFmd.ParsePartialFromString(attrval); if (!status) { eos_err("msg=\"failed parsing fmd attribute\" attr_sz=%lu", attrval.size()); } return {status, std::move(fmd)}; } //------------------------------------------------------------------------------ // Set Fmd xattr for the given file identifier //------------------------------------------------------------------------------ bool FmdAttrHandler::LocalPutFmd(const eos::common::FmdHelper& fmd, eos::common::FileId::fileid_t fid, eos::common::FileSystem::fsid_t fsid, const std::string& path) { if (path.empty()) { return LocalPutFmd(fmd, mFSPathHandler->GetPath(fid, fsid)); } else { return LocalPutFmd(fmd, path); } } //------------------------------------------------------------------------------ // Set Fmd xattr for the corresponding file path //------------------------------------------------------------------------------ bool FmdAttrHandler::LocalPutFmd(const eos::common::FmdHelper& fmd, const std::string& path) { FsIo localio {path}; struct stat info; if (localio.fileStat(&info)) { eos_err("msg=\"file not existing\" path=\"%s\"", path.c_str()); return false; } std::string attrval; fmd.mProtoFmd.SerializePartialToString(&attrval); int rc = localio.attrSet(gFmdAttrName, attrval.c_str(), attrval.length()); if (rc != 0) { eos_err("msg=\"failed to set xattr\" path=\"%s\" errno=%d", path.c_str(), errno); } return rc == 0; } //------------------------------------------------------------------------------ // Delete Fmd xattr for the corresponding file identifier //------------------------------------------------------------------------------ void FmdAttrHandler::LocalDeleteFmd(eos::common::FileId::fileid_t fid, eos::common::FileSystem::fsid_t fsid, bool drop_file) { return LocalDeleteFmd(mFSPathHandler->GetPath(fid, fsid), drop_file); } //------------------------------------------------------------------------------ // Delete Fmd xattr for the corresponding file path //------------------------------------------------------------------------------ void FmdAttrHandler::LocalDeleteFmd(const std::string& path, bool drop_file) { FsIo localio {path}; if (drop_file) { int rc = localio.fileRemove(); if (rc && errno != ENOENT) { eos_err("Failed to drop file at path=%s, errno=%d", path.c_str(), errno) } return; } if (int rc = localio.attrDelete(gFmdAttrName); rc != 0) { if (errno == ENOATTR || errno == ENOENT) { return; } eos_err("Failed to Delete Fmd Attribute at path:%s, rc=%d", path.c_str(), errno); } } bool FmdAttrHandler::Commit(eos::common::FmdHelper* fmd, bool lockit, std::string* path) { struct timeval tv; struct timezone tz; gettimeofday(&tv, &tz); fmd->mProtoFmd.set_mtime(tv.tv_sec); fmd->mProtoFmd.set_atime(tv.tv_sec); fmd->mProtoFmd.set_mtime_ns(tv.tv_usec * 1000); fmd->mProtoFmd.set_atime_ns(tv.tv_usec * 1000); if (path != nullptr) { return LocalPutFmd(*fmd, *path); } return LocalPutFmd(*fmd, fmd->mProtoFmd.fid(), fmd->mProtoFmd.fsid()); } std::unique_ptr FmdAttrHandler::LocalGetFmd(eos::common::FileId::fileid_t fid, eos::common::FileSystem::fsid_t fsid, bool force_retrieve, bool do_create, uid_t uid, gid_t gid, eos::common::LayoutId::layoutid_t layoutid) { auto [status, _fmd] = LocalRetrieveFmd(fid, fsid); if (!status && !do_create) { eos_warning("msg=\"no fmd record found\" fid=%08llx fsid=%lu", fid, fsid); return nullptr; } // Check the various conditions if we have a fmd attr already if (status) { auto fmd = std::make_unique(std::move(_fmd.mProtoFmd)); if ((fmd->mProtoFmd.fid() != fid) || (fmd->mProtoFmd.fsid() != fsid)) { eos_crit("msg=\"mismatch between requested fid/fsid and retrieved ones\" " "fxid=%08llx retrieved_fxid=%08llx fsid=%lu retrieved_fsid=%lu", fid, fmd->mProtoFmd.fid(), fsid, fmd->mProtoFmd.fsid()); if (!force_retrieve) { return nullptr; } } if (force_retrieve) { return fmd; } if (!eos::common::LayoutId::IsRain(fmd->mProtoFmd.lid())) { if (!do_create && ((fmd->mProtoFmd.disksize() && (fmd->mProtoFmd.disksize() != eos::common::FmdHelper::UNDEF) && (fmd->mProtoFmd.disksize() != fmd->mProtoFmd.size())) || (fmd->mProtoFmd.mgmsize() && (fmd->mProtoFmd.mgmsize() != eos::common::FmdHelper::UNDEF) && (fmd->mProtoFmd.mgmsize() != fmd->mProtoFmd.size())))) { eos_crit("msg=\"size mismatch disk/mgm vs memory\" fxid=%08llx " "fsid=%lu size=%llu disksize=%llu mgmsize=%llu", fid, (unsigned long) fsid, fmd->mProtoFmd.size(), fmd->mProtoFmd.disksize(), fmd->mProtoFmd.mgmsize()); return nullptr; } if (!do_create && ((fmd->mProtoFmd.filecxerror() == 1) || (fmd->mProtoFmd.mgmchecksum().length() && (fmd->mProtoFmd.mgmchecksum() != fmd->mProtoFmd.checksum())))) { eos_crit("msg=\"checksum error flagged/detected\" fxid=%08llx " "fsid=%lu checksum=%s diskchecksum=%s mgmchecksum=%s " "filecxerror=%d blockcxerror=%d", fid, (unsigned long) fsid, fmd->mProtoFmd.checksum().c_str(), fmd->mProtoFmd.diskchecksum().c_str(), fmd->mProtoFmd.mgmchecksum().c_str(), fmd->mProtoFmd.filecxerror(), fmd->mProtoFmd.blockcxerror()); } } else {//Non Rain if (fmd->mProtoFmd.blockcxerror() == 1) { eos_crit("msg=\"blockxs error detected\" fxid=%08llx fsid=%lu", fid, fsid); return nullptr; } } return fmd; } // status || force_retrieve // Creating an fmd auto fmd = make_unique(); fmd->mProtoFmd.set_uid(uid); fmd->mProtoFmd.set_gid(gid); fmd->mProtoFmd.set_lid(layoutid); fmd->mProtoFmd.set_fsid(fsid); fmd->mProtoFmd.set_fid(fid); struct timeval tv; struct timezone tz; gettimeofday(&tv, &tz); fmd->mProtoFmd.set_ctime(tv.tv_sec); fmd->mProtoFmd.set_ctime_ns(tv.tv_usec * 1000); if (Commit(fmd.get(), false)) { eos_debug("msg=\"return fmd object\" fid=%08llx fsid=%lu", fid, fsid); return fmd; } eos_crit("msg=\"failed to commit fmd to storage\" fid=%08llx fsid=%lu", fid, fsid); return nullptr; } bool FmdAttrHandler::ResetDiskInformation(eos::common::FileSystem::fsid_t fsid) { std::error_code ec; WalkFSTree(mFSPathHandler->GetFSPath(fsid), [](std::string path) { TransformAttr(path, gFmdAttrName, &FmdHandler::ResetFmdDiskInfo); }, ec); if (ec) { eos_err("msg=\"Failed to walk FST Tree\" error=%s", ec.message().c_str()); } return !ec; } bool FmdAttrHandler::ResetMgmInformation(eos::common::FileSystem::fsid_t fsid) { std::error_code ec; WalkFSTree(mFSPathHandler->GetFSPath(fsid), [](std::string path) { TransformAttr(path, gFmdAttrName, &FmdHandler::ResetFmdMgmInfo); }, ec); if (ec) { eos_err("msg=\"Failed to walk FST Tree\" error=%s", ec.message().c_str()); } return !ec; } EOSFSTNAMESPACE_END