Commit 0d8b1b1c authored by Bernd Lietzow's avatar Bernd Lietzow

Merge branch 'modsync-v6' into 'v6'

Modsync/locking fixes for v6

See merge request beegfs/projects0!715
parents 8e371141 15039642
......@@ -589,6 +589,8 @@ void InternodeSyncer::syncClients(const std::vector<NodeHandle>& clientsList, bo
EntryInfo* entryInfo = sessionFile->getEntryInfo();
FileIDLock lock(sessions->getEntryLockStore(), entryInfo->getEntryID());
if(allowRemoteComm)
MsgHelperClose::closeChunkFile(sessionID, fileHandleID.c_str(),
maxUsedNodesIndex, *inode, entryInfo, NETMSG_DEFAULT_USERID);
......
......@@ -29,6 +29,8 @@ bool UpdateDirParentMsgEx::processIncoming(ResponseContext& ctx)
(void) entryInfo;
(void) parentNodeID;
rctx = &ctx;
BaseType::processIncoming(ctx);
// update operation counters
......@@ -40,6 +42,9 @@ bool UpdateDirParentMsgEx::processIncoming(ResponseContext& ctx)
DirIDLock UpdateDirParentMsgEx::lock(EntryLockStore& store)
{
if (rctx->isLocallyGenerated())
return {};
return {&store, getEntryInfo()->getEntryID(), true};
}
......
......@@ -23,6 +23,8 @@ class UpdateDirParentMsgEx : public MirroredMessage<UpdateDirParentMsg, DirIDLoc
bool isMirrored() override { return getEntryInfo()->getIsBuddyMirrored(); }
private:
ResponseContext* rctx;
bool forwardToSecondary(ResponseContext& ctx) override;
FhgfsOpsErr processSecondaryResponse(NetMessage& resp) override
......
......@@ -25,99 +25,139 @@
#include <boost/scoped_array.hpp>
RenameV2Locks RenameV2MsgEx::lock(EntryLockStore& store)
{
RenameV2Locks result;
namespace {
struct DirHandle {
MetaStore* metaStore;
const EntryInfo* ei;
MetaStore* metaStore = Program::getApp()->getMetaStore();
DirHandle(MetaStore* metaStore, const EntryInfo* ei): metaStore(metaStore), ei(ei) {}
// take care about lock ordering! see MirroredMessage::lock()
// since directories are locked for read, and by the same id as the (parent,name) tuples,the
// same ordering applies.
if (getFromDirInfo()->getEntryID() < getToDirInfo()->getEntryID())
{
result.fromDirLock = {&store, getFromDirInfo()->getEntryID(), true};
result.toDirLock = {&store, getToDirInfo()->getEntryID(), true};
DirHandle(const DirHandle&) = delete;
DirHandle(DirHandle&&) = delete;
result.fromNameLock = {&store, getFromDirInfo()->getEntryID(), getOldName()};
result.toNameLock = {&store, getToDirInfo()->getEntryID(), getNewName()};
}
else if (getFromDirInfo()->getEntryID() == getToDirInfo()->getEntryID())
{
result.fromDirLock = {&store, getFromDirInfo()->getEntryID(), true};
DirHandle& operator=(const DirHandle&) = delete;
DirHandle& operator=(DirHandle&&) = delete;
if (getOldName() < getNewName())
{
result.fromNameLock = {&store, getFromDirInfo()->getEntryID(), getOldName()};
result.toNameLock = {&store, getToDirInfo()->getEntryID(), getNewName()};
}
else if (getOldName() == getNewName())
{
result.fromNameLock = {&store, getFromDirInfo()->getEntryID(), getOldName()};
}
else
{
result.toNameLock = {&store, getToDirInfo()->getEntryID(), getNewName()};
result.fromNameLock = {&store, getFromDirInfo()->getEntryID(), getOldName()};
}
}
else
{
result.toDirLock = {&store, getToDirInfo()->getEntryID(), true};
result.fromDirLock = {&store, getFromDirInfo()->getEntryID(), true};
result.toNameLock = {&store, getToDirInfo()->getEntryID(), getNewName()};
result.fromNameLock = {&store, getFromDirInfo()->getEntryID(), getOldName()};
~DirHandle() {
metaStore->releaseDir(ei->getEntryID());
}
};
}
EntryInfo fromFileInfo;
EntryInfo toFileInfo;
RenameV2Locks RenameV2MsgEx::lock(EntryLockStore& store)
{
MetaStore* metaStore = Program::getApp()->getMetaStore();
DirInode* fromDir = metaStore->referenceDir(getFromDirInfo()->getEntryID(),
getFromDirInfo()->getIsBuddyMirrored(), true);
// if the directory could not be referenced it does not exist on the current node. this will
// cause the operation to fail lateron during executeLocally() when we reference the same
// directory again. since we cannot do anything without having access to the source directory,
// and since no directory with the same id as the source directory can appear after the source
// directory has been removed, we can safely unlock everything right here and continue without
// blocking other workers on the (probably live) target directory.
DirInode* fromDir = metaStore->referenceDir(getFromDirInfo()->getEntryID(),
getFromDirInfo()->getIsBuddyMirrored(), true);
if (!fromDir)
return {};
else
{
const DirHandle _from(metaStore, getFromDirInfo());
DirInode* toDir = metaStore->referenceDir(getToDirInfo()->getEntryID(),
getToDirInfo()->getIsBuddyMirrored(), true);
if (!toDir)
return {};
const DirHandle _to(metaStore, getToDirInfo());
for (;;) {
RenameV2Locks result;
EntryInfo fromFileInfo;
EntryInfo toFileInfo;
fromDir->getFileEntryInfo(getOldName(), fromFileInfo);
if (getFromDirInfo()->getEntryID() == getToDirInfo()->getEntryID())
fromDir->getFileEntryInfo(getNewName(), toFileInfo);
toDir->getFileEntryInfo(getNewName(), toFileInfo);
metaStore->releaseDir(getFromDirInfo()->getEntryID());
}
{
std::map<std::string, DirIDLock*> lockOrder;
if (DirEntryType_ISFILE(fromFileInfo.getEntryType()) && fromFileInfo.getIsInlined())
{
if (DirEntryType_ISFILE(toFileInfo.getEntryType()) && toFileInfo.getIsInlined())
lockOrder.insert(std::make_pair(getFromDirInfo()->getEntryID(), &result.fromDirLock));
lockOrder.insert(std::make_pair(getToDirInfo()->getEntryID(), &result.toDirLock));
if (DirEntryType_ISDIR(fromFileInfo.getEntryType()))
lockOrder.insert(std::make_pair(fromFileInfo.getEntryID(), &result.fromFileLockD));
for (auto it = lockOrder.begin(); it != lockOrder.end(); ++it)
*it->second = {&store, it->first, true};
}
// we might have locked fromFileLockD before fromDirLock due to ordering. resolve the source
// once more and check that we still refer to the same id, otherwise retry until we have the
// correct inode.
// if the name went away we don't have to retry (it can't be created while the dir is locked),
// but retrying is simpler to do.
EntryInfo fromFileInfoCheck;
fromDir->getFileEntryInfo(getOldName(), fromFileInfoCheck);
if (fromFileInfo.getEntryID() != fromFileInfoCheck.getEntryID())
continue;
// take care about lock ordering! see MirroredMessage::lock()
// since directories are locked for read, and by the same id as the (parent,name) tuples,the
// same ordering applies.
if (getFromDirInfo()->getEntryID() < getToDirInfo()->getEntryID())
{
result.fromNameLock = {&store, getFromDirInfo()->getEntryID(), getOldName()};
result.toNameLock = {&store, getToDirInfo()->getEntryID(), getNewName()};
}
else if (getFromDirInfo()->getEntryID() == getToDirInfo()->getEntryID())
{
if (fromFileInfo.getEntryID() < toFileInfo.getEntryID())
if (getOldName() < getNewName())
{
result.fromFileLock = {&store, fromFileInfo.getEntryID()};
result.unlinkedFileLock = {&store, toFileInfo.getEntryID()};
result.fromNameLock = {&store, getFromDirInfo()->getEntryID(), getOldName()};
result.toNameLock = {&store, getToDirInfo()->getEntryID(), getNewName()};
}
else if (fromFileInfo.getEntryID() == toFileInfo.getEntryID())
else if (getOldName() == getNewName())
{
result.fromFileLock = {&store, fromFileInfo.getEntryID()};
result.fromNameLock = {&store, getFromDirInfo()->getEntryID(), getOldName()};
}
else
{
result.unlinkedFileLock = {&store, toFileInfo.getEntryID()};
result.fromFileLock = {&store, fromFileInfo.getEntryID()};
result.toNameLock = {&store, getToDirInfo()->getEntryID(), getNewName()};
result.fromNameLock = {&store, getFromDirInfo()->getEntryID(), getOldName()};
}
}
else
{
result.fromFileLock = {&store, fromFileInfo.getEntryID()};
result.toNameLock = {&store, getToDirInfo()->getEntryID(), getNewName()};
result.fromNameLock = {&store, getFromDirInfo()->getEntryID(), getOldName()};
}
if (DirEntryType_ISFILE(fromFileInfo.getEntryType()) && fromFileInfo.getIsInlined())
{
if (DirEntryType_ISFILE(toFileInfo.getEntryType()) && toFileInfo.getIsInlined())
{
if (fromFileInfo.getEntryID() < toFileInfo.getEntryID())
{
result.fromFileLockF = {&store, fromFileInfo.getEntryID()};
result.unlinkedFileLock = {&store, toFileInfo.getEntryID()};
}
else if (fromFileInfo.getEntryID() == toFileInfo.getEntryID())
{
result.fromFileLockF = {&store, fromFileInfo.getEntryID()};
}
else
{
result.unlinkedFileLock = {&store, toFileInfo.getEntryID()};
result.fromFileLockF = {&store, fromFileInfo.getEntryID()};
}
}
else
{
result.fromFileLockF = {&store, fromFileInfo.getEntryID()};
}
}
}
return result;
return result;
}
}
bool RenameV2MsgEx::processIncoming(ResponseContext& ctx)
......
......@@ -16,7 +16,8 @@ struct RenameV2Locks
DirIDLock toDirLock;
// source file must be locked because concurrent modifications of file attributes may
// race with the moving operation between two servers.
FileIDLock fromFileLock;
FileIDLock fromFileLockF;
DirIDLock fromFileLockD;
// if target exists, the target file must be unlocked to exclude concurrent operations on
// target (eg close, setxattr, ...)
FileIDLock unlinkedFileLock;
......@@ -43,7 +44,8 @@ struct RenameV2Locks
std::swap(toNameLock, other.toNameLock);
std::swap(fromDirLock, other.fromDirLock);
std::swap(toDirLock, other.toDirLock);
std::swap(fromFileLock, other.fromFileLock);
std::swap(fromFileLockF, other.fromFileLockF);
std::swap(fromFileLockD, other.fromFileLockD);
std::swap(unlinkedFileLock, other.unlinkedFileLock);
}
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment