New upstream version 8.1.0

This commit is contained in:
geos_one
2025-08-10 01:34:16 +02:00
commit c891bb7105
4398 changed files with 838833 additions and 0 deletions

View File

@@ -0,0 +1,38 @@
#pragma once
#include <common/net/message/session/AckNotifyMsg.h>
#include <common/net/message/session/AckNotifyRespMsg.h>
#include <net/message/MirroredMessage.h>
#include <session/MirrorMessageResponseState.h>
class AckNotifiyMsgEx : public MirroredMessage<AckNotifiyMsg, std::tuple<>>
{
public:
typedef ErrorCodeResponseState<
AckNotifiyRespMsg,
NETMSGTYPE_AckNotify> ResponseState;
std::unique_ptr<MirroredMessageResponseState> executeLocally(ResponseContext&, bool) override
{
// do nothing at all. MirroredMessage has taken care of everything
return boost::make_unique<ResponseState>(FhgfsOpsErr_SUCCESS);
}
std::tuple<> lock(EntryLockStore&) override { return {}; }
bool isMirrored() override { return true; }
private:
void forwardToSecondary(ResponseContext& ctx) override
{
sendToSecondary(ctx, *this, NETMSGTYPE_AckNotifyResp);
}
FhgfsOpsErr processSecondaryResponse(NetMessage& resp) override
{
return static_cast<AckNotifiyRespMsg&>(resp).getResult();
}
const char* mirrorLogContext() const override { return "AckNotifiyMsgEx/forward"; }
};

View File

@@ -0,0 +1,62 @@
#include "BumpFileVersionMsgEx.h"
#include <components/FileEventLogger.h>
#include <program/Program.h>
bool BumpFileVersionMsgEx::processIncoming(ResponseContext& ctx)
{
LOG_DBG(SESSIONS, DEBUG, "", getEntryInfo().getEntryID(), getEntryInfo().getIsBuddyMirrored(),
hasFlag(NetMessageHeader::Flag_BuddyMirrorSecond),
isMsgHeaderFeatureFlagSet(BUMPFILEVERSIONMSG_FLAG_PERSISTENT),
isMsgHeaderFeatureFlagSet(BUMPFILEVERSIONMSG_FLAG_HASEVENT));
if (isMsgHeaderFeatureFlagSet(BUMPFILEVERSIONMSG_FLAG_HASEVENT))
LOG_DBG(SESSIONS, DEBUG, "", int(getFileEvent()->type), getFileEvent()->path);
return BaseType::processIncoming(ctx);
}
FileIDLock BumpFileVersionMsgEx::lock(EntryLockStore& store)
{
return {&store, getEntryInfo().getEntryID(), true};
}
std::unique_ptr<MirroredMessageResponseState> BumpFileVersionMsgEx::executeLocally(
ResponseContext& ctx, bool isSecondary)
{
auto* app = Program::getApp();
auto* metaStore = app->getMetaStore();
auto [inode, referenceRes] = metaStore->referenceFile(&getEntryInfo());
if (!inode)
return boost::make_unique<ResponseState>(FhgfsOpsErr_INTERNAL);
if (isMsgHeaderFeatureFlagSet(BUMPFILEVERSIONMSG_FLAG_PERSISTENT) &&
!inode->incrementFileVersion(&getEntryInfo()))
{
metaStore->releaseFile(getEntryInfo().getParentEntryID(), inode);
return boost::make_unique<ResponseState>(FhgfsOpsErr_SAVEERROR);
}
if (!isSecondary && app->getFileEventLogger() && getFileEvent())
{
EventContext eventCtx = makeEventContext(
&getEntryInfo(),
getEntryInfo().getParentEntryID(),
getMsgHeaderUserID(),
"",
inode->getNumHardlinks(),
isSecondary
);
logEvent(app->getFileEventLogger(), *getFileEvent(), eventCtx);
}
metaStore->releaseFile(getEntryInfo().getParentEntryID(), inode);
return boost::make_unique<ResponseState>(FhgfsOpsErr_SUCCESS);
}
void BumpFileVersionMsgEx::forwardToSecondary(ResponseContext& ctx)
{
unsetMsgHeaderFeatureFlag(BUMPFILEVERSIONMSG_FLAG_HASEVENT);
sendToSecondary(ctx, *this, NETMSGTYPE_BumpFileVersionResp);
}

View File

@@ -0,0 +1,32 @@
#pragma once
#include <common/net/message/session/BumpFileVersionMsg.h>
#include <common/net/message/session/BumpFileVersionRespMsg.h>
#include <net/message/MirroredMessage.h>
class BumpFileVersionMsgEx : public MirroredMessage<BumpFileVersionMsg, FileIDLock>
{
public:
typedef ErrorCodeResponseState<BumpFileVersionRespMsg, NETMSGTYPE_BumpFileVersion>
ResponseState;
virtual bool processIncoming(ResponseContext& ctx) override;
std::unique_ptr<MirroredMessageResponseState> executeLocally(ResponseContext& ctx,
bool isSecondary) override;
FileIDLock lock(EntryLockStore& store) override;
bool isMirrored() override { return getEntryInfo().getIsBuddyMirrored(); }
private:
void forwardToSecondary(ResponseContext& ctx) override;
FhgfsOpsErr processSecondaryResponse(NetMessage& resp) override
{
return (FhgfsOpsErr) static_cast<BumpFileVersionRespMsg&>(resp).getValue();
}
const char* mirrorLogContext() const override { return "BumpFileVersionMsgEx/forward"; }
};

View File

