/* * Copyright (c) 2020 Red Hat, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. * * $Id: //eng/vdo-releases/aluminum/src/c++/vdo/base/header.h#4 $ */ #ifndef HEADER_H #define HEADER_H #include "buffer.h" #include "numeric.h" #include "types.h" /** * An in-memory representation of a version number for versioned structures on * disk. * * A version number consists of two portions, a major version and a * minor version. Any format change which does not require an explicit * upgrade step from the previous version should increment the minor * version. Any format change which either requires an explicit * upgrade step, or is wholly incompatible (i.e. can not be upgraded * to), should increment the major version, and set the minor version * to 0. **/ typedef struct { uint32_t majorVersion; uint32_t minorVersion; } __attribute__((packed)) VersionNumber; /** * A packed, machine-independent, on-disk representation of a VersionNumber. * Both fields are stored in little-endian byte order. **/ typedef struct { byte majorVersion[4]; byte minorVersion[4]; } __attribute__((packed)) PackedVersionNumber; /** * The registry of component ids for use in headers **/ typedef enum { SUPER_BLOCK = 0, FIXED_LAYOUT = 1, RECOVERY_JOURNAL = 2, SLAB_DEPOT = 3, BLOCK_MAP = 4, GEOMETRY_BLOCK = 5, } ComponentID; /** * The header for versioned data stored on disk. **/ typedef struct { ComponentID id; // The component this is a header for VersionNumber version; // The version of the data format size_t size; // The size of the data following this header } __attribute__((packed)) Header; enum { ENCODED_HEADER_SIZE = sizeof(Header), }; /** * Check whether two version numbers are the same. * * @param versionA The first version * @param versionB The second version * * @return true if the two versions are the same **/ static inline bool areSameVersion(VersionNumber versionA, VersionNumber versionB) { return ((versionA.majorVersion == versionB.majorVersion) && (versionA.minorVersion == versionB.minorVersion)); } /** * Check whether an actual version is upgradable to an expected version. * An actual version is upgradable if its major number is expected but * its minor number differs, and the expected version's minor number * is greater than the actual version's minor number. * * @param expectedVersion The expected version * @param actualVersion The version being validated * * @return true if the actual version is upgradable **/ static inline bool isUpgradableVersion(VersionNumber expectedVersion, VersionNumber actualVersion) { return ((expectedVersion.majorVersion == actualVersion.majorVersion) && (expectedVersion.minorVersion > actualVersion.minorVersion)); } /** * Check whether a version matches an expected version. Logs an error * describing a mismatch. * * @param expectedVersion The expected version * @param actualVersion The version being validated * @param componentName The name of the component or the calling function * (for error logging) * * @return VDO_SUCCESS if the versions are the same * VDO_UNSUPPORTED_VERSION if the versions don't match **/ int validateVersion(VersionNumber expectedVersion, VersionNumber actualVersion, const char *componentName) __attribute__((warn_unused_result)); /** * Check whether a header matches expectations. Logs an error describing the * first mismatch found. * * @param expectedHeader The expected header * @param actualHeader The header being validated * @param exactSize If true, the size fields of the two headers must be * the same, otherwise actualSize >= expectedSize is OK * @param componentName The name of the component or the calling function * (for error logging) * * @return VDO_SUCCESS if the header meets expectations * VDO_INCORRECT_COMPONENT if the component ids don't match * VDO_UNSUPPORTED_VERSION if the versions or sizes don't match **/ int validateHeader(const Header *expectedHeader, const Header *actualHeader, bool exactSize, const char *componentName) __attribute__((warn_unused_result)); /** * Encode a header into a buffer. * * @param header The header to encode * @param buffer The buffer in which to encode the header * * @return UDS_SUCCESS or an error **/ int encodeHeader(const Header *header, Buffer *buffer) __attribute__((warn_unused_result)); /** * Encode a version number into a buffer. * * @param version The version to encode * @param buffer The buffer in which to encode the version * * @return UDS_SUCCESS or an error **/ int encodeVersionNumber(VersionNumber version, Buffer *buffer) __attribute__((warn_unused_result)); /** * Decode a header from a buffer. * * @param [in] buffer The buffer from which to decode the header * @param [out] header The header to decode * * @return UDS_SUCCESS or an error **/ int decodeHeader(Buffer *buffer, Header *header) __attribute__((warn_unused_result)); /** * Decode a version number from a buffer. * * @param buffer The buffer from which to decode the version * @param version The version structure to decode into * * @return UDS_SUCCESS or an error **/ int decodeVersionNumber(Buffer *buffer, VersionNumber *version) __attribute__((warn_unused_result)); /** * Convert a VersionNumber to its packed on-disk representation. * * @param version The version number to convert * * @return the platform-independent representation of the version **/ static inline PackedVersionNumber packVersionNumber(VersionNumber version) { PackedVersionNumber packed; storeUInt32LE(packed.majorVersion, version.majorVersion); storeUInt32LE(packed.minorVersion, version.minorVersion); return packed; } /** * Convert a PackedVersionNumber to its native in-memory representation. * * @param version The version number to convert * * @return the platform-independent representation of the version **/ static inline VersionNumber unpackVersionNumber(PackedVersionNumber version) { return (VersionNumber) { .majorVersion = getUInt32LE(version.majorVersion), .minorVersion = getUInt32LE(version.minorVersion), }; } #endif // HEADER_H