From 046a3af5851b04e88ff008cdc4c625b7d2078536 Mon Sep 17 00:00:00 2001 From: "qian01.li" Date: Tue, 16 Dec 2025 03:17:52 +0800 Subject: [PATCH 1/2] feat: add support for multi-stream SSDs(such as FDP SSDs) The NVMe SSD (e.g. Flexible Data Placement SSD, TP4146) is supporting to recognize data lifetime information on device. Adding data lifetime information (writeHint) that passed to the devices to achieve lower write amplification and better performance. Kernel file-systems (ext4, XFS, btrfs, F2FS) have already supported to set the writeHint by fcntl(). This patch adds support in BeeGFS for data lifetime information. This patch enables BeeGFS to use multi-stream SSDs, such as FDP SSDs. --- .../net/message/session/rw/WriteLocalFileMsg.c | 3 +++ .../net/message/session/rw/WriteLocalFileMsg.h | 6 ++++-- .../message/session/rw/WriteLocalFileRDMAMsg.c | 3 +++ .../message/session/rw/WriteLocalFileRDMAMsg.h | 6 ++++-- client_module/source/filesystem/FhgfsInode.c | 1 + .../source/net/filesystem/FhgfsOpsCommKit.c | 5 +++-- .../source/net/filesystem/FhgfsOpsCommKitVec.c | 2 +- .../source/net/filesystem/RemotingIOInfo.h | 1 + .../net/message/session/rw/WriteLocalFileMsg.h | 18 +++++++++++++----- .../message/session/rw/WriteLocalFileRDMAMsg.h | 4 ++-- .../message/session/rw/WriteLocalFileMsgEx.cpp | 7 ++++--- .../message/session/rw/WriteLocalFileMsgEx.h | 5 +++++ storage/source/session/SessionLocalFile.cpp | 6 +++--- storage/source/session/SessionLocalFile.h | 3 ++- storage/source/storage/ChunkStore.cpp | 14 ++++++++++---- storage/source/storage/ChunkStore.h | 9 +++++++-- 16 files changed, 66 insertions(+), 27 deletions(-) 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..b87f9649 100644 --- a/client_module/source/filesystem/FhgfsInode.c +++ b/client_module/source/filesystem/FhgfsInode.c @@ -473,6 +473,7 @@ void __FhgfsInode_initOpenIOInfo(FhgfsInode* this, FhgfsInodeFileHandle* fileHan outIOInfo->userID = i_uid_read(&this->vfs_inode); outIOInfo->groupID = i_gid_read(&this->vfs_inode); + outIOInfo->writeHint = this->vfs_inode.i_write_hint; #ifdef BEEGFS_NVFS outIOInfo->nvfs = false; #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..6e9a42d2 100644 --- a/client_module/source/net/filesystem/RemotingIOInfo.h +++ b/client_module/source/net/filesystem/RemotingIOInfo.h @@ -44,6 +44,7 @@ struct RemotingIOInfo #ifdef BEEGFS_NVFS bool nvfs; #endif + uint64_t writeHint; }; diff --git a/common/source/common/net/message/session/rw/WriteLocalFileMsg.h b/common/source/common/net/message/session/rw/WriteLocalFileMsg.h index 9104dd9a..5ae4f7f2 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 unsigned 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..bbf26780 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,12 @@ std::pair ChunkStore::openAndChown(const int targetFD, const s return {FhgfsOpsErrTk::fromSysErr(errno), -1}; } + int r = fcntl(fd, F_SET_RW_HINT, &writeHint); + if (r < 0) { + LOG(GENERAL, ERR, "Failed to set writeHint.", + ("writeHint", StringTk::uint64ToStr(writeHint))); + } + if (!quota.useQuota) return {FhgfsOpsErr_SUCCESS, fd}; @@ -607,7 +613,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 +643,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 +671,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 From 541e206aa3c790e00531c699ad5fd167cd9faa2f Mon Sep 17 00:00:00 2001 From: Qian Li Date: Wed, 14 Jan 2026 03:52:37 +0800 Subject: [PATCH 2/2] perf: check if inode in VFS has i_write_hint field This commit addresses the review comments from commit 046a3af5851b. It includes minor fixes such as correcting field types, refining condition checks, and adding initialization assignments. Additionally, it enhances the PR description with further details on FDP technology and the benchmark results demonstrating WAF reduction. Signed-off-by: Qian Li --- client_module/build/feature-detect.sh | 5 +++++ client_module/source/filesystem/FhgfsInode.c | 7 ++++++- .../source/net/filesystem/RemotingIOInfo.h | 5 +++++ .../net/message/session/rw/WriteLocalFileMsg.h | 2 +- storage/source/storage/ChunkStore.cpp | 13 +++++++++---- 5 files changed, 26 insertions(+), 6 deletions(-) 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/filesystem/FhgfsInode.c b/client_module/source/filesystem/FhgfsInode.c index b87f9649..b099368a 100644 --- a/client_module/source/filesystem/FhgfsInode.c +++ b/client_module/source/filesystem/FhgfsInode.c @@ -473,10 +473,15 @@ void __FhgfsInode_initOpenIOInfo(FhgfsInode* this, FhgfsInodeFileHandle* fileHan outIOInfo->userID = i_uid_read(&this->vfs_inode); outIOInfo->groupID = i_gid_read(&this->vfs_inode); - outIOInfo->writeHint = this->vfs_inode.i_write_hint; #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/RemotingIOInfo.h b/client_module/source/net/filesystem/RemotingIOInfo.h index 6e9a42d2..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; @@ -79,6 +80,8 @@ void RemotingIOInfo_initOpen(App* app, unsigned accessFlags, AtomicInt* maxUsedT #ifdef BEEGFS_NVFS outIOInfo->nvfs = false; #endif + + outIOInfo->writeHint = RW_HINT_INVALID; } @@ -105,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 5ae4f7f2..6a8b360e 100644 --- a/common/source/common/net/message/session/rw/WriteLocalFileMsg.h +++ b/common/source/common/net/message/session/rw/WriteLocalFileMsg.h @@ -22,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 unsigned writeHint) + const int64_t offset, const int64_t count, const uint64_t writeHint) { this->clientNumID = clientNumID; diff --git a/storage/source/storage/ChunkStore.cpp b/storage/source/storage/ChunkStore.cpp index bbf26780..7d5bbda7 100644 --- a/storage/source/storage/ChunkStore.cpp +++ b/storage/source/storage/ChunkStore.cpp @@ -583,10 +583,15 @@ std::pair ChunkStore::openAndChown(const int targetFD, const s return {FhgfsOpsErrTk::fromSysErr(errno), -1}; } - int r = fcntl(fd, F_SET_RW_HINT, &writeHint); - if (r < 0) { - LOG(GENERAL, ERR, "Failed to set writeHint.", - ("writeHint", StringTk::uint64ToStr(writeHint))); + 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)