@@ -0,0 +1,35 @@
#include "GetFileVersionMsgEx.h"
#include <program/Program.h>
bool GetFileVersionMsgEx::processIncoming(ResponseContext& ctx)
{
LOG_DBG(SESSIONS, DEBUG, "", getEntryInfo().getEntryID(), getEntryInfo().getIsBuddyMirrored());
return BaseType::processIncoming(ctx);
}
FileIDLock GetFileVersionMsgEx::lock(EntryLockStore& store)
{
return {&store, getEntryInfo().getEntryID(), false};
}
std::unique_ptr<MirroredMessageResponseState> GetFileVersionMsgEx::executeLocally(ResponseContext& ctx,
bool isSecondary)
{
GetFileVersionMsgResponseState resp;
auto& metaStore = *Program::getApp()->getMetaStore();
auto [inode, referenceRes] = metaStore.referenceFile(&getEntryInfo());
if (!inode)
{
// The GetFileVersionMsgResponseState constructor sets default values for 'result' and
// 'version', indicating an error condition, eliminating the need to specify them
// separately. Hence, returning a ResponseState with the moved 'resp'.
return boost::make_unique<ResponseState>(std::move(resp));
}
resp.setGetFileVersionResult(FhgfsOpsErr_SUCCESS);
resp.setFileVersion(inode->getFileVersion());
metaStore.releaseFile(getEntryInfo().getParentEntryID(), inode);
return boost::make_unique<ResponseState>(std::move(resp));
}

View File

@@ -0,0 +1,74 @@
#pragma once
#include <common/net/message/session/GetFileVersionMsg.h>
#include <common/net/message/session/GetFileVersionRespMsg.h>
#include <common/net/message/session/GetFileVersionRespMsg.h>
#include <net/message/MirroredMessage.h>
class GetFileVersionMsgResponseState : public MirroredMessageResponseState
{
public:
GetFileVersionMsgResponseState() : result(FhgfsOpsErr_INTERNAL), version(0)
{
}
GetFileVersionMsgResponseState(GetFileVersionMsgResponseState&& other) :
result(other.result),
version(other.version)
{
}
void sendResponse(NetMessage::ResponseContext& ctx) override
{
GetFileVersionRespMsg resp(result, version);
ctx.sendResponse(resp);
}
// GetFileVersionMsgEx is transformed into a mirrored message to leverage
// MirroredMessage::lock(), preventing races with operations such as unlink.
// However, forwarding this message to the secondary is unnecessary.
// Overriding the changeObservableState() function to always return false ensures
// that this message is never forwarded unnecessarily.
bool changesObservableState() const override
{
return false;
}
void setGetFileVersionResult(FhgfsOpsErr result) { this->result = result; }
void setFileVersion(uint32_t version) { this->version = version; }
protected:
uint32_t serializerTag() const override { return NETMSGTYPE_GetFileVersion; }
void serializeContents(Serializer& ser) const override {}
private:
FhgfsOpsErr result;
uint32_t version;
};
class GetFileVersionMsgEx : public MirroredMessage<GetFileVersionMsg, FileIDLock>
{
public:
typedef GetFileVersionMsgResponseState ResponseState;
virtual bool processIncoming(ResponseContext& ctx) override;
FileIDLock lock(EntryLockStore& store) override;
bool isMirrored() override
{
return getEntryInfo().getIsBuddyMirrored();
}
private:
private:
std::unique_ptr<MirroredMessageResponseState> executeLocally(ResponseContext& ctx,
bool isSecondary) override;
void forwardToSecondary(ResponseContext& ctx) override {}
FhgfsOpsErr processSecondaryResponse(NetMessage& resp) override
{
return FhgfsOpsErr_SUCCESS;
}
const char* mirrorLogContext() const override { return "GetFileVersionMsgEx/forward"; }
};

View File

@@ -0,0 +1,57 @@
#include <common/net/message/session/locking/FLockAppendRespMsg.h>
#include <common/toolkit/MessagingTk.h>
#include <common/toolkit/SessionTk.h>
#include <net/msghelpers/MsgHelperLocking.h>
#include <program/Program.h>
#include <session/SessionStore.h>
#include <storage/MetaStore.h>
#include "FLockAppendMsgEx.h"
bool FLockAppendMsgEx::processIncoming(ResponseContext& ctx)
{
/* note: this code is very similar to FLockRangeMsgEx::processIncoming(), so if you change
something here, you probably want to change it there, too. */
#ifdef BEEGFS_DEBUG
const char* logContext = "FLockAppendMsg incoming";
#endif // BEEGFS_DEBUG
LOG_DEBUG(logContext, Log_DEBUG, "entryID: " + this->getEntryInfo()->getEntryID());
clientResult = FhgfsOpsErr_INTERNAL;
return BaseType::processIncoming(ctx);
}
FileIDLock FLockAppendMsgEx::lock(EntryLockStore& store)
{
return {&store, getEntryInfo()->getEntryID(), true};
}
std::unique_ptr<MirroredMessageResponseState> FLockAppendMsgEx::executeLocally(ResponseContext& ctx,
bool isSecondary)
{
const char* logContext = "FLock Append Msg";
unsigned ownerFD = SessionTk::ownerFDFromHandleID(getFileHandleID() );
EntryLockDetails lockDetails(getClientNumID(), getClientFD(), getOwnerPID(), getLockAckID(),
getLockTypeFlags() );
LogContext(logContext).log(Log_DEBUG, lockDetails.toString());
EntryInfo* entryInfo = getEntryInfo();
clientResult = MsgHelperLocking::flockAppend(entryInfo, ownerFD, lockDetails);
LogContext(logContext).log(Log_DEBUG, "FLock Append result: " + std::to_string(clientResult));
Program::getApp()->getNodeOpStats()->updateNodeOp(ctx.getSocket()->getPeerIP(),
MetaOpCounter_FLOCKAPPEND, getMsgHeaderUserID() );
return boost::make_unique<ResponseState>(clientResult);
}
void FLockAppendMsgEx::forwardToSecondary(ResponseContext& ctx)
{
sendToSecondary(ctx, *this, NETMSGTYPE_FLockAppendResp, clientResult);
}

View File

@@ -0,0 +1,32 @@
#pragma once
#include <common/net/message/session/locking/FLockAppendMsg.h>
#include <common/net/message/session/locking/FLockAppendRespMsg.h>
#include <net/message/MirroredMessage.h>
#include <common/storage/StorageErrors.h>
#include <storage/FileInode.h>
class FLockAppendMsgEx : public MirroredMessage<FLockAppendMsg, FileIDLock>
{
public:
typedef ErrorCodeResponseState<FLockAppendRespMsg, NETMSGTYPE_FLockAppend> ResponseState;
virtual bool processIncoming(ResponseContext& ctx) override;
std::unique_ptr<MirroredMessageResponseState> executeLocally(ResponseContext& ctx,
bool isSecondary) override;
FileIDLock lock(EntryLockStore& store) override;
bool isMirrored() override { return getEntryInfo()->getIsBuddyMirrored(); }
private:
FhgfsOpsErr clientResult;
void forwardToSecondary(ResponseContext& ctx) override;
FhgfsOpsErr processSecondaryResponse(NetMessage& resp) override
{
return static_cast<FLockAppendRespMsg&>(resp).getResult();
}
const char* mirrorLogContext() const override { return "FLockAppendMsgEx/forward"; }
};

View File

@@ -0,0 +1,135 @@
#include <common/net/message/session/locking/FLockEntryRespMsg.h>
#include <common/toolkit/MessagingTk.h>
#include <common/toolkit/SessionTk.h>
#include <net/msghelpers/MsgHelperLocking.h>
#include <program/Program.h>
#include <session/SessionStore.h>
#include <storage/MetaStore.h>
#include "FLockEntryMsgEx.h"
bool FLockEntryMsgEx::processIncoming(ResponseContext& ctx)
{
/* note: this code is very similar to FLockRangeMsgEx::processIncoming(), so if you change
something here, you probably want to change it there, too. */
clientResult = FhgfsOpsErr_INTERNAL;
updateNodeOp(ctx, MetaOpCounter_FLOCKENTRY);
return BaseType::processIncoming(ctx);
}
FileIDLock FLockEntryMsgEx::lock(EntryLockStore& store)
{
return {&store, getEntryInfo()->getEntryID(), true};
}
std::unique_ptr<MirroredMessageResponseState> FLockEntryMsgEx::executeLocally(ResponseContext& ctx,
bool isSecondary)
{
App* app = Program::getApp();
MetaStore* metaStore = app->getMetaStore();
unsigned ownerFD = SessionTk::ownerFDFromHandleID(getFileHandleID() );
EntryLockDetails lockDetails(getClientNumID(), getClientFD(), getOwnerPID(), getLockAckID(),
getLockTypeFlags() );
LOG_DBG(GENERAL, SPAM, lockDetails.toString());
EntryInfo* entryInfo = getEntryInfo();
SessionStore* sessions = entryInfo->getIsBuddyMirrored()
? app->getMirroredSessions()
: app->getSessions();
// find sessionFile
Session* session = sessions->referenceSession(getClientNumID(), true);
SessionFileStore* sessionFiles = session->getFiles();
SessionFile* sessionFile = sessionFiles->referenceSession(ownerFD);
if(!sessionFile)
{ // sessionFile not exists (mds restarted?)
// check if this is just an UNLOCK REQUEST
if(getLockTypeFlags() & ENTRYLOCKTYPE_UNLOCK)
{ // it's an unlock => we'll just ignore it (since the locks are gone anyways)
clientResult = FhgfsOpsErr_SUCCESS;
goto cleanup_session;
}
// check if this is a LOCK CANCEL REQUEST
if(getLockTypeFlags() & ENTRYLOCKTYPE_CANCEL)
{ // it's a lock cancel
/* this is an important special case, because client might have succeeded in closing the
file but the conn might have been interrupted during unlock, so we definitely have to try
canceling the lock here */
// if the file still exists, just do the lock cancel without session recovery attempt
auto [lockCancelFile, referenceRes] = metaStore->referenceFile(entryInfo);
if(lockCancelFile)
{
lockCancelFile->flockEntry(lockDetails);
metaStore->releaseFile(entryInfo->getParentEntryID(), lockCancelFile);
}
clientResult = FhgfsOpsErr_SUCCESS;
goto cleanup_session;
}
// it's a LOCK REQUEST => try to recover session file to do the locking
clientResult = MsgHelperLocking::trySesssionRecovery(entryInfo, getClientNumID(),
ownerFD, sessionFiles, &sessionFile);
// (note: sessionFile==NULL now if recovery was not successful)
} // end of session file session recovery attempt
if(sessionFile)
{ // sessionFile exists (or was successfully recovered)
auto& file = sessionFile->getInode();
auto lockGranted = file->flockEntry(lockDetails);
if (!lockGranted.first)
clientResult = FhgfsOpsErr_WOULDBLOCK;
else
clientResult = FhgfsOpsErr_SUCCESS;
if ((getLockTypeFlags() & ENTRYLOCKTYPE_UNLOCK) && !file->incrementFileVersion(entryInfo))
{
LOG(GENERAL, ERR, "Could not bump file version.", file->getEntryID());
sessionFiles->releaseSession(sessionFile, entryInfo);
clientResult = FhgfsOpsErr_INTERNAL;
goto cleanup_session;
}
if (!lockGranted.second.empty() && !isSecondary)
LockingNotifier::notifyWaitersEntryLock(LockEntryNotifyType_FLOCK,
file->getReferenceParentID(), file->getEntryID(), file->getIsBuddyMirrored(),
std::move(lockGranted.second));
// cleanup
sessionFiles->releaseSession(sessionFile, entryInfo);
}
// cleanup
cleanup_session:
sessions->releaseSession(session);
LOG_DBG(GENERAL, SPAM, "", getClientNumID(), clientResult);
return boost::make_unique<ResponseState>(clientResult);
}
void FLockEntryMsgEx::forwardToSecondary(ResponseContext& ctx)
{
sendToSecondary(ctx, *this, NETMSGTYPE_FLockEntryResp, clientResult);
}

