diff --git a/client_module/build/feature-detect.sh b/client_module/build/feature-detect.sh index dada4686..d6145ae9 100755 --- a/client_module/build/feature-detect.sh +++ b/client_module/build/feature-detect.sh @@ -193,6 +193,11 @@ run_job check_struct_field \ inode::i_mtime \ KERNEL_HAS_INODE_MTIME \ linux/fs.h + +run_job check_struct_field \ + inode::i_write_hint \ + KERNEL_HAS_INODE_I_WRITE_HINT \ + linux/fs.h run_job check_struct_field \ dentry::d_subdirs \ diff --git a/client_module/source/common/net/message/session/rw/WriteLocalFileMsg.c b/client_module/source/common/net/message/session/rw/WriteLocalFileMsg.c index 94d35f82..ba142a11 100644 --- a/client_module/source/common/net/message/session/rw/WriteLocalFileMsg.c +++ b/client_module/source/common/net/message/session/rw/WriteLocalFileMsg.c @@ -41,4 +41,7 @@ void WriteLocalFileMsg_serializePayload(NetMessage* this, SerializeCtx* ctx) // targetID Serialization_serializeUShort(ctx, thisCast->targetID); + + // writeHint + Serialization_serializeUInt64(ctx, thisCast->writeHint); } diff --git a/client_module/source/common/net/message/session/rw/WriteLocalFileMsg.h b/client_module/source/common/net/message/session/rw/WriteLocalFileMsg.h index 07ef6f41..25df1678 100644 --- a/client_module/source/common/net/message/session/rw/WriteLocalFileMsg.h +++ b/client_module/source/common/net/message/session/rw/WriteLocalFileMsg.h @@ -24,7 +24,7 @@ typedef struct WriteLocalFileMsg WriteLocalFileMsg; static inline void WriteLocalFileMsg_init(WriteLocalFileMsg* this); static inline void WriteLocalFileMsg_initFromSession(WriteLocalFileMsg* this, NumNodeID clientNumID, const char* fileHandleID, uint16_t targetID, PathInfo* pathInfo, - unsigned accessFlags, int64_t offset, int64_t count); + unsigned accessFlags, int64_t offset, int64_t count, uint64_t writeHint); // virtual functions extern void WriteLocalFileMsg_serializePayload(NetMessage* this, SerializeCtx* ctx); @@ -51,6 +51,7 @@ struct WriteLocalFileMsg PathInfo* pathInfo; unsigned userID; unsigned groupID; + uint64_t writeHint; }; extern const struct NetMessageOps WriteLocalFileMsg_Ops; @@ -67,7 +68,7 @@ void WriteLocalFileMsg_init(WriteLocalFileMsg* this) void WriteLocalFileMsg_initFromSession(WriteLocalFileMsg* this, NumNodeID clientNumID, const char* fileHandleID, uint16_t targetID, PathInfo* pathInfo, unsigned accessFlags, - int64_t offset, int64_t count) + int64_t offset, int64_t count, uint64_t writeHint) { WriteLocalFileMsg_init(this); @@ -83,6 +84,7 @@ void WriteLocalFileMsg_initFromSession(WriteLocalFileMsg* this, this->offset = offset; this->count = count; + this->writeHint = writeHint; } void WriteLocalFileMsg_setUserdataForQuota(WriteLocalFileMsg* this, unsigned userID, diff --git a/client_module/source/common/net/message/session/rw/WriteLocalFileRDMAMsg.c b/client_module/source/common/net/message/session/rw/WriteLocalFileRDMAMsg.c index 9828f32f..5e3f99c4 100644 --- a/client_module/source/common/net/message/session/rw/WriteLocalFileRDMAMsg.c +++ b/client_module/source/common/net/message/session/rw/WriteLocalFileRDMAMsg.c @@ -45,5 +45,8 @@ void WriteLocalFileRDMAMsg_serializePayload(NetMessage* this, SerializeCtx* ctx) // RDMA info RdmaInfo_serialize(ctx, thisCast->rdmap); + + // writeHint + Serialization_serializeUInt64(ctx, thisCast->writeHint); } #endif /* BEEGFS_NVFS */ diff --git a/client_module/source/common/net/message/session/rw/WriteLocalFileRDMAMsg.h b/client_module/source/common/net/message/session/rw/WriteLocalFileRDMAMsg.h index dafaf6ec..6e002f45 100644 --- a/client_module/source/common/net/message/session/rw/WriteLocalFileRDMAMsg.h +++ b/client_module/source/common/net/message/session/rw/WriteLocalFileRDMAMsg.h @@ -26,7 +26,7 @@ typedef struct WriteLocalFileRDMAMsg WriteLocalFileRDMAMsg; static inline void WriteLocalFileRDMAMsg_init(WriteLocalFileRDMAMsg* this); static inline void WriteLocalFileRDMAMsg_initFromSession(WriteLocalFileRDMAMsg* this, NumNodeID clientNumID, const char* fileHandleID, uint16_t targetID, PathInfo* pathInfo, - unsigned accessFlags, int64_t offset, int64_t count, RdmaInfo *rdmap); + unsigned accessFlags, int64_t offset, int64_t count, uint64_t writeHint, RdmaInfo *rdmap); // virtual functions extern void WriteLocalFileRDMAMsg_serializePayload(NetMessage* this, SerializeCtx* ctx); @@ -53,6 +53,7 @@ struct WriteLocalFileRDMAMsg PathInfo* pathInfo; unsigned userID; unsigned groupID; + uint64_t writeHint; RdmaInfo *rdmap; }; @@ -69,7 +70,7 @@ void WriteLocalFileRDMAMsg_init(WriteLocalFileRDMAMsg* this) */ void WriteLocalFileRDMAMsg_initFromSession(WriteLocalFileRDMAMsg* this, NumNodeID clientNumID, const char* fileHandleID, uint16_t targetID, PathInfo* pathInfo, - unsigned accessFlags, int64_t offset, int64_t count, RdmaInfo *rdmap) + unsigned accessFlags, int64_t offset, int64_t count, uint64_t writeHint, RdmaInfo *rdmap) { WriteLocalFileRDMAMsg_init(this); @@ -85,6 +86,7 @@ void WriteLocalFileRDMAMsg_initFromSession(WriteLocalFileRDMAMsg* this, this->offset = offset; this->count = count; + this->writeHint = writeHint; this->rdmap = rdmap; } diff --git a/client_module/source/filesystem/FhgfsInode.c b/client_module/source/filesystem/FhgfsInode.c index 59321acc..b099368a 100644 --- a/client_module/source/filesystem/FhgfsInode.c +++ b/client_module/source/filesystem/FhgfsInode.c @@ -476,6 +476,12 @@ void __FhgfsInode_initOpenIOInfo(FhgfsInode* this, FhgfsInodeFileHandle* fileHan #ifdef BEEGFS_NVFS outIOInfo->nvfs = false; #endif + +#if defined(KERNEL_HAS_INODE_I_WRITE_HINT) + outIOInfo->writeHint = this->vfs_inode.i_write_hint; +#else + outIOInfo->writeHint = RW_HINT_INVALID; +#endif } /** diff --git a/client_module/source/net/filesystem/FhgfsOpsCommKit.c b/client_module/source/net/filesystem/FhgfsOpsCommKit.c index fcefc304..815d1eff 100644 --- a/client_module/source/net/filesystem/FhgfsOpsCommKit.c +++ b/client_module/source/net/filesystem/FhgfsOpsCommKit.c @@ -1322,7 +1322,8 @@ static unsigned __commkit_writefile_prepareHeader(CommKitContext* context, { WriteLocalFileMsg_initFromSession(&writeMsg, localNodeNumID, context->ioInfo->fileHandleID, info->targetID, context->ioInfo->pathInfo, - context->ioInfo->accessFlags, currentState->offset, currentState->totalSize); + context->ioInfo->accessFlags, currentState->offset, currentState->totalSize, + context->ioInfo->writeHint); netMessage = &writeMsg.netMessage; } @@ -1332,7 +1333,7 @@ static unsigned __commkit_writefile_prepareHeader(CommKitContext* context, WriteLocalFileRDMAMsg_initFromSession(&writeRDMAMsg, localNodeNumID, context->ioInfo->fileHandleID, info->targetID, context->ioInfo->pathInfo, context->ioInfo->accessFlags, currentState->offset, currentState->totalSize, - currentState->rdmap); + context->ioInfo->writeHint, currentState->rdmap); netMessage = &writeRDMAMsg.netMessage; } diff --git a/client_module/source/net/filesystem/FhgfsOpsCommKitVec.c b/client_module/source/net/filesystem/FhgfsOpsCommKitVec.c index 21a129b5..1bcb9d2f 100644 --- a/client_module/source/net/filesystem/FhgfsOpsCommKitVec.c +++ b/client_module/source/net/filesystem/FhgfsOpsCommKitVec.c @@ -678,7 +678,7 @@ void __FhgfsOpsCommKitVec_writefileStagePREPARE(CommKitVecHelper* commHelper, // prepare message WriteLocalFileMsg_initFromSession(&writeMsg, localNodeNumID, commHelper->ioInfo->fileHandleID, comm->targetID, commHelper->ioInfo->pathInfo, - commHelper->ioInfo->accessFlags, offset, remainingDataSize); + commHelper->ioInfo->accessFlags, offset, remainingDataSize, commHelper->ioInfo->writeHint); NetMessage_setMsgHeaderTargetID( (NetMessage*)&writeMsg, nodeReferenceTargetID); diff --git a/client_module/source/net/filesystem/RemotingIOInfo.h b/client_module/source/net/filesystem/RemotingIOInfo.h index 7087d1d6..eb5f6e89 100644 --- a/client_module/source/net/filesystem/RemotingIOInfo.h +++ b/client_module/source/net/filesystem/RemotingIOInfo.h @@ -7,6 +7,7 @@ #include #include +#define RW_HINT_INVALID 0xFF struct RemotingIOInfo; typedef struct RemotingIOInfo RemotingIOInfo; @@ -44,6 +45,7 @@ struct RemotingIOInfo #ifdef BEEGFS_NVFS bool nvfs; #endif + uint64_t writeHint; }; @@ -78,6 +80,8 @@ void RemotingIOInfo_initOpen(App* app, unsigned accessFlags, AtomicInt* maxUsedT #ifdef BEEGFS_NVFS outIOInfo->nvfs = false; #endif + + outIOInfo->writeHint = RW_HINT_INVALID; } @@ -104,6 +108,8 @@ void RemotingIOInfo_initSpecialClose(App* app, const char* fileHandleID, #ifdef BEEGFS_NVFS outIOInfo->nvfs = false; #endif + + outIOInfo->writeHint = RW_HINT_INVALID; } /** diff --git a/common/source/common/net/message/session/rw/WriteLocalFileMsg.h b/common/source/common/net/message/session/rw/WriteLocalFileMsg.h index 9104dd9a..6a8b360e 100644 --- a/common/source/common/net/message/session/rw/WriteLocalFileMsg.h +++ b/common/source/common/net/message/session/rw/WriteLocalFileMsg.h @@ -12,6 +12,7 @@ #define WRITELOCALFILEMSG_FLAG_BUDDYMIRROR_SECOND 16 /* secondary of group, otherwise primary */ #define WRITELOCALFILEMSG_FLAG_BUDDYMIRROR_FORWARD 32 /* forward msg to secondary */ +#define RW_HINT_INVALID 0xFF class WriteLocalFileMsgBase { public: @@ -21,7 +22,7 @@ class WriteLocalFileMsgBase */ WriteLocalFileMsgBase(const NumNodeID clientNumID, const char* fileHandleID, const uint16_t targetID, const PathInfo* pathInfo, const unsigned accessFlags, - const int64_t offset, const int64_t count) + const int64_t offset, const int64_t count, const uint64_t writeHint) { this->clientNumID = clientNumID; @@ -36,6 +37,7 @@ class WriteLocalFileMsgBase this->offset = offset; this->count = count; + this->writeHint = writeHint; } WriteLocalFileMsgBase() {} @@ -57,7 +59,8 @@ class WriteLocalFileMsgBase % serdes::rawString(obj->fileHandleID, obj->fileHandleIDLen, 4) % obj->clientNumID % serdes::backedPtr(obj->pathInfoPtr, obj->pathInfo) - % obj->targetID; + % obj->targetID + % obj->writeHint; } protected: @@ -71,7 +74,7 @@ class WriteLocalFileMsgBase uint32_t userID; uint32_t groupID; - + uint64_t writeHint; // for serialization const PathInfo* pathInfoPtr; @@ -126,6 +129,11 @@ class WriteLocalFileMsgBase return groupID; } + uint64_t getWriteHint() const + { + return writeHint; + } + void setUserdataForQuota(unsigned userID, unsigned groupID) { this->userID = userID; @@ -162,9 +170,9 @@ class WriteLocalFileMsg : public WriteLocalFileMsgBase, public NetMessageSerdes< */ WriteLocalFileMsg(const NumNodeID clientNumID, const char* fileHandleID, const uint16_t targetID, const PathInfo* pathInfo, const unsigned accessFlags, - const int64_t offset, const int64_t count) : + const int64_t offset, const int64_t count, const uint64_t writeHint = RW_HINT_INVALID) : WriteLocalFileMsgBase(clientNumID, fileHandleID, targetID, pathInfo, accessFlags, - offset, count), + offset, count, writeHint), BaseType(NETMSGTYPE_WriteLocalFile) {} /** diff --git a/common/source/common/net/message/session/rw/WriteLocalFileRDMAMsg.h b/common/source/common/net/message/session/rw/WriteLocalFileRDMAMsg.h index 8a3f6123..6154f96c 100644 --- a/common/source/common/net/message/session/rw/WriteLocalFileRDMAMsg.h +++ b/common/source/common/net/message/session/rw/WriteLocalFileRDMAMsg.h @@ -17,8 +17,8 @@ class WriteLocalFileRDMAMsg : public WriteLocalFileMsgBase, public NetMessageSer */ WriteLocalFileRDMAMsg(const NumNodeID clientNumID, const char* fileHandleID, const uint16_t targetID, const PathInfo* pathInfo, const unsigned accessFlags, - const int64_t offset, const int64_t count) : - WriteLocalFileMsgBase(clientNumID, fileHandleID, targetID, pathInfo, accessFlags, offset, count), + const int64_t offset, const int64_t count, const uint64_t writeHint = RW_HINT_INVALID) : + WriteLocalFileMsgBase(clientNumID, fileHandleID, targetID, pathInfo, accessFlags, offset, count, writeHint), BaseType(NETMSGTYPE_WriteLocalFileRDMA) {} /** diff --git a/storage/source/net/message/session/rw/WriteLocalFileMsgEx.cpp b/storage/source/net/message/session/rw/WriteLocalFileMsgEx.cpp index 47d7bd38..41fa6506 100644 --- a/storage/source/net/message/session/rw/WriteLocalFileMsgEx.cpp +++ b/storage/source/net/message/session/rw/WriteLocalFileMsgEx.cpp @@ -523,7 +523,8 @@ FhgfsOpsErr WriteLocalFileMsgExBase::openFile(const StorageTarg SessionQuotaInfo quotaInfo(useQuota, enforceQuota, getUserID(), getGroupID() ); - FhgfsOpsErr openChunkRes = sessionLocalFile->openFile(targetFD, getPathInfo(), true, "aInfo); + FhgfsOpsErr openChunkRes = sessionLocalFile->openFile(targetFD, getPathInfo(), + true, "aInfo, getWriteHint()); return openChunkRes; } @@ -638,7 +639,7 @@ FhgfsOpsErr WriteLocalFileMsgExBase::prepareMirroring(char* buf mirrorToSock = mirrorToNode->getConnPool()->acquireStreamSocket(); WriteLocalFileMsg mirrorWriteMsg(getClientNumID(), getFileHandleID(), getTargetID(), - getPathInfo(), getAccessFlags(), getOffset(), getCount()); + getPathInfo(), getAccessFlags(), getOffset(), getCount(), getWriteHint()); if(doSessionCheck() ) mirrorWriteMsg.addMsgHeaderFeatureFlag(WRITELOCALFILEMSG_FLAG_SESSION_CHECK); @@ -733,7 +734,7 @@ FhgfsOpsErr WriteLocalFileMsgExBase::sendToMirror(const char* b mirrorToSock = mirrorToNode->getConnPool()->acquireStreamSocket(); WriteLocalFileMsg mirrorWriteMsg(getClientNumID(), getFileHandleID(), - getTargetID(), getPathInfo(), getAccessFlags(), offset, toBeMirrored); + getTargetID(), getPathInfo(), getAccessFlags(), offset, toBeMirrored, getWriteHint()); if(doSessionCheck() ) mirrorWriteMsg.addMsgHeaderFeatureFlag(WRITELOCALFILEMSG_FLAG_SESSION_CHECK); diff --git a/storage/source/net/message/session/rw/WriteLocalFileMsgEx.h b/storage/source/net/message/session/rw/WriteLocalFileMsgEx.h index 86ebafaf..304849d6 100644 --- a/storage/source/net/message/session/rw/WriteLocalFileMsgEx.h +++ b/storage/source/net/message/session/rw/WriteLocalFileMsgEx.h @@ -160,6 +160,11 @@ class WriteLocalFileMsgExBase : public Msg { return static_cast(*this).getPathInfo(); } + + inline uint64_t getWriteHint() const + { + return static_cast(*this).getWriteHint(); + } }; /** diff --git a/storage/source/session/SessionLocalFile.cpp b/storage/source/session/SessionLocalFile.cpp index 61f550d2..d38d7210 100644 --- a/storage/source/session/SessionLocalFile.cpp +++ b/storage/source/session/SessionLocalFile.cpp @@ -50,7 +50,7 @@ void SessionLocalFile::serializeNodeID(SessionLocalFile* obj, Deserializer& des) * @param isWriteOpen if set to true, the file will be created if it didn't exist. */ FhgfsOpsErr SessionLocalFile::openFile(int targetFD, const PathInfo* pathInfo, - bool isWriteOpen, const SessionQuotaInfo* quotaInfo) + bool isWriteOpen, const SessionQuotaInfo* quotaInfo, uint64_t writeHint) { FhgfsOpsErr retVal = FhgfsOpsErr_SUCCESS; @@ -94,7 +94,7 @@ FhgfsOpsErr SessionLocalFile::openFile(int targetFD, const PathInfo* pathInfo, FhgfsOpsErr openChunkRes = chunkDirStore->openChunkFile( targetFD, &chunkDirPath, chunkFilePathStr, hasOrigFeature, openFlags, &fd, quotaInfo, - exceededQuotaStore); + exceededQuotaStore, writeHint); // fix chunk path permissions if (unlikely(openChunkRes == FhgfsOpsErr_NOTOWNER && quotaInfo->useQuota) ) @@ -104,7 +104,7 @@ FhgfsOpsErr SessionLocalFile::openFile(int targetFD, const PathInfo* pathInfo, openChunkRes = chunkDirStore->openChunkFile( targetFD, &chunkDirPath, chunkFilePathStr, hasOrigFeature, openFlags, &fd, - quotaInfo, exceededQuotaStore); + quotaInfo, exceededQuotaStore, writeHint); } if (openChunkRes != FhgfsOpsErr_SUCCESS) diff --git a/storage/source/session/SessionLocalFile.h b/storage/source/session/SessionLocalFile.h index 42929f85..ffa49eab 100644 --- a/storage/source/session/SessionLocalFile.h +++ b/storage/source/session/SessionLocalFile.h @@ -10,6 +10,7 @@ #include +#define RW_HINT_INVALID 0xFF /** * Represents the client session information for an open chunk file. */ @@ -97,7 +98,7 @@ class SessionLocalFile } FhgfsOpsErr openFile(int targetFD, const PathInfo* pathInfo, bool isWriteOpen, - const SessionQuotaInfo* quotaInfo); + const SessionQuotaInfo* quotaInfo, uint64_t writeHint = RW_HINT_INVALID); NodeHandle setMirrorNodeExclusive(NodeHandle mirrorNode); diff --git a/storage/source/storage/ChunkStore.cpp b/storage/source/storage/ChunkStore.cpp index ab0f93fc..7d5bbda7 100644 --- a/storage/source/storage/ChunkStore.cpp +++ b/storage/source/storage/ChunkStore.cpp @@ -549,7 +549,7 @@ bool ChunkStore::mkdirChunkDirPath(int targetFD, const Path* chunkDirPath, bool } std::pair ChunkStore::openAndChown(const int targetFD, const std::string& path, - const int openFlags, const SessionQuotaInfo& quota) + const int openFlags, const SessionQuotaInfo& quota, uint64_t writeHint) { // if we aren't using quota, we don't care about the file owner at all and may simply create the // file if it does exist (and if openFlags requests it). @@ -583,6 +583,17 @@ std::pair ChunkStore::openAndChown(const int targetFD, const s return {FhgfsOpsErrTk::fromSysErr(errno), -1}; } + if (writeHint != RW_HINT_INVALID) + { + int r = fcntl(fd, F_SET_RW_HINT, &writeHint); + if (r < 0) + { + LOG(GENERAL, ERR, + "Client requested a write lifetime hint, but server failed to set it.", + ("writeHint", StringTk::uint64ToStr(writeHint)), sysErr); + } + } + if (!quota.useQuota) return {FhgfsOpsErr_SUCCESS, fd}; @@ -607,7 +618,7 @@ std::pair ChunkStore::openAndChown(const int targetFD, const s */ FhgfsOpsErr ChunkStore::openChunkFile(int targetFD, const Path* chunkDirPath, const std::string& chunkFilePathStr, bool hasOrigFeature, int openFlags, int* outFD, - const SessionQuotaInfo* quotaInfo, const ExceededQuotaStorePtr exQuotaStore) + const SessionQuotaInfo* quotaInfo, const ExceededQuotaStorePtr exQuotaStore, uint64_t writeHint) { const char* logContext = "ChunkStore create chunkFile"; FhgfsOpsErr retVal = FhgfsOpsErr_INTERNAL; @@ -637,7 +648,7 @@ FhgfsOpsErr ChunkStore::openChunkFile(int targetFD, const Path* chunkDirPath, } } - std::tie(retVal, *outFD) = openAndChown(targetFD, chunkFilePathStr, openFlags, *quotaInfo); + std::tie(retVal, *outFD) = openAndChown(targetFD, chunkFilePathStr, openFlags, *quotaInfo, writeHint); if (retVal == FhgfsOpsErr_SUCCESS) return FhgfsOpsErr_SUCCESS; @@ -665,7 +676,7 @@ FhgfsOpsErr ChunkStore::openChunkFile(int targetFD, const Path* chunkDirPath, } // dir created => try file open/create again... - std::tie(retVal, *outFD) = openAndChown(targetFD, chunkFilePathStr, openFlags, *quotaInfo); + std::tie(retVal, *outFD) = openAndChown(targetFD, chunkFilePathStr, openFlags, *quotaInfo, writeHint); if (lastChunkDirElement) // old V2 files do not get this { diff --git a/storage/source/storage/ChunkStore.h b/storage/source/storage/ChunkStore.h index d6fe8fe0..60ee5fbb 100644 --- a/storage/source/storage/ChunkStore.h +++ b/storage/source/storage/ChunkStore.h @@ -11,9 +11,14 @@ #include "ChunkDir.h" +#define RW_HINT_INVALID 0xFF #define PATH_DEPTH_IDENTIFIER 'l' // we use 'l' (level) instead of 'd', as d is part of hex numbers +#ifndef F_SET_RW_HINT +#define F_LINUX_SPECIFIC_BASE 1024 +#define F_SET_RW_HINT (F_LINUX_SPECIFIC_BASE + 12) +#endif class ChunkDir; @@ -55,7 +60,7 @@ class ChunkStore FhgfsOpsErr openChunkFile(int targetFD, const Path* chunkDirPath, const std::string& chunkFilePathStr, bool hasOrigFeature, int openFlags, int* outFD, - const SessionQuotaInfo* quotaInfo, const ExceededQuotaStorePtr exQuotaStore); + const SessionQuotaInfo* quotaInfo, const ExceededQuotaStorePtr exQuotaStore, uint64_t writeHint = RW_HINT_INVALID); bool chmodV2ChunkDirPath(int targetFD, const Path* chunkDirPath, const std::string& entryID); @@ -87,7 +92,7 @@ class ChunkStore ChunkDir** outChunkDir); std::pair openAndChown(const int targetFD, const std::string& path, - const int openFlags, const SessionQuotaInfo& quota); + const int openFlags, const SessionQuotaInfo& quota, uint64_t writeHint = RW_HINT_INVALID); // inlined