1011 lines
31 KiB
C
1011 lines
31 KiB
C
#include <app/config/Config.h>
|
|
#include <app/log/Logger.h>
|
|
#include <app/App.h>
|
|
#include <common/nodes/MirrorBuddyGroupMapper.h>
|
|
#include <common/nodes/TargetMapper.h>
|
|
#include <common/nodes/TargetStateStore.h>
|
|
#include <common/system/System.h>
|
|
#include <common/toolkit/ackstore/AcknowledgmentStore.h>
|
|
#include <common/toolkit/NetFilter.h>
|
|
#include <common/toolkit/Time.h>
|
|
#include <components/AckManager.h>
|
|
#include <components/DatagramListener.h>
|
|
#include <components/Flusher.h>
|
|
#include <components/InternodeSyncer.h>
|
|
#include <filesystem/FhgfsOpsPages.h>
|
|
#include <filesystem/FhgfsOpsInode.h>
|
|
#include <net/filesystem/FhgfsOpsCommKit.h>
|
|
#include <net/filesystem/FhgfsOpsRemoting.h>
|
|
#include <nodes/NodeStoreEx.h>
|
|
#include <toolkit/InodeRefStore.h>
|
|
#include <toolkit/NoAllocBufferStore.h>
|
|
#include <toolkit/StatFsCache.h>
|
|
|
|
// REMOVEME
|
|
#include <common/toolkit/Random.h>
|
|
|
|
#include <linux/xattr.h>
|
|
|
|
#ifndef BEEGFS_VERSION
|
|
#error BEEGFS_VERSION undefined
|
|
#endif
|
|
|
|
/**
|
|
* @param mountConfig belongs to the app afterwards (and will automatically be destructed
|
|
* by the app)
|
|
*/
|
|
void App_init(App* this, MountConfig* mountConfig)
|
|
{
|
|
this->mountConfig = mountConfig;
|
|
|
|
this->appResult = APPCODE_NO_ERROR;
|
|
|
|
this->connRetriesEnabled = true;
|
|
this->netBenchModeEnabled = false;
|
|
|
|
this->cfg = NULL;
|
|
this->netFilter = NULL;
|
|
this->tcpOnlyFilter = NULL;
|
|
this->logger = NULL;
|
|
this->fsUUID = NULL;
|
|
StrCpyList_init(&this->allowedInterfaces);
|
|
StrCpyList_init(&this->allowedRDMAInterfaces);
|
|
UInt16List_init(&this->preferredMetaNodes);
|
|
UInt16List_init(&this->preferredStorageTargets);
|
|
this->cacheBufStore = NULL;
|
|
this->pathBufStore = NULL;
|
|
this->msgBufStore = NULL;
|
|
this->ackStore = NULL;
|
|
this->inodeRefStore = NULL;
|
|
this->statfsCache = NULL;
|
|
this->localNode = NULL;
|
|
this->mgmtNodes = NULL;
|
|
this->metaNodes = NULL;
|
|
this->storageNodes = NULL;
|
|
this->targetMapper = NULL;
|
|
this->storageBuddyGroupMapper = NULL;
|
|
this->metaBuddyGroupMapper = NULL;
|
|
this->targetStateStore = NULL;
|
|
this->metaStateStore = NULL;
|
|
|
|
this->dgramListener = NULL;
|
|
this->internodeSyncer = NULL;
|
|
this->ackManager = NULL;
|
|
this->flusher = NULL;
|
|
|
|
this->fileInodeOps = NULL;
|
|
this->symlinkInodeOps = NULL;
|
|
this->dirInodeOps = NULL;
|
|
this->specialInodeOps = NULL;
|
|
|
|
Mutex_init(&this->nicListMutex);
|
|
Mutex_init(&this->fsUUIDMutex);
|
|
|
|
#ifdef BEEGFS_DEBUG
|
|
Mutex_init(&this->debugCounterMutex);
|
|
|
|
this->numRPCs = 0;
|
|
this->numRemoteReads = 0;
|
|
this->numRemoteWrites = 0;
|
|
#endif // BEEGFS_DEBUG
|
|
|
|
}
|
|
|
|
void App_uninit(App* this)
|
|
{
|
|
SAFE_DESTRUCT(this->flusher, Flusher_destruct);
|
|
SAFE_DESTRUCT(this->ackManager, AckManager_destruct);
|
|
SAFE_DESTRUCT(this->internodeSyncer, InternodeSyncer_destruct);
|
|
SAFE_DESTRUCT(this->dgramListener, DatagramListener_destruct);
|
|
|
|
SAFE_DESTRUCT(this->storageNodes, NodeStoreEx_destruct);
|
|
SAFE_DESTRUCT(this->metaNodes, NodeStoreEx_destruct);
|
|
SAFE_DESTRUCT(this->mgmtNodes, NodeStoreEx_destruct);
|
|
|
|
if(this->logger)
|
|
Logger_setAllLogLevels(this->logger, LOG_NOTHING); // disable logging
|
|
|
|
SAFE_DESTRUCT(this->localNode, Node_put);
|
|
SAFE_DESTRUCT(this->targetMapper, TargetMapper_destruct);
|
|
SAFE_DESTRUCT(this->storageBuddyGroupMapper, MirrorBuddyGroupMapper_destruct);
|
|
SAFE_DESTRUCT(this->metaBuddyGroupMapper, MirrorBuddyGroupMapper_destruct);
|
|
SAFE_DESTRUCT(this->metaStateStore, TargetStateStore_destruct);
|
|
SAFE_DESTRUCT(this->targetStateStore, TargetStateStore_destruct);
|
|
SAFE_DESTRUCT(this->statfsCache, StatFsCache_destruct);
|
|
SAFE_DESTRUCT(this->inodeRefStore, InodeRefStore_destruct);
|
|
SAFE_DESTRUCT(this->ackStore, AcknowledgmentStore_destruct);
|
|
SAFE_DESTRUCT(this->msgBufStore, NoAllocBufferStore_destruct);
|
|
SAFE_DESTRUCT(this->pathBufStore, NoAllocBufferStore_destruct);
|
|
SAFE_DESTRUCT(this->cacheBufStore, NoAllocBufferStore_destruct);
|
|
UInt16List_uninit(&this->preferredStorageTargets);
|
|
UInt16List_uninit(&this->preferredMetaNodes);
|
|
StrCpyList_uninit(&this->allowedInterfaces);
|
|
StrCpyList_uninit(&this->allowedRDMAInterfaces);
|
|
SAFE_DESTRUCT(this->logger, Logger_destruct);
|
|
SAFE_DESTRUCT(this->tcpOnlyFilter, NetFilter_destruct);
|
|
SAFE_DESTRUCT(this->netFilter, NetFilter_destruct);
|
|
SAFE_DESTRUCT(this->cfg, Config_destruct);
|
|
|
|
AtomicInt_uninit(&this->lockAckAtomicCounter);
|
|
|
|
SAFE_DESTRUCT(this->mountConfig, MountConfig_destruct);
|
|
|
|
ListTk_kfreeNicAddressListElems(&this->rdmaNicList);
|
|
NicAddressList_uninit(&this->rdmaNicList);
|
|
|
|
kfree(this->fileInodeOps);
|
|
kfree(this->symlinkInodeOps);
|
|
kfree(this->dirInodeOps);
|
|
kfree(this->specialInodeOps);
|
|
|
|
Mutex_uninit(&this->nicListMutex);
|
|
|
|
#ifdef BEEGFS_DEBUG
|
|
Mutex_uninit(&this->debugCounterMutex);
|
|
#endif // BEEGFS_DEBUG
|
|
}
|
|
|
|
int App_run(App* this)
|
|
{
|
|
|
|
printk_fhgfs(KERN_INFO, "Built "
|
|
#ifdef BEEGFS_NVFS
|
|
"with"
|
|
#else
|
|
"without"
|
|
#endif
|
|
" NVFS RDMA support.\n");
|
|
|
|
// init data objects & storage
|
|
|
|
if(!__App_initDataObjects(this, this->mountConfig) )
|
|
{
|
|
printk_fhgfs(KERN_WARNING,
|
|
"Configuration error: Initialization of common objects failed. "
|
|
"(Log file may provide additional information.)\n");
|
|
this->appResult = APPCODE_INVALID_CONFIG;
|
|
return this->appResult;
|
|
}
|
|
|
|
if(!__App_initInodeOperations(this) )
|
|
{
|
|
printk_fhgfs(KERN_WARNING, "Initialization of inode operations failed.");
|
|
this->appResult = APPCODE_INITIALIZATION_ERROR;
|
|
return this->appResult;
|
|
}
|
|
|
|
|
|
// init components
|
|
|
|
if(!__App_initComponents(this) )
|
|
{
|
|
printk_fhgfs(KERN_WARNING, "Component initialization error. "
|
|
"(Log file may provide additional information.)\n");
|
|
this->appResult = APPCODE_INITIALIZATION_ERROR;
|
|
return this->appResult;
|
|
}
|
|
|
|
__App_logInfos(this);
|
|
|
|
|
|
// start components
|
|
|
|
__App_startComponents(this);
|
|
|
|
// Note: We wait some ms for the node downloads here because the kernel would like to
|
|
// check the properties of the root directory directly after mount.
|
|
|
|
InternodeSyncer_waitForMgmtInit(this->internodeSyncer, 1000);
|
|
|
|
if(!__App_mountServerCheck(this) )
|
|
{ // mount check failed => cancel mount
|
|
printk_fhgfs(KERN_WARNING, "Mount sanity check failed. Canceling mount. "
|
|
"(Log file may provide additional information. Check can be disabled with "
|
|
"sysMountSanityCheckMS=0 in the config file.)\n");
|
|
this->appResult = APPCODE_INITIALIZATION_ERROR;
|
|
|
|
return this->appResult;
|
|
}
|
|
|
|
// mark: mount succeeded if we got here!
|
|
|
|
return this->appResult;
|
|
}
|
|
|
|
void App_stop(App* this)
|
|
{
|
|
const char* logContext = "App (stop)";
|
|
|
|
// note: be careful, because we don't know what has been succesfully initialized!
|
|
|
|
// note: this can also be called from App_run() to cancel a mount!
|
|
|
|
if(this->cfg)
|
|
{
|
|
__App_stopComponents(this);
|
|
|
|
if(!Config_getConnUnmountRetries(this->cfg) )
|
|
this->connRetriesEnabled = false;
|
|
|
|
// wait for termination
|
|
__App_joinComponents(this);
|
|
|
|
if(this->logger)
|
|
Logger_log(this->logger, 1, logContext, "All components stopped.");
|
|
}
|
|
}
|
|
|
|
bool __App_initDataObjects(App* this, MountConfig* mountConfig)
|
|
{
|
|
const char* logContext = "App (init data objects)";
|
|
|
|
char* interfacesFilename;
|
|
char* rdmaInterfacesFilename;
|
|
char* preferredMetaFile;
|
|
char* preferredStorageFile;
|
|
size_t numCacheBufs;
|
|
size_t cacheBufSize;
|
|
size_t numPathBufs;
|
|
size_t pathBufsSize;
|
|
size_t numMsgBufs;
|
|
size_t msgBufsSize;
|
|
char* interfacesList;
|
|
|
|
AtomicInt_init(&this->lockAckAtomicCounter, 0);
|
|
|
|
this->cfg = Config_construct(mountConfig);
|
|
if(!this->cfg)
|
|
return false;
|
|
|
|
|
|
if(!StringTk_hasLength(Config_getSysMgmtdHost(this->cfg) ) )
|
|
{
|
|
printk_fhgfs(KERN_WARNING, "Management host undefined\n");
|
|
return false;
|
|
}
|
|
|
|
{ // load net filter (required before any connection can be made, incl. local conns)
|
|
const char* netFilterFile = Config_getConnNetFilterFile(this->cfg);
|
|
|
|
this->netFilter = NetFilter_construct(netFilterFile);
|
|
if(!this->netFilter)
|
|
return false;
|
|
}
|
|
|
|
{ // load tcp-only filter (required before any connection can be made, incl. local conns)
|
|
const char* tcpOnlyFilterFile = Config_getConnTcpOnlyFilterFile(this->cfg);
|
|
|
|
this->tcpOnlyFilter = NetFilter_construct(tcpOnlyFilterFile);
|
|
if(!this->tcpOnlyFilter)
|
|
return false;
|
|
}
|
|
|
|
// logger (+ hostname as initial clientID, real ID will be set below)
|
|
this->logger = Logger_construct(this, this->cfg);
|
|
if(Config_getLogClientID(this->cfg) )
|
|
{
|
|
const char* hostnameCopy = System_getHostnameCopy();
|
|
Logger_setClientID(this->logger, hostnameCopy);
|
|
kfree(hostnameCopy);
|
|
}
|
|
|
|
|
|
// load allowed interface list
|
|
interfacesList = Config_getConnInterfacesList(this->cfg);
|
|
if (StringTk_hasLength(interfacesList) )
|
|
StringTk_explode(interfacesList, ',', &this->allowedInterfaces);
|
|
else
|
|
{
|
|
// load allowed interface file
|
|
interfacesFilename = Config_getConnInterfacesFile(this->cfg);
|
|
if(strlen(interfacesFilename) &&
|
|
!Config_loadStringListFile(interfacesFilename, &this->allowedInterfaces) )
|
|
{
|
|
Logger_logErrFormatted(this->logger, logContext,
|
|
"Unable to load configured interfaces file: %s", interfacesFilename);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// load allowed RDMA interface file
|
|
rdmaInterfacesFilename = Config_getConnRDMAInterfacesFile(this->cfg);
|
|
if(strlen(rdmaInterfacesFilename) &&
|
|
!Config_loadStringListFile(rdmaInterfacesFilename, &this->allowedRDMAInterfaces) )
|
|
{
|
|
Logger_logErrFormatted(this->logger, logContext,
|
|
"Unable to load configured RDMA interfaces file: %s", rdmaInterfacesFilename);
|
|
return false;
|
|
}
|
|
|
|
// load preferred nodes files
|
|
preferredMetaFile = Config_getTunePreferredMetaFile(this->cfg);
|
|
if(strlen(preferredMetaFile) &&
|
|
!Config_loadUInt16ListFile(this->cfg, preferredMetaFile, &this->preferredMetaNodes) )
|
|
{
|
|
Logger_logErrFormatted(this->logger, logContext,
|
|
"Unable to load configured preferred meta nodes file: %s", preferredMetaFile);
|
|
return false;
|
|
}
|
|
|
|
preferredStorageFile = Config_getTunePreferredStorageFile(this->cfg);
|
|
if(strlen(preferredStorageFile) &&
|
|
!Config_loadUInt16ListFile(this->cfg, preferredStorageFile, &this->preferredStorageTargets) )
|
|
{
|
|
Logger_logErrFormatted(this->logger, logContext,
|
|
"Unable to load configured preferred storage nodes file: %s", preferredStorageFile);
|
|
return false;
|
|
}
|
|
|
|
// init stores, queues etc.
|
|
|
|
this->targetMapper = TargetMapper_construct();
|
|
|
|
this->storageBuddyGroupMapper = MirrorBuddyGroupMapper_construct();
|
|
|
|
this->metaBuddyGroupMapper = MirrorBuddyGroupMapper_construct();
|
|
|
|
this->targetStateStore = TargetStateStore_construct();
|
|
|
|
this->metaStateStore = TargetStateStore_construct();
|
|
|
|
this->mgmtNodes = NodeStoreEx_construct(this, NODETYPE_Mgmt);
|
|
|
|
this->metaNodes = NodeStoreEx_construct(this, NODETYPE_Meta);
|
|
|
|
this->storageNodes = NodeStoreEx_construct(this, NODETYPE_Storage);
|
|
|
|
if(!__App_initLocalNodeInfo(this) )
|
|
return false;
|
|
|
|
if(Config_getLogClientID(this->cfg) )
|
|
{ // set real clientID
|
|
NodeString alias;
|
|
Node_copyAlias(this->localNode, &alias);
|
|
Logger_setClientID(this->logger, alias.buf);
|
|
}
|
|
|
|
// prealloc buffers
|
|
|
|
switch(Config_getTuneFileCacheTypeNum(this->cfg) )
|
|
{
|
|
case FILECACHETYPE_Buffered:
|
|
numCacheBufs = Config_getTuneFileCacheBufNum(this->cfg);
|
|
break;
|
|
|
|
default:
|
|
numCacheBufs = 0;
|
|
break;
|
|
}
|
|
|
|
cacheBufSize = Config_getTuneFileCacheBufSize(this->cfg);
|
|
|
|
this->cacheBufStore = NoAllocBufferStore_construct(numCacheBufs, cacheBufSize);
|
|
if(!this->cacheBufStore)
|
|
return false;
|
|
|
|
numPathBufs = Config_getTunePathBufNum(this->cfg);
|
|
pathBufsSize = Config_getTunePathBufSize(this->cfg);
|
|
|
|
this->pathBufStore = NoAllocBufferStore_construct(numPathBufs, pathBufsSize);
|
|
if(!this->pathBufStore)
|
|
return false;
|
|
|
|
numMsgBufs = Config_getTuneMsgBufNum(this->cfg);
|
|
msgBufsSize = Config_getTuneMsgBufSize(this->cfg);
|
|
|
|
this->msgBufStore = NoAllocBufferStore_construct(numMsgBufs, msgBufsSize);
|
|
|
|
this->ackStore = AcknowledgmentStore_construct();
|
|
|
|
this->inodeRefStore = InodeRefStore_construct();
|
|
|
|
this->statfsCache = StatFsCache_construct(this);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Initialized the inode_operations structs depending on what features have been enabled in
|
|
* the config.
|
|
*/
|
|
bool __App_initInodeOperations(App* this)
|
|
{
|
|
Config* cfg = App_getConfig(this);
|
|
|
|
this->fileInodeOps = os_kzalloc(sizeof(struct inode_operations) );
|
|
this->symlinkInodeOps = os_kzalloc(sizeof(struct inode_operations) );
|
|
this->dirInodeOps = os_kzalloc(sizeof(struct inode_operations) );
|
|
this->specialInodeOps = os_kzalloc(sizeof(struct inode_operations) );
|
|
|
|
if (!this->fileInodeOps || !this->symlinkInodeOps ||
|
|
!this->dirInodeOps || !this->specialInodeOps)
|
|
{
|
|
SAFE_KFREE(this->fileInodeOps);
|
|
SAFE_KFREE(this->symlinkInodeOps);
|
|
SAFE_KFREE(this->dirInodeOps);
|
|
SAFE_KFREE(this->specialInodeOps);
|
|
|
|
return false;
|
|
}
|
|
|
|
this->fileInodeOps->getattr = FhgfsOps_getattr;
|
|
this->fileInodeOps->permission = FhgfsOps_permission;
|
|
this->fileInodeOps->setattr = FhgfsOps_setattr;
|
|
|
|
#ifdef KERNEL_HAS_GENERIC_READLINK
|
|
this->symlinkInodeOps->readlink = generic_readlink; // default is fine for us currently
|
|
#endif
|
|
#ifdef KERNEL_HAS_GET_LINK
|
|
this->symlinkInodeOps->get_link = FhgfsOps_get_link;
|
|
#else
|
|
this->symlinkInodeOps->follow_link = FhgfsOps_follow_link;
|
|
this->symlinkInodeOps->put_link = FhgfsOps_put_link;
|
|
#endif
|
|
this->symlinkInodeOps->getattr = FhgfsOps_getattr;
|
|
this->symlinkInodeOps->permission = FhgfsOps_permission;
|
|
this->symlinkInodeOps->setattr = FhgfsOps_setattr;
|
|
|
|
#ifdef KERNEL_HAS_ATOMIC_OPEN
|
|
#ifdef BEEGFS_ENABLE_ATOMIC_OPEN
|
|
this->dirInodeOps->atomic_open = FhgfsOps_atomicOpen;
|
|
#endif // BEEGFS_ENABLE_ATOMIC_OPEN
|
|
#endif
|
|
this->dirInodeOps->lookup = FhgfsOps_lookupIntent;
|
|
this->dirInodeOps->create = FhgfsOps_createIntent;
|
|
this->dirInodeOps->link = FhgfsOps_link;
|
|
this->dirInodeOps->unlink = FhgfsOps_unlink;
|
|
this->dirInodeOps->mknod = FhgfsOps_mknod;
|
|
this->dirInodeOps->symlink = FhgfsOps_symlink;
|
|
this->dirInodeOps->mkdir = FhgfsOps_mkdir;
|
|
this->dirInodeOps->rmdir = FhgfsOps_rmdir;
|
|
this->dirInodeOps->rename = FhgfsOps_rename;
|
|
this->dirInodeOps->getattr = FhgfsOps_getattr;
|
|
this->dirInodeOps->permission = FhgfsOps_permission;
|
|
this->dirInodeOps->setattr = FhgfsOps_setattr;
|
|
|
|
this->specialInodeOps->setattr = FhgfsOps_setattr;
|
|
|
|
if (Config_getSysXAttrsEnabled(cfg) )
|
|
{
|
|
this->fileInodeOps->listxattr = FhgfsOps_listxattr;
|
|
this->dirInodeOps->listxattr = FhgfsOps_listxattr;
|
|
|
|
#ifdef KERNEL_HAS_GENERIC_GETXATTR
|
|
this->fileInodeOps->getxattr = generic_getxattr;
|
|
this->fileInodeOps->removexattr = FhgfsOps_removexattr;
|
|
this->fileInodeOps->setxattr = generic_setxattr;
|
|
|
|
this->dirInodeOps->getxattr = generic_getxattr;
|
|
this->dirInodeOps->removexattr = FhgfsOps_removexattr;
|
|
this->dirInodeOps->setxattr = generic_setxattr;
|
|
#endif
|
|
|
|
if (Config_getSysACLsEnabled(cfg) )
|
|
{
|
|
#if defined(KERNEL_HAS_SET_ACL) || defined(KERNEL_HAS_SET_ACL_DENTRY)
|
|
this->fileInodeOps->set_acl = FhgfsOps_set_acl;
|
|
this->dirInodeOps->set_acl = FhgfsOps_set_acl;
|
|
/* Note: symlinks don't have ACLs
|
|
* The get_acl() operation was introduced as get_inode_acl() in the struct inode_operations in Linux 6.2
|
|
*/
|
|
#if defined(KERNEL_HAS_GET_ACL)
|
|
this->fileInodeOps->get_acl = FhgfsOps_get_acl;
|
|
this->dirInodeOps->get_acl = FhgfsOps_get_acl;
|
|
#endif
|
|
#if defined(KERNEL_HAS_GET_INODE_ACL)
|
|
this->fileInodeOps->get_inode_acl = FhgfsOps_get_inode_acl;
|
|
this->dirInodeOps->get_inode_acl = FhgfsOps_get_inode_acl;
|
|
#endif
|
|
#else
|
|
Logger_logErr(this->logger, "Init inode operations",
|
|
"ACLs activated in config, but the signature inode->i_op->set_acl()"
|
|
"not supported on this kernel version.");
|
|
return false;
|
|
#endif // KERNEL_HAS_SET_ACL or KERNEL_HAS_SET_ACL_DENTRY
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Retrieve NICs for the local node.
|
|
*
|
|
* @param nicList an uninitialized NicAddressList. Caller is responsible for
|
|
* memory management.
|
|
*/
|
|
void App_cloneLocalNicList(App* this, NicAddressList* nicList)
|
|
{
|
|
Node_cloneNicList(this->localNode, nicList);
|
|
}
|
|
|
|
void App_updateLocalInterfaces(App* this, NicAddressList* nicList)
|
|
{
|
|
NicAddressList rdmaNicList;
|
|
NicListCapabilities nicCaps;
|
|
NodeStoreEx* stores[] = {
|
|
this->mgmtNodes, this->metaNodes, this->storageNodes, NULL
|
|
};
|
|
int i;
|
|
|
|
App_findAllowedRDMAInterfaces(this, nicList, &rdmaNicList);
|
|
|
|
Mutex_lock(&this->nicListMutex); // L O C K
|
|
|
|
ListTk_kfreeNicAddressListElems(&this->rdmaNicList);
|
|
NicAddressList_uninit(&this->rdmaNicList);
|
|
ListTk_cloneNicAddressList(&rdmaNicList, &this->rdmaNicList, true);
|
|
|
|
Mutex_unlock(&this->nicListMutex); // U N L O C K
|
|
|
|
NIC_supportedCapabilities(nicList, &nicCaps);
|
|
Node_updateInterfaces(this->localNode, Node_getPortUDP(this->localNode),
|
|
Node_getPortTCP(this->localNode), nicList);
|
|
Node_updateLocalInterfaces(this->localNode, nicList, &nicCaps, NULL);
|
|
|
|
for (i = 0; stores[i] != NULL; ++i)
|
|
{
|
|
NodeStoreEx* store = stores[i];
|
|
Node* node;
|
|
|
|
for (node = NodeStoreEx_referenceFirstNode(store); node != NULL;
|
|
node = NodeStoreEx_referenceNextNodeAndReleaseOld(store, node))
|
|
{
|
|
int nodeType = Node_getNodeType(node);
|
|
Node_updateLocalInterfaces(node, nicList, &nicCaps,
|
|
nodeType == NODETYPE_Meta || nodeType == NODETYPE_Storage? &rdmaNicList : NULL);
|
|
}
|
|
|
|
}
|
|
ListTk_kfreeNicAddressListElems(&rdmaNicList);
|
|
NicAddressList_uninit(&rdmaNicList);
|
|
}
|
|
|
|
/**
|
|
* Retrieve file system UUID for the mounted BeeGFS.
|
|
*
|
|
* @return a pointer to a copy of the file system UUID. Must be freed by the caller.
|
|
*/
|
|
char* App_cloneFsUUID(App* this)
|
|
{
|
|
char* fsUUID;
|
|
Mutex_lock(&this->fsUUIDMutex);
|
|
fsUUID = StringTk_strDup(this->fsUUID);
|
|
Mutex_unlock(&this->fsUUIDMutex);
|
|
|
|
return fsUUID;
|
|
}
|
|
|
|
/**
|
|
* Update file system UUID for the mounted BeeGFS.
|
|
*
|
|
* @param fsUUID will be cloned and stored in the app object so original pointer can be freed.
|
|
*/
|
|
void App_updateFsUUID(App* this, const char* fsUUID)
|
|
{
|
|
Mutex_lock(&this->fsUUIDMutex);
|
|
this->fsUUID = StringTk_strDup(fsUUID);
|
|
Mutex_unlock(&this->fsUUIDMutex);
|
|
}
|
|
|
|
/**
|
|
* Populate nicList with the allowed and available interfaces.
|
|
*
|
|
* @param nicList uninitialized list to populate. Caller is responsible for memory
|
|
* management
|
|
* @return true if an allowed and available NIC was found. nicList is initialized and
|
|
* contains elements.
|
|
*/
|
|
bool App_findAllowedInterfaces(App* this, NicAddressList* nicList)
|
|
{
|
|
NicAddressList tmpNicList;
|
|
bool useRDMA = Config_getConnUseRDMA(this->cfg);
|
|
bool result;
|
|
|
|
NicAddressList_init(&tmpNicList);
|
|
NIC_findAll(&this->allowedInterfaces, useRDMA, false, &tmpNicList);
|
|
|
|
if(!NicAddressList_length(&tmpNicList) )
|
|
{
|
|
result = false;
|
|
goto exit;
|
|
}
|
|
|
|
// created sorted tmpNicList clone
|
|
ListTk_cloneSortNicAddressList(&tmpNicList, nicList, &this->allowedInterfaces);
|
|
|
|
result = true;
|
|
|
|
exit:
|
|
if (result)
|
|
ListTk_kfreeNicAddressListElems(&tmpNicList);
|
|
NicAddressList_uninit(&tmpNicList);
|
|
return result;
|
|
}
|
|
|
|
void App_cloneLocalRDMANicList(App* this, NicAddressList* rdmaNicList)
|
|
{
|
|
Mutex_lock(&this->nicListMutex); // L O C K
|
|
ListTk_cloneNicAddressList(&this->rdmaNicList, rdmaNicList, true);
|
|
Mutex_unlock(&this->nicListMutex); // U N L O C K
|
|
}
|
|
|
|
void App_findAllowedRDMAInterfaces(App* this, NicAddressList* nicList, NicAddressList* rdmaNicList)
|
|
{
|
|
const char* logContext = "App (find RDMA interfaces)";
|
|
bool useRDMA = Config_getConnUseRDMA(this->cfg);
|
|
if (useRDMA && StrCpyList_length(&this->allowedRDMAInterfaces) > 0)
|
|
{
|
|
NicAddressList tmpList;
|
|
|
|
NicAddressList_init(&tmpList);
|
|
NIC_findAll(&this->allowedRDMAInterfaces, true, true, &tmpList);
|
|
|
|
if(!NicAddressList_length(&tmpList) )
|
|
{
|
|
Logger_logErr(this->logger, logContext, "Couldn't find any filtered and usable outbound RDMA NIC, using any");
|
|
NicAddressList_init(rdmaNicList);
|
|
}
|
|
else
|
|
{
|
|
// created sorted rdmaNicList clone
|
|
ListTk_cloneSortNicAddressList(&tmpList, rdmaNicList, &this->allowedRDMAInterfaces);
|
|
}
|
|
ListTk_kfreeNicAddressListElems(&tmpList);
|
|
NicAddressList_uninit(&tmpList);
|
|
}
|
|
else
|
|
{
|
|
NicAddressList_init(rdmaNicList);
|
|
}
|
|
}
|
|
|
|
bool __App_initLocalNodeInfo(App* this)
|
|
{
|
|
const char* logContext = "App (init local node info)";
|
|
|
|
NicAddressList nicList;
|
|
char* hostname;
|
|
Time now;
|
|
pid_t currentPID;
|
|
char* generatedAlias;
|
|
char* alias;
|
|
|
|
if (!App_findAllowedInterfaces(this, &nicList))
|
|
{
|
|
Logger_logErr(this->logger, logContext, "Couldn't find any usable NIC");
|
|
// required by App_uninit()
|
|
NicAddressList_init(&this->rdmaNicList);
|
|
return false;
|
|
}
|
|
|
|
App_findAllowedRDMAInterfaces(this, &nicList, &this->rdmaNicList);
|
|
|
|
// prepare clientID and create localNode
|
|
Time_setToNowReal(&now);
|
|
hostname = System_getHostnameCopy();
|
|
currentPID = current->pid;
|
|
|
|
// Generate the client alias (formerly nodeID):
|
|
generatedAlias = StringTk_kasprintf("c%llX-%llX-%s",
|
|
(uint64_t)currentPID, (uint64_t)now.tv_sec, hostname);
|
|
|
|
// Truncate the generatedAlias at 32 characters before using it as the nodeID since it will be
|
|
// used as this client's alias by the management, and aliases are limited to 32 characters.
|
|
alias = os_kmalloc(33);
|
|
strncpy(alias, generatedAlias, 32);
|
|
alias[32] = '\0';
|
|
|
|
// note: numeric ID gets initialized with 0; will be set by management later in InternodeSyncer
|
|
this->localNode = Node_construct(this, alias, (NumNodeID){0},
|
|
Config_getConnClientPort(this->cfg), 0, &nicList, NULL);
|
|
|
|
// clean up
|
|
kfree(generatedAlias);
|
|
kfree(alias);
|
|
kfree(hostname);
|
|
|
|
// delete nicList elems
|
|
ListTk_kfreeNicAddressListElems(&nicList);
|
|
NicAddressList_uninit(&nicList);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool __App_initComponents(App* this)
|
|
{
|
|
const char* logContext = "App (init components)";
|
|
|
|
Logger_log(this->logger, Log_DEBUG, logContext, "Initializing components...");
|
|
|
|
this->dgramListener =
|
|
DatagramListener_construct(this, this->localNode, Config_getConnClientPort(this->cfg) );
|
|
if(!this->dgramListener)
|
|
{
|
|
Logger_logErr(this->logger, logContext,
|
|
"Initialization of DatagramListener component failed");
|
|
return false;
|
|
}
|
|
|
|
this->internodeSyncer = InternodeSyncer_construct(this); // (requires dgramlis)
|
|
|
|
this->ackManager = AckManager_construct(this);
|
|
|
|
this->flusher = Flusher_construct(this);
|
|
|
|
Logger_log(this->logger, Log_DEBUG, logContext, "Components initialized.");
|
|
|
|
return true;
|
|
}
|
|
|
|
void __App_startComponents(App* this)
|
|
{
|
|
const char* logContext = "App (start components)";
|
|
|
|
Logger_log(this->logger, Log_DEBUG, logContext, "Starting up components...");
|
|
|
|
Thread_start( (Thread*)this->dgramListener);
|
|
|
|
Thread_start( (Thread*)this->internodeSyncer);
|
|
Thread_start( (Thread*)this->ackManager);
|
|
|
|
if(Config_getTuneFileCacheTypeNum(this->cfg) == FILECACHETYPE_Buffered)
|
|
Thread_start( (Thread*)this->flusher);
|
|
|
|
Logger_log(this->logger, Log_DEBUG, logContext, "Components running.");
|
|
}
|
|
|
|
void __App_stopComponents(App* this)
|
|
{
|
|
const char* logContext = "App (stop components)";
|
|
|
|
if(this->logger)
|
|
Logger_log(this->logger, Log_WARNING, logContext, "Stopping components...");
|
|
|
|
if(this->flusher && Config_getTuneFileCacheTypeNum(this->cfg) == FILECACHETYPE_Buffered)
|
|
Thread_selfTerminate( (Thread*)this->flusher);
|
|
if(this->ackManager)
|
|
Thread_selfTerminate( (Thread*)this->ackManager);
|
|
if(this->internodeSyncer)
|
|
Thread_selfTerminate( (Thread*)this->internodeSyncer);
|
|
|
|
if(this->dgramListener)
|
|
Thread_selfTerminate( (Thread*)this->dgramListener);
|
|
}
|
|
|
|
void __App_joinComponents(App* this)
|
|
{
|
|
const char* logContext = "App (join components)";
|
|
|
|
if(this->logger)
|
|
Logger_log(this->logger, 4, logContext, "Waiting for components to self-terminate...");
|
|
|
|
|
|
if(Config_getTuneFileCacheTypeNum(this->cfg) == FILECACHETYPE_Buffered)
|
|
__App_waitForComponentTermination(this, (Thread*)this->flusher);
|
|
|
|
__App_waitForComponentTermination(this, (Thread*)this->ackManager);
|
|
__App_waitForComponentTermination(this, (Thread*)this->internodeSyncer);
|
|
|
|
__App_waitForComponentTermination(this, (Thread*)this->dgramListener);
|
|
}
|
|
|
|
/**
|
|
* @param component the thread that we're waiting for via join(); may be NULL (in which case this
|
|
* method returns immediately)
|
|
*/
|
|
void __App_waitForComponentTermination(App* this, Thread* component)
|
|
{
|
|
const char* logContext = "App (wait for component termination)";
|
|
|
|
const int timeoutMS = 2000;
|
|
|
|
bool isTerminated;
|
|
|
|
if(!component)
|
|
return;
|
|
|
|
isTerminated = Thread_timedjoin(component, timeoutMS);
|
|
if(!isTerminated)
|
|
{ // print message to show user which thread is blocking
|
|
if(this->logger)
|
|
Logger_logFormatted(this->logger, 2, logContext,
|
|
"Still waiting for this component to stop: %s", Thread_getName(component) );
|
|
|
|
Thread_join(component);
|
|
|
|
if(this->logger)
|
|
Logger_logFormatted(this->logger, 2, logContext,
|
|
"Component stopped: %s", Thread_getName(component) );
|
|
}
|
|
}
|
|
|
|
void __App_logInfos(App* this)
|
|
{
|
|
const char* logContext = "App_logInfos";
|
|
NodeString alias;
|
|
size_t nicListStrLen = 1024;
|
|
char* nicListStr = os_kmalloc(nicListStrLen);
|
|
char* extendedNicListStr = os_kmalloc(nicListStrLen);
|
|
NicAddressList nicList;
|
|
NicAddressListIter nicIter;
|
|
|
|
Node_cloneNicList(this->localNode, &nicList);
|
|
|
|
// print software version (BEEGFS_VERSION)
|
|
Logger_logFormatted(this->logger, 1, logContext, "BeeGFS Client Version: %s", BEEGFS_VERSION);
|
|
|
|
// print debug version info
|
|
LOG_DEBUG(this->logger, 1, logContext, "--DEBUG VERSION--");
|
|
|
|
// print local clientID
|
|
Node_copyAlias(this->localNode, &alias);
|
|
Logger_logFormatted(this->logger, 2, logContext, "ClientID: %s", alias.buf);
|
|
|
|
// list usable network interfaces
|
|
NicAddressListIter_init(&nicIter, &nicList);
|
|
nicListStr[0] = 0;
|
|
extendedNicListStr[0] = 0;
|
|
|
|
for( ; !NicAddressListIter_end(&nicIter); NicAddressListIter_next(&nicIter) )
|
|
{
|
|
const char* nicTypeStr;
|
|
char* nicAddrStr;
|
|
NicAddress* nicAddr = NicAddressListIter_value(&nicIter);
|
|
char* tmpStr = os_kmalloc(nicListStrLen);
|
|
|
|
if(nicAddr->nicType == NICADDRTYPE_RDMA)
|
|
nicTypeStr = "RDMA";
|
|
else
|
|
if(nicAddr->nicType == NICADDRTYPE_STANDARD)
|
|
nicTypeStr = "TCP";
|
|
else
|
|
nicTypeStr = "Unknown";
|
|
|
|
// short NIC info
|
|
snprintf(tmpStr, nicListStrLen, "%s%s(%s) ", nicListStr, nicAddr->name, nicTypeStr);
|
|
strcpy(nicListStr, tmpStr); // tmpStr to avoid writing to a buffer that we're reading
|
|
// from at the same time
|
|
|
|
// extended NIC info
|
|
nicAddrStr = NIC_nicAddrToString(nicAddr);
|
|
snprintf(tmpStr, nicListStrLen, "%s\n+ %s", extendedNicListStr, nicAddrStr);
|
|
strcpy(extendedNicListStr, tmpStr); // tmpStr to avoid writing to a buffer that we're
|
|
// reading from at the same time
|
|
kfree(nicAddrStr);
|
|
|
|
SAFE_KFREE(tmpStr);
|
|
}
|
|
|
|
Logger_logFormatted(this->logger, 2, logContext, "Usable NICs: %s", nicListStr);
|
|
Logger_logFormatted(this->logger, 4, logContext, "Extended list of usable NICs: %s",
|
|
extendedNicListStr);
|
|
|
|
// print net filters
|
|
if(NetFilter_getNumFilterEntries(this->netFilter) )
|
|
{
|
|
Logger_logFormatted(this->logger, Log_WARNING, logContext, "Net filters: %d",
|
|
(int)NetFilter_getNumFilterEntries(this->netFilter) );
|
|
}
|
|
|
|
if(NetFilter_getNumFilterEntries(this->tcpOnlyFilter) )
|
|
{
|
|
Logger_logFormatted(this->logger, Log_WARNING, logContext, "TCP-only filters: %d",
|
|
(int)NetFilter_getNumFilterEntries(this->tcpOnlyFilter) );
|
|
}
|
|
|
|
// print preferred nodes and targets
|
|
|
|
if(UInt16List_length(&this->preferredMetaNodes) )
|
|
{
|
|
Logger_logFormatted(this->logger, Log_WARNING, logContext, "Preferred metadata servers: %d",
|
|
(int)UInt16List_length(&this->preferredMetaNodes) );
|
|
}
|
|
|
|
if(UInt16List_length(&this->preferredStorageTargets) )
|
|
{
|
|
Logger_logFormatted(this->logger, Log_WARNING, logContext, "Preferred storage targets: %d",
|
|
(int)UInt16List_length(&this->preferredStorageTargets) );
|
|
}
|
|
|
|
// Print a warning message if user has enabled ACLs, but no XAttrs (in that case, XAttrs have
|
|
// been auto-enabled which contradicts the config file.)
|
|
if (Config_getSysXAttrsImplicitlyEnabled(this->cfg) )
|
|
{
|
|
Logger_log(this->logger, Log_WARNING, logContext,
|
|
"WARNING: ACLs are enabled, but XAttrs are not. "
|
|
"XAttrs are needed to store ACLs, so they have automatically been enabled. "
|
|
"Please check configuration.");
|
|
}
|
|
|
|
// clean up
|
|
SAFE_KFREE(nicListStr);
|
|
SAFE_KFREE(extendedNicListStr);
|
|
|
|
ListTk_kfreeNicAddressListElems(&nicList);
|
|
NicAddressList_uninit(&nicList);
|
|
|
|
}
|
|
|
|
/**
|
|
* Perform some basic sanity checks to deny mount in case of an error.
|
|
*/
|
|
bool __App_mountServerCheck(App* this)
|
|
{
|
|
const char* logContext = "Mount sanity check";
|
|
Config* cfg = this->cfg;
|
|
|
|
unsigned waitMS = Config_getSysMountSanityCheckMS(cfg);
|
|
|
|
bool retVal = false;
|
|
bool retriesEnabledOrig = this->connRetriesEnabled;
|
|
bool mgmtInitDone;
|
|
FhgfsOpsErr statRootErr;
|
|
fhgfs_stat statRootDetails;
|
|
FhgfsOpsErr statStorageErr;
|
|
int64_t storageSpaceTotal;
|
|
int64_t storageSpaceFree;
|
|
|
|
|
|
if(!waitMS)
|
|
return true; // mount check disabled
|
|
|
|
|
|
this->connRetriesEnabled = false; // NO _ R E T R I E S
|
|
|
|
// wait for management init
|
|
|
|
mgmtInitDone = InternodeSyncer_waitForMgmtInit(this->internodeSyncer, waitMS);
|
|
if(!mgmtInitDone)
|
|
{
|
|
Logger_logErr(this->logger, logContext, "Waiting for management server initialization "
|
|
"timed out. Are the server settings correct? Is the management daemon running?");
|
|
|
|
goto error_resetRetries;
|
|
}
|
|
|
|
// check root metadata server
|
|
|
|
statRootErr = FhgfsOpsRemoting_statRoot(this, &statRootDetails);
|
|
if(statRootErr != FhgfsOpsErr_SUCCESS)
|
|
{
|
|
Logger_logErrFormatted(this->logger, logContext, "Retrieval of root directory entry "
|
|
"failed. Are all metadata servers running and registered at the management daemon? "
|
|
"(Error: %s)", FhgfsOpsErr_toErrString(statRootErr) );
|
|
|
|
goto error_resetRetries;
|
|
}
|
|
|
|
// check storage servers
|
|
|
|
statStorageErr = FhgfsOpsRemoting_statStoragePath(this, false,
|
|
&storageSpaceTotal, &storageSpaceFree);
|
|
|
|
if(statStorageErr != FhgfsOpsErr_SUCCESS)
|
|
{
|
|
Logger_logErrFormatted(this->logger, logContext, "Retrieval of storage server free space "
|
|
"info failed. Are the storage servers running and registered at the management daemon? "
|
|
"Did you remove a storage target directory on a server? (Error: %s)",
|
|
FhgfsOpsErr_toErrString(statStorageErr) );
|
|
|
|
goto error_resetRetries;
|
|
}
|
|
|
|
retVal = true;
|
|
|
|
|
|
error_resetRetries:
|
|
this->connRetriesEnabled = retriesEnabledOrig; // R E S E T _ R E T R I E S
|
|
|
|
return retVal;
|
|
}
|
|
|
|
/**
|
|
* Note: This is actually a Program version, not an App version, but we have it here now because
|
|
* app provides a stable closed source part and we want this version to be fixed at compile time.
|
|
*/
|
|
const char* App_getVersionStr(void)
|
|
{
|
|
return BEEGFS_VERSION;
|
|
}
|