View File

@@ -0,0 +1,36 @@
#pragma once
#include <common/net/message/session/locking/FLockEntryMsg.h>
#include <common/net/message/session/locking/FLockEntryRespMsg.h>
#include <common/storage/StorageErrors.h>
#include <net/message/MirroredMessage.h>
#include <storage/FileInode.h>
class FLockEntryMsgEx : public MirroredMessage<FLockEntryMsg, FileIDLock>
{
public:
typedef ErrorCodeResponseState<FLockEntryRespMsg, NETMSGTYPE_FLockEntry> ResponseState;
virtual bool processIncoming(ResponseContext& ctx) override;
std::unique_ptr<MirroredMessageResponseState> executeLocally(ResponseContext& ctx,
bool isSecondary) override;
FileIDLock lock(EntryLockStore& store) override;
bool isMirrored() override { return getEntryInfo()->getIsBuddyMirrored(); }
private:
FhgfsOpsErr clientResult;
void forwardToSecondary(ResponseContext& ctx) override;
FhgfsOpsErr processSecondaryResponse(NetMessage& resp) override
{
return static_cast<FLockEntryRespMsg&>(resp).getResult();
}
const char* mirrorLogContext() const override { return "FLockEntryMsgEx/forward"; }
};

View File

@@ -0,0 +1,134 @@
#include <common/net/message/session/locking/FLockRangeRespMsg.h>
#include <common/toolkit/MessagingTk.h>
#include <common/toolkit/SessionTk.h>
#include <net/msghelpers/MsgHelperLocking.h>
#include <program/Program.h>
#include <session/SessionStore.h>
#include <storage/MetaStore.h>
#include "FLockRangeMsgEx.h"
bool FLockRangeMsgEx::processIncoming(ResponseContext& ctx)
{
/* note: this code is very similar to FLockEntryMsgEx::processIncoming(), so if you change
something here, you probably want to change it there, too. */
clientResult = FhgfsOpsErr_INTERNAL;
updateNodeOp(ctx, MetaOpCounter_FLOCKRANGE);
return BaseType::processIncoming(ctx);
}
FileIDLock FLockRangeMsgEx::lock(EntryLockStore& store)
{
return {&store, getEntryInfo()->getEntryID(), true};
}
std::unique_ptr<MirroredMessageResponseState> FLockRangeMsgEx::executeLocally(ResponseContext& ctx,
bool isSecondary)
{
App* app = Program::getApp();
MetaStore* metaStore = app->getMetaStore();
unsigned ownerFD = SessionTk::ownerFDFromHandleID(getFileHandleID() );
RangeLockDetails lockDetails(getClientNumID(), getOwnerPID(), getLockAckID(),
getLockTypeFlags(), getStart(), getEnd() );
LOG_DBG(GENERAL, SPAM, lockDetails.toString());
EntryInfo* entryInfo = getEntryInfo();
SessionStore* sessions = entryInfo->getIsBuddyMirrored()
? app->getMirroredSessions()
: app->getSessions();
// find sessionFile
Session* session = sessions->referenceSession(getClientNumID(), true);
SessionFileStore* sessionFiles = session->getFiles();
SessionFile* sessionFile = sessionFiles->referenceSession(ownerFD);
if(!sessionFile)
{ // sessionFile not exists (mds restarted?)
// check if this is just an UNLOCK REQUEST
if(getLockTypeFlags() & ENTRYLOCKTYPE_LOCKOPS_REMOVE)
{ // it's an unlock => we'll just ignore it (since the locks are gone anyways)
clientResult = FhgfsOpsErr_SUCCESS;
goto cleanup_session;
}
// check if this is a LOCK CANCEL REQUEST
if(getLockTypeFlags() & ENTRYLOCKTYPE_CANCEL)
{ // it's a lock cancel
/* this is an important special case, because client might have succeeded in closing the
file but the conn might have been interrupted during unlock, so we definitely have to try
canceling the lock here */
// if the file still exists, just do the lock cancel without session recovery attempt
auto [lockCancelFile, referenceRes] = metaStore->referenceFile(entryInfo);
if(lockCancelFile)
{
lockCancelFile->flockRange(lockDetails);
metaStore->releaseFile(entryInfo->getParentEntryID(), lockCancelFile);
}
clientResult = FhgfsOpsErr_SUCCESS;
goto cleanup_session;
}
// it's a LOCK REQUEST => try to recover session file to do the locking
clientResult = MsgHelperLocking::trySesssionRecovery(entryInfo, getClientNumID(),
ownerFD, sessionFiles, &sessionFile);
// (note: sessionFile==NULL now if recovery was not successful)
} // end of session file session recovery attempt
if(sessionFile)
{ // sessionFile exists (or was successfully recovered)
auto& file = sessionFile->getInode();
auto lockGranted = file->flockRange(lockDetails);
if (!lockGranted.first)
clientResult = FhgfsOpsErr_WOULDBLOCK;
else
clientResult = FhgfsOpsErr_SUCCESS;
if ((getLockTypeFlags() & ENTRYLOCKTYPE_UNLOCK) && !file->incrementFileVersion(entryInfo))
{
LOG(GENERAL, ERR, "Could not bump file version.", file->getEntryID());
sessionFiles->releaseSession(sessionFile, entryInfo);
clientResult = FhgfsOpsErr_INTERNAL;
goto cleanup_session;
}
if (!lockGranted.second.empty() && !isSecondary)
LockingNotifier::notifyWaitersRangeLock(file->getReferenceParentID(), file->getEntryID(),
file->getIsBuddyMirrored(), std::move(lockGranted.second));
// cleanup
sessionFiles->releaseSession(sessionFile, entryInfo);
}
// cleanup
cleanup_session:
sessions->releaseSession(session);
LOG_DBG(GENERAL, SPAM, "", clientResult);
return boost::make_unique<ResponseState>(clientResult);
}
void FLockRangeMsgEx::forwardToSecondary(ResponseContext& ctx)
{
sendToSecondary(ctx, *this, NETMSGTYPE_FLockRangeResp, clientResult);
}

