beegfs/meta/source/storage/DiskMetaData.cpp
2025-08-10 01:34:16 +02:00

852 lines
26 KiB
C++

/*
* Dentry and inode serialization/deserialization.
*
* Note: Currently inodes and dentries are stored in exactly the same format, even if
* inodes are not inlined into a dentry.
* If we should add another inode-only format, all code linking inodes to dentries
* e.g. (MetaStore::unlinkInodeLaterUnlocked() calling dirInode->linkInodeToDir() must
* be updated.
*/
#include <program/Program.h>
#include <common/storage/StorageDefinitions.h>
#include "DiskMetaData.h"
#include "DirInode.h"
#include "FileInode.h"
#include "DirEntry.h"
#define DISKMETADATA_LOG_CONTEXT "DiskMetadata"
// 8-bit
#define DIRENTRY_STORAGE_FORMAT_VER2 2 // version beginning with release 2011.04
#define DIRENTRY_STORAGE_FORMAT_VER3 3 // version, same as V2, but removes the file name
// from the dentry (for dir.dentries)
#define DIRENTRY_STORAGE_FORMAT_VER4 4 // version, which includes inlined inodes, deprecated
#define DIRENTRY_STORAGE_FORMAT_VER5 5 /* version, which includes inlined inodes
* and chunk-path V3, StatData have a flags field */
#define DIRENTRY_STORAGE_FORMAT_VER6 6 /* VER5 + additional storage pool in pattern */
// 8-bit
#define DIRECTORY_STORAGE_FORMAT_VER1 1 // 16 bit node IDs
#define DIRECTORY_STORAGE_FORMAT_VER2 2 // 32 bit node IDs
#define DIRECTORY_STORAGE_FORMAT_VER3 3 // 32 bit node IDs + storage pool in pattern
void DiskMetaData::serializeFileInode(Serializer& ser)
{
// inodeData set in constructor
if (!DirEntryType_ISVALID(this->dentryDiskData->getDirEntryType() ) )
{
StatData* statData = this->inodeData->getInodeStatData();
unsigned mode = statData->getMode();
DirEntryType entryType = MetadataTk::posixFileTypeToDirEntryType(mode);
this->dentryDiskData->setDirEntryType(entryType);
#ifdef BEEGFS_DEBUG
const char* logContext = "Serialize FileInode";
LogContext(logContext).logErr("Bug: entryType not set!");
LogContext(logContext).logBacktrace();
#endif
}
/* We use this method to clone inodes which might be inlined into a dentry, so the real
* meta type depends on if the inode is inlined or not. */
DiskMetaDataType metaDataType;
if (this->dentryDiskData->dentryFeatureFlags & DENTRY_FEATURE_INODE_INLINE)
metaDataType = DiskMetaDataType_FILEDENTRY;
else
metaDataType = DiskMetaDataType_FILEINODE;
serializeInDentryFormat(ser, metaDataType);
}
void DiskMetaData::serializeDentry(Serializer& ser)
{
DiskMetaDataType metaDataType;
if (DirEntryType_ISDIR(this->dentryDiskData->getDirEntryType() ) )
metaDataType = DiskMetaDataType_DIRDENTRY;
else
metaDataType = DiskMetaDataType_FILEDENTRY;
serializeInDentryFormat(ser, metaDataType);
}
/*
* Note: Current object state is used for the serialization
*/
void DiskMetaData::serializeInDentryFormat(Serializer& ser, DiskMetaDataType metaDataType)
{
// note: the total amount of serialized data may not be larger than DIRENTRY_SERBUF_SIZE
int dentryFormatVersion;
// set the type into the entry (1 byte)
ser % uint8_t(metaDataType);
// storage-format-version (1 byte)
if (DirEntryType_ISDIR(this->dentryDiskData->getDirEntryType()))
{
// metadata format version-3 for directories
ser % uint8_t(DIRENTRY_STORAGE_FORMAT_VER3);
dentryFormatVersion = DIRENTRY_STORAGE_FORMAT_VER3;
}
else
{
if (metaDataType == DiskMetaDataType_FILEINODE)
{
dentryFormatVersion = DIRENTRY_STORAGE_FORMAT_VER6;
}
else if ((!(this->dentryDiskData->getDentryFeatureFlags() &
DENTRY_FEATURE_INODE_INLINE)))
{
dentryFormatVersion = DIRENTRY_STORAGE_FORMAT_VER3;
}
else if (this->inodeData->getOrigFeature() == FileInodeOrigFeature_TRUE)
dentryFormatVersion = DIRENTRY_STORAGE_FORMAT_VER6;
else
dentryFormatVersion = DIRENTRY_STORAGE_FORMAT_VER4;
// metadata format version-4 for files (inlined inodes)
ser % uint8_t(dentryFormatVersion);
}
// dentry feature flags (2 bytes)
// note: for newly written/serialized dentries we always use the long nodeIDs
this->dentryDiskData->addDentryFeatureFlag(DENTRY_FEATURE_32BITIDS);
ser % uint16_t(this->dentryDiskData->getDentryFeatureFlags());
// entryType (1 byte)
// (note: we have a fixed position for the entryType byte: DIRENTRY_TYPE_BUF_POS)
ser % uint8_t(this->dentryDiskData->getDirEntryType());
// 3 bytes padding for 8 byte alignment
ser.skip(3);
// end of 8 byte header
switch (dentryFormatVersion)
{
case DIRENTRY_STORAGE_FORMAT_VER3:
serializeDentryV3(ser); // V3, currently for dirs only
break;
case DIRENTRY_STORAGE_FORMAT_VER4:
serializeDentryV4(ser); // V4 for files with inlined inodes
break;
case DIRENTRY_STORAGE_FORMAT_VER5: // gets automatically upgraded to v6
dentryFormatVersion = DIRENTRY_STORAGE_FORMAT_VER6; // inlined inodes + chunk-path-V3
inodeData->getStripePattern()->setStoragePoolId(StoragePoolStore::DEFAULT_POOL_ID);
BEEGFS_FALLTHROUGH;
case DIRENTRY_STORAGE_FORMAT_VER6:
serializeDentryV6(ser); // inlined inodes + chunk-path-V3 + storage pools in pattern
break;
}
}
/*
* Deserialize a dentry buffer. Here we only deserialize basic values and will continue with
* version specific dentry sub functions.
*
* Note: Applies deserialized data directly to the current object
*/
void DiskMetaData::deserializeDentry(Deserializer& des)
{
const char* logContext = DISKMETADATA_LOG_CONTEXT " (Dentry Deserialization)";
// note: assumes that the total amount of serialized data may not be larger than
// DIRENTRY_SERBUF_SIZE
uint8_t formatVersion; // which dentry format version
{
uint8_t metaDataType;
des % metaDataType;
}
des % formatVersion;
{ // dentry feature flags
uint16_t dentryFeatureFlags;
des % dentryFeatureFlags;
if (!des.good())
{
std::string serialType = "Feature flags";
LogContext(logContext).logErr("Deserialization failed: " + serialType);
return;
}
bool compatCheckRes = checkFeatureFlagsCompat(
dentryFeatureFlags, getSupportedDentryFeatureFlags() );
if(unlikely(!compatCheckRes) )
{
des.setBad();
LOG(GENERAL, ERR, "Incompatible DirEntry feature flags found.", hex(dentryFeatureFlags),
hex(getSupportedDentryFeatureFlags()));
return;
}
this->dentryDiskData->setDentryFeatureFlags(dentryFeatureFlags);
}
{
// (note: we have a fixed position for the entryType byte: DIRENTRY_TYPE_BUF_POS)
uint8_t type;
des % type;
this->dentryDiskData->setDirEntryType((DirEntryType)type );
}
// mirrorNodeID (depends on feature flag) + padding
if(this->dentryDiskData->getDentryFeatureFlags() & DENTRY_FEATURE_MIRRORED)
{ // mirrorNodeID + padding
// Note: we have an old-style mirrored file here; what we do is just throw away the mirror
// information here, because we don't need it; when the file gets written back to disk it
// will be written as unmirrored file!
// first of all strip the feature flag, so we do not write it to disk again
this->dentryDiskData->removeDentryFeatureFlag(DENTRY_FEATURE_MIRRORED);
uint16_t mirrorNodeID; // will be thrown away
des % mirrorNodeID;
// 1 byte padding for 8 byte aligned header
des.skip(1);
}
else
{ // 3 bytes padding for 8 byte aligned header
des.skip(3);
}
// end of 8-byte header
switch (formatVersion)
{
case DIRENTRY_STORAGE_FORMAT_VER3:
deserializeDentryV3(des);
return;
case DIRENTRY_STORAGE_FORMAT_VER4:
{
// data inlined, so this node must be the owner
App* app = Program::getApp();
MirrorBuddyGroupMapper* metaBuddyGroupMapper = app->getMetaBuddyGroupMapper();
deserializeDentryV4(des);
if (!des.good())
return;
// setting the owner node ID is a manual action, as it is not saved on disk
// depending on whether the file is mirrored or not, we set nodeID oder buddyGroupID here
NumNodeID ownerNodeID = this->inodeData->getIsBuddyMirrored() ?
NumNodeID(metaBuddyGroupMapper->getLocalGroupID() ) : app->getLocalNode().getNumID();
this->dentryDiskData->setOwnerNodeID(ownerNodeID);
this->inodeData->setOrigFeature(FileInodeOrigFeature_FALSE); // V4 does not have it
} break;
case DIRENTRY_STORAGE_FORMAT_VER5:
{
// data inlined, so this node must be the owner
App* app = Program::getApp();
MirrorBuddyGroupMapper* metaBuddyGroupMapper = app->getMetaBuddyGroupMapper();
deserializeDentryV5(des);
if (!des.good())
return;
// setting the owner node ID is a manual action, as it is not saved on disk
// depending on whether the file is mirrored or not, we set nodeID oder buddyGroupID here
NumNodeID ownerNodeID = this->inodeData->getIsBuddyMirrored() ?
NumNodeID(metaBuddyGroupMapper->getLocalGroupID() ) : app->getLocalNode().getNumID();
this->dentryDiskData->setOwnerNodeID(ownerNodeID);
this->inodeData->setOrigFeature(FileInodeOrigFeature_TRUE); // V5 has the origFeature
// for upgrade to V6 format, immediately add pool ID
inodeData->getStripePattern()->setStoragePoolId(StoragePoolStore::DEFAULT_POOL_ID);
} break;
case DIRENTRY_STORAGE_FORMAT_VER6:
{
// data inlined, so this node must be the owner
App* app = Program::getApp();
MirrorBuddyGroupMapper* metaBuddyGroupMapper = app->getMetaBuddyGroupMapper();
deserializeDentryV6(des);
if (!des.good())
return;
// setting the owner node ID is a manual action, as it is not saved on disk
// depending on whether the file is mirrored or not, we set nodeID oder buddyGroupID here
NumNodeID ownerNodeID = this->inodeData->getIsBuddyMirrored() ?
NumNodeID(metaBuddyGroupMapper->getLocalGroupID() ) : app->getLocalNode().getNumID();
this->dentryDiskData->setOwnerNodeID(ownerNodeID);
this->inodeData->setOrigFeature(FileInodeOrigFeature_TRUE); // V5 has the origFeature
} break;
default:
LogContext(logContext).logErr("Invalid Storage Format: " +
StringTk::uintToStr((unsigned) formatVersion) );
des.setBad();
}
}
/*
* Version 3 format, now only used for directories and for example for disposal files
*/
void DiskMetaData::serializeDentryV3(Serializer& ser)
{
ser
% serdes::stringAlign4(this->dentryDiskData->getEntryID())
% this->dentryDiskData->getOwnerNodeID();
}
/**
* Deserialize dentries, which have the V3 format.
*/
void DiskMetaData::deserializeDentryV3(Deserializer& des)
{
{
std::string entryID;
des % serdes::stringAlign4(entryID);
this->dentryDiskData->setEntryID(entryID);
this->inodeData->setEntryID(entryID);
}
if (this->dentryDiskData->getDentryFeatureFlags() & DENTRY_FEATURE_32BITIDS)
{
// dentry uses 32 bit nodeIDs, so we can just use our regular NumNodeIDs
NumNodeID ownerNodeID;
des % ownerNodeID;
this->dentryDiskData->setOwnerNodeID(ownerNodeID);
}
else
{
// dentry uses old-style 16 bit nodeIDs
uint16_t ownerNodeID;
des % ownerNodeID;
this->dentryDiskData->setOwnerNodeID(NumNodeID(ownerNodeID));
}
}
/*
* Version 4 format, for files with inlined inodes
*/
void DiskMetaData::serializeDentryV4(Serializer& ser)
{
StatData* statData = this->inodeData->getInodeStatData();
StripePattern* stripePattern = this->inodeData->getPattern();
ser % inodeData->getInodeFeatureFlags();
ser.skip(4); // unused, was the chunkHash
ser
% statData->serializeAs(StatDataFormat_DENTRYV4)
% serdes::stringAlign4(this->dentryDiskData->getEntryID())
% stripePattern;
if (inodeData->getInodeFeatureFlags() & FILEINODE_FEATURE_HAS_VERSIONS)
{
ser % inodeData->getFileVersion();
ser % inodeData->getMetaVersion();
}
}
/**
* Deserialize dentries, which have the V4 format, which includes inlined inodes and have the old
* chunk path (V1, by directly in hash dirs)
*/
void DiskMetaData::deserializeDentryV4(Deserializer& des)
{
uint32_t inodeFeatureFlags;
{
des % inodeFeatureFlags;
if (!des.good())
return;
bool compatCheckRes = checkFeatureFlagsCompat(
inodeFeatureFlags, getSupportedDentryV4FileInodeFeatureFlags() );
if(unlikely(!compatCheckRes) )
{
des.setBad();
LOG(GENERAL, ERR, "Incompatible FileInode feature flags found.", hex(inodeFeatureFlags),
hex(getSupportedDentryV4FileInodeFeatureFlags()));
return;
}
this->inodeData->setInodeFeatureFlags(inodeFeatureFlags);
}
// unused, was the chunkHash
des.skip(4);
des % this->inodeData->getInodeStatData()->serializeAs(StatDataFormat_DENTRYV4);
// note: up to here only fixed integers length, below follow variable string lengths
{
std::string entryID;
des % serdes::stringAlign4(entryID);
this->dentryDiskData->setEntryID(entryID);
this->inodeData->setEntryID(entryID);
}
// mirrorNodeID (depends on feature flag)
if(inodeFeatureFlags & FILEINODE_FEATURE_MIRRORED)
{
// Note: we have an old-style mirrored file here; what we do is just throw away the mirror
// information here, because we don't need it; when the file gets written back to disk it
// will be written as unmirrored file!
// first of all strip the feature flag, so we do not write it to disk again
this->inodeData->removeInodeFeatureFlag(FILEINODE_FEATURE_MIRRORED);
uint16_t mirrorNodeID; // will be thrown away
des % mirrorNodeID;
}
{
StripePattern* pattern = StripePattern::deserialize(des, false);
this->inodeData->setPattern(pattern);
}
if (inodeFeatureFlags & FILEINODE_FEATURE_HAS_VERSIONS)
{
des % inodeData->fileVersion;
des % inodeData->metaVersion;
}
inodeData->addInodeFeatureFlag(FILEINODE_FEATURE_HAS_VERSIONS);
// sanity checks
#ifdef BEEGFS_DEBUG
const char* logContext = DISKMETADATA_LOG_CONTEXT " (Dentry Deserialization V4)";
if (unlikely(!(this->dentryDiskData->getDentryFeatureFlags() & DENTRY_FEATURE_IS_FILEINODE)))
{
LogContext(logContext).logErr("Bug: inode data successfully deserialized, but "
"the file-inode flag is not set. ");
return;
}
#endif
}
/*
* Version 6 format, for files with inlined inodes and orig-parentID + orig-UID + storage pool
*
* Note: Serialization in V5 is not supported any longer => auto upgrade to v6
*/
void DiskMetaData::serializeDentryV6(Serializer& ser)
{
StatData* statData = this->inodeData->getInodeStatData();
StripePattern* stripePattern = this->inodeData->getPattern();
uint32_t inodeFeatureFlags = inodeData->getInodeFeatureFlags();
ser % inodeFeatureFlags;
if (inodeFeatureFlags & FILEINODE_FEATURE_HAS_STATE_FLAGS)
{
ser % inodeData->getFileState();
ser.skip(3); // unused (3 bytes) for 8 byte alignment
}
else
{
// unused, for alignment
ser.skip(4);
}
ser % statData->serializeAs(StatDataFormat_FILEINODE);
if (inodeFeatureFlags & FILEINODE_FEATURE_HAS_ORIG_UID)
ser % this->inodeData->getOrigUID();
if (inodeFeatureFlags & FILEINODE_FEATURE_HAS_ORIG_PARENTID)
ser % serdes::stringAlign4(this->inodeData->getOrigParentEntryID());
ser
% serdes::stringAlign4(this->dentryDiskData->getEntryID())
% stripePattern;
if (inodeData->getInodeFeatureFlags() & FILEINODE_FEATURE_HAS_VERSIONS)
{
ser % inodeData->getFileVersion();
ser % inodeData->getMetaVersion();
}
}
/**
* Deserialize dentries, which have the V5 or V6 format. Both include inlined inodes and have the
* new chunk path (V2, which has UID and parentID); Additionally, V6 has a storage pool in stripe
* pattern
*/
void DiskMetaData::deserializeDentryV5V6(Deserializer& des, bool hasStoragePool)
{
unsigned inodeFeatureFlags;
{
des % inodeFeatureFlags;
if (!des.good())
return;
bool compatCheckRes = checkFeatureFlagsCompat(
inodeFeatureFlags, getSupportedDentryV5FileInodeFeatureFlags() );
if(unlikely(!compatCheckRes) )
{
des.setBad();
LOG(GENERAL, ERR, "Incompatible FileInode feature flags found.", hex(inodeFeatureFlags),
hex(getSupportedDentryV5FileInodeFeatureFlags()));
return;
}
this->inodeData->setInodeFeatureFlags(inodeFeatureFlags);
}
if (inodeFeatureFlags & FILEINODE_FEATURE_HAS_STATE_FLAGS)
{
uint8_t state;
des % state;
this->inodeData->setFileState(state);
// unused, for alignment
des.skip(3);
}
else
{
// unused, for alignment
des.skip(4);
}
StatData* statData = this->inodeData->getInodeStatData();
des % statData->serializeAs(StatDataFormat_FILEINODE);
if (inodeFeatureFlags & FILEINODE_FEATURE_HAS_ORIG_UID)
{
unsigned origParentUID;
des % origParentUID;
this->inodeData->setOrigUID(origParentUID);
}
else
{ // no separate field, orig-UID and UID are identical
unsigned origParentUID = statData->getUserID();
this->inodeData->setOrigUID(origParentUID);
}
if (inodeFeatureFlags & FILEINODE_FEATURE_HAS_ORIG_PARENTID)
{
std::string origParentEntryID;
des % serdes::stringAlign4(origParentEntryID);
this->inodeData->setDiskOrigParentEntryID(origParentEntryID);
}
// note: up to here only fixed integers length, below follow variable string lengths
{
std::string entryID;
des % serdes::stringAlign4(entryID);
this->dentryDiskData->setEntryID(entryID);
this->inodeData->setEntryID(entryID);
}
if(inodeFeatureFlags & FILEINODE_FEATURE_MIRRORED)
{
// Note: we have an old-style mirrored file here; what we do is just throw away the mirror
// information here, because we don't need it; when the file gets written back to disk it
// will be written as unmirrored file!
// first of all strip the feature flag, so we do not write it to disk again
this->inodeData->removeInodeFeatureFlag(FILEINODE_FEATURE_MIRRORED);
uint16_t mirrorNodeID; // will be thrown away
des % mirrorNodeID;
}
{
StripePattern* pattern = StripePattern::deserialize(des, hasStoragePool);
this->inodeData->setPattern(pattern);
}
if (inodeFeatureFlags & FILEINODE_FEATURE_HAS_VERSIONS)
{
des % inodeData->fileVersion;
des % inodeData->metaVersion;
}
inodeData->addInodeFeatureFlag(FILEINODE_FEATURE_HAS_VERSIONS);
}
void DiskMetaData::deserializeDentryV5(Deserializer& des)
{
// sanity checks
deserializeDentryV5V6(des, false);
#ifdef BEEGFS_DEBUG
const char* logContext = DISKMETADATA_LOG_CONTEXT " (Dentry Deserialization V5)";
if (unlikely(!(this->dentryDiskData->getDentryFeatureFlags() & DENTRY_FEATURE_IS_FILEINODE)))
{
LogContext(logContext).logErr("Bug: inode data successfully deserialized, but "
"the file-inode flag is not set. ");
return;
}
#endif
}
void DiskMetaData::deserializeDentryV6(Deserializer& des)
{
// sanity checks
deserializeDentryV5V6(des, true);
#ifdef BEEGFS_DEBUG
const char* logContext = DISKMETADATA_LOG_CONTEXT " (Dentry Deserialization V6)";
if (unlikely(!(this->dentryDiskData->getDentryFeatureFlags() & DENTRY_FEATURE_IS_FILEINODE)))
{
LogContext(logContext).logErr("Bug: inode data successfully deserialized, but "
"the file-inode flag is not set. ");
return;
}
#endif
}
/**
* This method is for file-inodes located in the inode-hash directories.
*/
void DiskMetaData::deserializeFileInode(Deserializer& des)
{
// right now file inodes are stored in the dentry format only, that will probably change
// later on.
return deserializeDentry(des);
}
template<typename Inode, typename Ctx>
void DiskMetaData::serializeDirInodeCommonData(Inode& inode, Ctx& ctx)
{
if (likely(inode.featureFlags & DIRINODE_FEATURE_EARLY_SUBDIRS))
ctx % inode.numSubdirs;
ctx % inode.statData.serializeAs(
inode.featureFlags & DIRINODE_FEATURE_STATFLAGS
? StatDataFormat_DIRINODE
: StatDataFormat_DIRINODE_NOFLAGS);
if (unlikely(!(inode.featureFlags & DIRINODE_FEATURE_EARLY_SUBDIRS)))
ctx % inode.numSubdirs;
ctx
% inode.numFiles
% serdes::stringAlign4(inode.id)
% serdes::stringAlign4(inode.parentDirID);
}
/*
* Note: Current object state is used for the serialization
*/
void DiskMetaData::serializeDirInode(Serializer& ser, DirInode& inode)
{
// note: the total amount of serialized data may not be larger than META_SERBUF_SIZE
inode.featureFlags |= (DIRINODE_FEATURE_EARLY_SUBDIRS | DIRINODE_FEATURE_STATFLAGS);
ser
% uint8_t(DiskMetaDataType_DIRINODE)
% uint8_t(DIRECTORY_STORAGE_FORMAT_VER3)
% inode.featureFlags;
serializeDirInodeCommonData<const DirInode>(inode, ser);
ser
% inode.ownerNodeID
% inode.parentNodeID
% inode.stripePattern;
}
/*
* Deserialize a DirInode
*
* Note: Applies deserialized data directly to the current object
*
*/
void DiskMetaData::deserializeDirInode(Deserializer& des, DirInode& outInode)
{
const char* logContext = DISKMETADATA_LOG_CONTEXT " (DirInode Deserialization)";
// note: assumes that the total amount of serialized data may not be larger than META_SERBUF_SIZE
uint8_t formatVersion;
{
uint8_t metaDataType;
des % metaDataType;
if (unlikely(des.good() && metaDataType != DiskMetaDataType_DIRINODE))
{
LogContext(logContext).logErr(
std::string("Deserialization failed: expected DirInode, but got (numeric type): ")
+ StringTk::uintToStr((unsigned) metaDataType) );
des.setBad();
return;
}
}
des % formatVersion;
{
des % outInode.featureFlags;
if (!des.good())
return;
bool compatCheckRes = checkFeatureFlagsCompat(
outInode.featureFlags, getSupportedDirInodeFeatureFlags() );
if(unlikely(!compatCheckRes) )
{
LogContext(logContext).logErr("Incompatible DirInode feature flags found. "
"Used flags (hex): " + StringTk::uintToHexStr(outInode.featureFlags) + "; "
"Supported (hex): " + StringTk::uintToHexStr(getSupportedDirInodeFeatureFlags() ) );
des.setBad();
return;
}
}
serializeDirInodeCommonData(outInode, des);
bool hasStoragePool;
switch (formatVersion)
{
case DIRECTORY_STORAGE_FORMAT_VER1:
{
uint16_t ownerNode;
uint16_t parentNode;
des
% ownerNode
% parentNode;
outInode.ownerNodeID = NumNodeID(ownerNode);
outInode.parentNodeID = NumNodeID(parentNode);
hasStoragePool = false;
break;
}
case DIRECTORY_STORAGE_FORMAT_VER2:
{
des
% outInode.ownerNodeID
% outInode.parentNodeID;
hasStoragePool = false;
break;
}
case DIRECTORY_STORAGE_FORMAT_VER3:
{
des
% outInode.ownerNodeID
% outInode.parentNodeID;
hasStoragePool = true;
break;
}
default:
{
LogContext(logContext).logErr("Incompatible DirInode version found. "
"Version:" + StringTk::uintToStr(formatVersion));
des.setBad();
return;
}
}
// mirrorNodeID (depends on feature flag)
if(outInode.featureFlags & DIRINODE_FEATURE_MIRRORED)
{
// Note: we have an old-style mirrored file here; what we do is just throw away the mirror
// information here, because we don't need it; when the file gets written back to disk it
// will be written as unmirrored file!
// first of all strip the feature flag, so we do not write it to disk again
outInode.removeFeatureFlag(DIRINODE_FEATURE_MIRRORED);
uint16_t mirrorNodeID; // will be thrown away
des % mirrorNodeID;
}
outInode.stripePattern = StripePattern::deserialize(des, hasStoragePool);
if (!hasStoragePool)
outInode.getStripePattern()->setStoragePoolId(StoragePoolStore::DEFAULT_POOL_ID);
}
/**
* @return mask of supported dentry feature flags
*/
unsigned DiskMetaData::getSupportedDentryFeatureFlags()
{
return DENTRY_FEATURE_INODE_INLINE | DENTRY_FEATURE_IS_FILEINODE | DENTRY_FEATURE_MIRRORED
| DENTRY_FEATURE_BUDDYMIRRORED | DENTRY_FEATURE_32BITIDS;
}
/**
* @return mask of supported file inode feature flags, inlined into V4 Dentries
*/
unsigned DiskMetaData::getSupportedDentryV4FileInodeFeatureFlags()
{
return FILEINODE_FEATURE_MIRRORED | FILEINODE_FEATURE_BUDDYMIRRORED |
FILEINODE_FEATURE_HAS_VERSIONS;
}
/**
* @return mask of supported file inode feature flags, inlined into V5 Dentries
*/
unsigned DiskMetaData::getSupportedDentryV5FileInodeFeatureFlags()
{
return FILEINODE_FEATURE_MIRRORED | FILEINODE_FEATURE_BUDDYMIRRORED |
FILEINODE_FEATURE_HAS_ORIG_PARENTID | FILEINODE_FEATURE_HAS_ORIG_UID |
FILEINODE_FEATURE_HAS_VERSIONS | FILEINODE_FEATURE_HAS_RST | FILEINODE_FEATURE_HAS_STATE_FLAGS;
}
/**
* @return mask of supported dir inode feature flags
*/
unsigned DiskMetaData::getSupportedDirInodeFeatureFlags()
{
return DIRINODE_FEATURE_EARLY_SUBDIRS | DIRINODE_FEATURE_MIRRORED | DIRINODE_FEATURE_STATFLAGS |
DIRINODE_FEATURE_BUDDYMIRRORED | DIRINODE_FEATURE_HAS_RST;
}
/**
* Compare usedFeatureFlags with supportedFeatureFlags to find out whether an unsupported
* feature flag is used.
*
* @return false if an unsupported feature flag was set in usedFeatureFlags
*/
bool DiskMetaData::checkFeatureFlagsCompat(unsigned usedFeatureFlags,
unsigned supportedFeatureFlags)
{
unsigned unsupportedFlags = ~supportedFeatureFlags;
return !(usedFeatureFlags & unsupportedFlags);
}