View File

@@ -0,0 +1,36 @@
#pragma once
#include <common/net/message/session/locking/FLockRangeMsg.h>
#include <common/net/message/session/locking/FLockRangeRespMsg.h>
#include <common/storage/StorageErrors.h>
#include <net/message/MirroredMessage.h>
#include <storage/FileInode.h>
class FLockRangeMsgEx : public MirroredMessage<FLockRangeMsg, FileIDLock>
{
public:
typedef ErrorCodeResponseState<FLockRangeRespMsg, NETMSGTYPE_FLockRange> ResponseState;
virtual bool processIncoming(ResponseContext& ctx) override;
std::unique_ptr<MirroredMessageResponseState> executeLocally(ResponseContext& ctx,
bool isSecondary) override;
FileIDLock lock(EntryLockStore& store) override;
bool isMirrored() override { return getEntryInfo()->getIsBuddyMirrored(); }
private:
FhgfsOpsErr clientResult;
void forwardToSecondary(ResponseContext& ctx) override;
FhgfsOpsErr processSecondaryResponse(NetMessage& resp) override
{
return static_cast<FLockRangeRespMsg&>(resp).getResult();
}
const char* mirrorLogContext() const override { return "FLockRangeMsgEx/forward"; }
};

View File

@@ -0,0 +1,246 @@
#include <common/components/streamlistenerv2/IncomingPreprocessedMsgWork.h>
#include <common/net/message/control/GenericResponseMsg.h>
#include <common/net/message/session/opening/CloseFileRespMsg.h>
#include <common/toolkit/MessagingTk.h>
#include <common/toolkit/SessionTk.h>
#include <components/FileEventLogger.h>
#include <net/msghelpers/MsgHelperClose.h>
#include <net/msghelpers/MsgHelperLocking.h>
#include <program/Program.h>
#include <session/EntryLock.h>
#include <storage/MetaStore.h>
#include "CloseFileMsgEx.h"
FileIDLock CloseFileMsgEx::lock(EntryLockStore& store)
{
return {&store, getEntryInfo()->getEntryID(), true};
}
bool CloseFileMsgEx::processIncoming(ResponseContext& ctx)
{
#ifdef BEEGFS_DEBUG
const char* logContext = "CloseFileMsg incoming";
#endif // BEEGFS_DEBUG
LOG_DEBUG(logContext, Log_DEBUG,
"BuddyMirrored: " + std::string(getEntryInfo()->getIsBuddyMirrored() ? "Yes" : "No") +
" Secondary: " +
std::string(hasFlag(NetMessageHeader::Flag_BuddyMirrorSecond) ? "Yes" : "No") );
// update operation counters (here on top because we have an early sock release in this msg)
updateNodeOp(ctx, MetaOpCounter_CLOSE);
return BaseType::processIncoming(ctx);
}
std::unique_ptr<MirroredMessageResponseState> CloseFileMsgEx::executeLocally(ResponseContext& ctx,
bool isSecondary)
{
if (isSecondary)
return closeFileSecondary(ctx);
else
return closeFilePrimary(ctx);
}
std::unique_ptr<CloseFileMsgEx::ResponseState> CloseFileMsgEx::closeFilePrimary(
ResponseContext& ctx)
{
FhgfsOpsErr closeRes;
bool unlinkDisposalFile = false;
bool outLastWriterClosed = false;
EntryInfo* entryInfo = getEntryInfo();
unsigned numHardlinks;
bool closeSucceeded;
if(isMsgHeaderFeatureFlagSet(CLOSEFILEMSG_FLAG_CANCELAPPENDLOCKS) )
{ // client requests cleanup of granted or pending locks for this handle
unsigned ownerFD = SessionTk::ownerFDFromHandleID(getFileHandleID() );
EntryLockDetails lockDetails(getClientNumID(), 0, 0, "", ENTRYLOCKTYPE_CANCEL);
MsgHelperLocking::flockAppend(entryInfo, ownerFD, lockDetails);
}
/* two alternatives:
1) early response before chunk file close (if client isn't interested in chunks result).
2) normal response after chunk file close. */
// if we are buddy mirrored, *do not* allow early close responses. since the primary will close
// the chunk files (and update the inodes dynamic attributes), the secondary cannot do that.
// thus we need to close all chunks, get the dynamic attributes, and push them to the secondary
if (getEntryInfo()->getIsBuddyMirrored())
unsetMsgHeaderFeatureFlag(CLOSEFILEMSG_FLAG_EARLYRESPONSE);
if(isMsgHeaderFeatureFlagSet(CLOSEFILEMSG_FLAG_EARLYRESPONSE) )
{ // alternative 1: client requests an early response
/* note: linux won't even return the vfs release() result to userspace apps, so there's
usually no point in waiting for the chunk file close result before sending the response */
unsigned accessFlags;
MetaFileHandle inode;
closeRes = MsgHelperClose::closeSessionFile(
getClientNumID(), getFileHandleID(), entryInfo, &accessFlags, inode);
closeSucceeded = closeRes == FhgfsOpsErr_SUCCESS;
// send response
earlyComplete(ctx, ResponseState(closeRes));
// if session file close succeeds but chunk file close fails we should not attempt to
// dispose. if chunk close failed for any other reason than network outages we might
// put the storage server into an even weirder state by unlinking the chunk file:
// the file itself is still open (has a session), but is gone on disk, and thus cannot
// be reopened from stored sessions when the server is restarted.
if(likely(closeRes == FhgfsOpsErr_SUCCESS) )
closeRes = closeFileAfterEarlyResponse(std::move(inode), accessFlags, &unlinkDisposalFile,
numHardlinks, outLastWriterClosed);
}
else
{ // alternative 2: normal response (after chunk file close)
closeRes = MsgHelperClose::closeFile(getClientNumID(), getFileHandleID(),
entryInfo, getMaxUsedNodeIndex(), getMsgHeaderUserID(), &unlinkDisposalFile,
&numHardlinks, outLastWriterClosed, &dynAttribs, &inodeTimestamps);
closeSucceeded = closeRes == FhgfsOpsErr_SUCCESS;
if (getEntryInfo()->getIsBuddyMirrored() && getMaxUsedNodeIndex() >= 0)
addMsgHeaderFeatureFlag(CLOSEFILEMSG_FLAG_DYNATTRIBS);
//Avoid sending early response. Let unlink of Disposal file happens.
//with Locks held. But make sure before file gets unlink we synchronise
//the operation with any on-going buddy mirror resync operation.
ResponseState responseState(closeRes);
buddyResyncNotify(ctx, responseState.changesObservableState());
}
if (closeSucceeded && Program::getApp()->getFileEventLogger() && getFileEvent())
{
// Important Note:
// - If the last writer, who previously opened this file with write permissions,
// is currently closing it,
// - And it is not marked for disposal,
// - And it is not due to a symlink creation,
// Then we update the event type to LAST_WRITER_CLOSED.
bool isSymlinkEvent = getFileEvent()->type == FileEventType::SYMLINK;
if (!isSymlinkEvent && outLastWriterClosed && !unlinkDisposalFile)
{
auto fileEvent = const_cast<FileEvent*>(getFileEvent());
fileEvent->type = FileEventType::LAST_WRITER_CLOSED;
}
EventContext eventCtx = makeEventContext(
entryInfo,
entryInfo->getParentEntryID(),
getMsgHeaderUserID(),
"", // targetParentID
numHardlinks,
false // This is not the secondary node if closeFilePrimary() was called.
);
logEvent(Program::getApp()->getFileEventLogger(), *getFileEvent(), eventCtx);
}
// unlink if file marked as disposable
if( (closeRes == FhgfsOpsErr_SUCCESS) && unlinkDisposalFile)
{ // check whether file has been unlinked (and perform the unlink operation on last close)
/* note: we do this only if also the chunk file close succeeded, because if storage servers
are down, unlinkDisposableFile() will keep the file in the disposal store anyways */
// this only touches timestamps on the disposal dirinode, which is not visible to the user,
// so no need to fix up timestamps that have diverged between primary and secondary
MsgHelperClose::unlinkDisposableFile(entryInfo->getEntryID(), getMsgHeaderUserID(),
entryInfo->getIsBuddyMirrored());
}
//for alternative 2: forward the operation to secondary
//after unlinkDisposalFile on primary is complete.
if(!isMsgHeaderFeatureFlagSet(CLOSEFILEMSG_FLAG_EARLYRESPONSE))
return boost::make_unique<ResponseState>(closeRes);
return {};
}
std::unique_ptr<CloseFileMsgEx::ResponseState> CloseFileMsgEx::closeFileSecondary(
ResponseContext& ctx)
{
if (isMsgHeaderFeatureFlagSet(CLOSEFILEMSG_FLAG_CANCELAPPENDLOCKS))
{
// client requests cleanup of granted or pending locks for this handle
unsigned ownerFD = SessionTk::ownerFDFromHandleID(getFileHandleID() );
EntryLockDetails lockDetails(getClientNumID(), 0, 0, "", ENTRYLOCKTYPE_CANCEL);
MsgHelperLocking::flockAppend(getEntryInfo(), ownerFD, lockDetails);
}
// on secondary we only need to close the session and the meta file, because the chunk files
// will be closed by primary
unsigned accessFlags;
MetaFileHandle inode;
FhgfsOpsErr closeRes = MsgHelperClose::closeSessionFile(
getClientNumID(), getFileHandleID(), getEntryInfo(), &accessFlags, inode);
// the file may not be open on the secondary, in which case inode == nullptr
if (closeRes != FhgfsOpsErr_SUCCESS)
return boost::make_unique<ResponseState>(closeRes);
// maybe assert?
if (isMsgHeaderFeatureFlagSet(CLOSEFILEMSG_FLAG_DYNATTRIBS))
inode->setDynAttribs(dynAttribs);
fixInodeTimestamp(*inode, inodeTimestamps, getEntryInfo());
unsigned numHardlinks;
unsigned numInodeRefs;
bool outLastWriterClosed;
Program::getApp()->getMetaStore()->closeFile(getEntryInfo(), std::move(inode), accessFlags,
&numHardlinks, &numInodeRefs, outLastWriterClosed);
// unlink if file marked as disposable
// this only touches timestamps on the disposal dirinode, which is not visible to the user,
// so no need to fix up timestamps that have diverged between primary and secondary
if( (closeRes == FhgfsOpsErr_SUCCESS) && (!numHardlinks) && (!numInodeRefs))
MsgHelperClose::unlinkDisposableFile(getEntryInfo()->getEntryID(), getMsgHeaderUserID(),
getEntryInfo()->getIsBuddyMirrored());
return boost::make_unique<ResponseState>(closeRes);
}
/**
* The rest after MsgHelperClose::closeSessionFile(), i.e. MsgHelperClose::closeChunkFile()
* and metaStore->closeFile().
*
* @param inode inode for closed file (as returned by MsgHelperClose::closeSessionFile() )
* @param maxUsedNodeIndex zero-based index, -1 means "none"
* @param outFileWasUnlinked true if the hardlink count of the file was 0
*/
FhgfsOpsErr CloseFileMsgEx::closeFileAfterEarlyResponse(MetaFileHandle inode, unsigned accessFlags,
bool* outUnlinkDisposalFile, unsigned& outNumHardlinks, bool& outLastWriterClosed)
{
MetaStore* metaStore = Program::getApp()->getMetaStore();
unsigned numInodeRefs;
*outUnlinkDisposalFile = false;
FhgfsOpsErr chunksRes = MsgHelperClose::closeChunkFile(
getClientNumID(), getFileHandleID(), getMaxUsedNodeIndex(), *inode, getEntryInfo(),
getMsgHeaderUserID(), NULL);
metaStore->closeFile(getEntryInfo(), std::move(inode), accessFlags, &outNumHardlinks,
&numInodeRefs, outLastWriterClosed);
if (!outNumHardlinks && !numInodeRefs)
*outUnlinkDisposalFile = true;
return chunksRes;
}
void CloseFileMsgEx::forwardToSecondary(ResponseContext& ctx)
{
sendToSecondary(ctx, *this, NETMSGTYPE_CloseFileResp);
}

View File

@@ -0,0 +1,38 @@
#pragma once
#include <common/storage/StorageErrors.h>
#include <common/net/message/session/opening/CloseFileMsg.h>
#include <common/net/message/session/opening/CloseFileRespMsg.h>
#include <net/message/MirroredMessage.h>
#include <session/EntryLock.h>
#include <storage/FileInode.h>
class CloseFileMsgEx : public MirroredMessage<CloseFileMsg, FileIDLock>
{
public:
typedef ErrorCodeResponseState<CloseFileRespMsg, NETMSGTYPE_CloseFile> ResponseState;
virtual bool processIncoming(ResponseContext& ctx) override;
std::unique_ptr<MirroredMessageResponseState> executeLocally(ResponseContext& ctx,
bool isSecondary) override;
FileIDLock lock(EntryLockStore& store) override;
bool isMirrored() override { return getEntryInfo()->getIsBuddyMirrored(); }
private:
std::unique_ptr<ResponseState> closeFilePrimary(ResponseContext& ctx);
std::unique_ptr<ResponseState> closeFileSecondary(ResponseContext& ctx);
void forwardToSecondary(ResponseContext& ctx) override;
FhgfsOpsErr closeFileAfterEarlyResponse(MetaFileHandle inode, unsigned accessFlags,
bool* outUnlinkDisposalFile, unsigned& numHardlinks, bool& outLastWriterClosed);
FhgfsOpsErr processSecondaryResponse(NetMessage& resp) override
{
return (FhgfsOpsErr) static_cast<CloseFileRespMsg&>(resp).getValue();
}
const char* mirrorLogContext() const override { return "CloseFileMsgEx/forward"; }
};

View File

@@ -0,0 +1,157 @@
#include <common/net/message/control/GenericResponseMsg.h>
#include <common/net/message/session/opening/OpenFileRespMsg.h>
#include <common/toolkit/SessionTk.h>
#include <common/storage/striping/Raid0Pattern.h>
#include <components/FileEventLogger.h>
#include <net/msghelpers/MsgHelperOpen.h>
#include <program/Program.h>
#include <session/EntryLock.h>
#include <session/SessionStore.h>
#include "OpenFileMsgEx.h"
FileIDLock OpenFileMsgEx::lock(EntryLockStore& store)
{
return {&store, getEntryInfo()->getEntryID(), true};
}
bool OpenFileMsgEx::processIncoming(ResponseContext& ctx)
{
#ifdef BEEGFS_DEBUG
const char* logContext = "OpenFileMsg incoming";
EntryInfo* entryInfo = getEntryInfo();
LOG_DEBUG(logContext, Log_SPAM, "ParentInfo: " + entryInfo->getParentEntryID() +
" EntryID: " + entryInfo->getEntryID() + " FileName: " + entryInfo->getFileName() );
LOG_DEBUG(logContext, Log_DEBUG,
"BuddyMirrored: " + std::string(entryInfo->getIsBuddyMirrored() ? "Yes" : "No") +
" Secondary: " +
std::string(hasFlag(NetMessageHeader::Flag_BuddyMirrorSecond) ? "Yes" : "No") );
#endif // BEEGFS_DEBUG
return BaseType::processIncoming(ctx);
}
std::unique_ptr<MirroredMessageResponseState> OpenFileMsgEx::executeLocally(ResponseContext& ctx,
bool isSecondary)
{
App* app = Program::getApp();
EntryInfo* entryInfo = this->getEntryInfo();
bool useQuota = isMsgHeaderFeatureFlagSet(OPENFILEMSG_FLAG_USE_QUOTA);
bool bypassAccessCheck = isMsgHeaderFeatureFlagSet(OPENFILEMSG_FLAG_BYPASS_ACCESS_CHECK);
const bool eventLoggingEnabled = !isSecondary && app->getFileEventLogger() && getFileEvent();
MetaFileHandle inode;
PathInfo pathInfo;
StripePattern* pattern;
unsigned sessionFileID;
SessionStore* sessions = entryInfo->getIsBuddyMirrored()
? app->getMirroredSessions()
: app->getSessions();
FhgfsOpsErr openRes = MsgHelperOpen::openFile(
entryInfo, getAccessFlags(), useQuota, bypassAccessCheck, getMsgHeaderUserID(),
inode, isSecondary);
if (openRes == FhgfsOpsErr_SUCCESS && shouldFixTimestamps())
fixInodeTimestamp(*inode, fileTimestamps, entryInfo);
// update operation counters
updateNodeOp(ctx, MetaOpCounter_OPEN);
if (openRes != FhgfsOpsErr_SUCCESS)
{
// If open() fails due to file state restrictions, emit an OPEN_BLOCKED event
// (when event logging is enabled). The numHardlinks in event context will be 0
// since inode is nullptr after access denial.
if ((openRes == FhgfsOpsErr_FILEACCESS_DENIED) && eventLoggingEnabled)
{
FileEvent* fileEvent = const_cast<FileEvent*>(getFileEvent());
fileEvent->type = FileEventType::OPEN_BLOCKED;
EventContext eventCtx = makeEventContext(
entryInfo,
entryInfo->getParentEntryID(),
getMsgHeaderUserID(),
"",
inode ? inode->getNumHardlinks() : 0,
isSecondary
);
logEvent(app->getFileEventLogger(), *fileEvent, eventCtx);
}
// error occurred
Raid0Pattern dummyPattern(1, UInt16Vector{});
// generate response
if(unlikely(openRes == FhgfsOpsErr_COMMUNICATION))
{
return boost::make_unique<OpenFileResponseState>();
}
else
{ // normal response
return boost::make_unique<OpenFileResponseState>(openRes, std::string(), dummyPattern,
pathInfo, 0);
}
}
if (eventLoggingEnabled)
{
EventContext eventCtx = makeEventContext(
entryInfo,
entryInfo->getParentEntryID(),
getMsgHeaderUserID(),
"",
inode->getNumHardlinks(),
isSecondary
);
logEvent(app->getFileEventLogger(), *getFileEvent(), eventCtx);
}
// success => insert session
SessionFile* sessionFile = new SessionFile(std::move(inode), getAccessFlags(), entryInfo);
Session* session = sessions->referenceSession(getClientNumID(), true);
pattern = sessionFile->getInode()->getStripePattern();
if (!isSecondary)
{
sessionFileID = session->getFiles()->addSession(sessionFile);
fileHandleID = SessionTk::generateFileHandleID(sessionFileID, entryInfo->getEntryID() );
setSessionFileID(sessionFileID);
setFileHandleID(fileHandleID.c_str());
}
else
{
fileHandleID = getFileHandleID();
sessionFileID = getSessionFileID();
bool addRes = session->getFiles()->addSession(sessionFile, sessionFileID);
if (!addRes)
{
const char* logContext = "OpenFileMsgEx (executeLocally)";
LogContext(logContext).log(Log_NOTICE,
"Couldn't add sessionFile on secondary buddy; sessionID: " + getClientNumID().str()
+ "; sessionFileID: " + StringTk::uintToStr(sessionFileID));
}
}
sessions->releaseSession(session);
sessionFile->getInode()->getPathInfo(&pathInfo);
return boost::make_unique<OpenFileResponseState>(openRes, fileHandleID, *pattern, pathInfo,
sessionFile->getInode()->getFileVersion());
}
void OpenFileMsgEx::forwardToSecondary(ResponseContext& ctx)
{
sendToSecondary(ctx, *this, NETMSGTYPE_OpenFileResp);
}

View File

@@ -0,0 +1,105 @@
#pragma once
#include <common/storage/StorageErrors.h>
#include <common/net/message/session/opening/OpenFileMsg.h>
#include <common/net/message/session/opening/OpenFileRespMsg.h>
#include <storage/DirInode.h>
#include <storage/FileInode.h>
#include <net/message/MirroredMessage.h>
#include <session/EntryLock.h>
class OpenFileResponseState : public MirroredMessageResponseState
{
public:
OpenFileResponseState()
: isIndirectCommErr(true)
{
}
explicit OpenFileResponseState(Deserializer& des)
{
serialize(this, des);
}
OpenFileResponseState(FhgfsOpsErr result, const std::string& fileHandleID,
const StripePattern& pattern, const PathInfo& pathInfo, uint32_t fileVersion)
: isIndirectCommErr(false), result(result), fileHandleID(fileHandleID),
pattern(pattern.clone()), pathInfo(pathInfo), fileVersion(fileVersion)
{
}
void sendResponse(NetMessage::ResponseContext& ctx) override
{
if (isIndirectCommErr)
ctx.sendResponse(
GenericResponseMsg(
GenericRespMsgCode_INDIRECTCOMMERR,
"Communication with storage targets failed"));
else
ctx.sendResponse(
OpenFileRespMsg(
result, fileHandleID, pattern.get(), &pathInfo, fileVersion));
}
bool changesObservableState() const override
{
return !isIndirectCommErr && result == FhgfsOpsErr_SUCCESS;
}
protected:
uint32_t serializerTag() const override { return NETMSGTYPE_OpenFile; }
template<typename This, typename Ctx>
static void serialize(This* obj, Ctx& ctx)
{
ctx
% obj->isIndirectCommErr;
if (!obj->isIndirectCommErr)
ctx
% serdes::as<int32_t>(obj->result)
% obj->fileHandleID
% obj->pattern
% obj->pathInfo;
}
void serializeContents(Serializer& ser) const override
{
serialize(this, ser);
}
private:
bool isIndirectCommErr;
FhgfsOpsErr result;
std::string fileHandleID;
std::unique_ptr<StripePattern> pattern;
PathInfo pathInfo;
uint32_t fileVersion;
};
class OpenFileMsgEx : public MirroredMessage<OpenFileMsg, FileIDLock>
{
public:
typedef OpenFileResponseState ResponseState;
bool processIncoming(ResponseContext& ctx) override;
FileIDLock lock(EntryLockStore& store) override;
std::unique_ptr<MirroredMessageResponseState> executeLocally(ResponseContext& ctx,
bool isSecondary) override;
void forwardToSecondary(ResponseContext& ctx) override;
bool isMirrored() override { return getEntryInfo()->getIsBuddyMirrored(); }
private:
FhgfsOpsErr processSecondaryResponse(NetMessage& resp) override
{
return (FhgfsOpsErr) static_cast<OpenFileRespMsg&>(resp).getResult();
}
const char* mirrorLogContext() const override { return "OpenFileMsgEx/forward"; }
std::string fileHandleID;
};