diff --git a/headers/private/fs_shell/fssh_kernel_priv.h b/headers/private/fs_shell/fssh_kernel_priv.h index 0892102864..db7df042af 100644 --- a/headers/private/fs_shell/fssh_kernel_priv.h +++ b/headers/private/fs_shell/fssh_kernel_priv.h @@ -45,7 +45,7 @@ #define ROUNDUP(a, b) (((a) + ((b)-1)) & ~((b)-1)) -#define ROUNDOWN(a, b) (((a) / (b)) * (b)) +#define ROUNDDOWN(a, b) (((a) / (b)) * (b)) #define CHECK_BIT(a, b) ((a) & (1 << (b))) diff --git a/src/add-ons/kernel/file_systems/ext2/Jamfile b/src/add-ons/kernel/file_systems/ext2/Jamfile index 7d9c8f8ed6..ab8dc4c8b6 100644 --- a/src/add-ons/kernel/file_systems/ext2/Jamfile +++ b/src/add-ons/kernel/file_systems/ext2/Jamfile @@ -11,7 +11,7 @@ KernelAddon ext2 : Attribute.cpp BitmapBlock.cpp BlockAllocator.cpp - crc32.c + crc32.cpp CRCTable.cpp DataStream.cpp DeviceOpener.cpp @@ -34,7 +34,7 @@ KernelAddon ext2 : SEARCH on [ FGristFiles DeviceOpener.cpp ] = [ FDirName $(HAIKU_TOP) src add-ons kernel file_systems shared ] ; -SEARCH on [ FGristFiles crc32.c ] +SEARCH on [ FGristFiles crc32.cpp ] = [ FDirName $(HAIKU_TOP) src add-ons kernel file_systems shared ] ; SEARCH on [ FGristFiles CRCTable.cpp ] diff --git a/src/add-ons/kernel/file_systems/shared/CRCTable.h b/src/add-ons/kernel/file_systems/shared/CRCTable.h index 04d802d2aa..bdaada97f0 100644 --- a/src/add-ons/kernel/file_systems/shared/CRCTable.h +++ b/src/add-ons/kernel/file_systems/shared/CRCTable.h @@ -12,8 +12,8 @@ uint16 calculate_crc(uint16 crc, uint8 *data, uint16 length); -__BEGIN_DECLS + uint32 calculate_crc32c(uint32 crc32c, const unsigned char *buffer, unsigned int length); -__END_DECLS + diff --git a/src/add-ons/kernel/file_systems/shared/crc32.c b/src/add-ons/kernel/file_systems/shared/crc32.cpp similarity index 96% rename from src/add-ons/kernel/file_systems/shared/crc32.c rename to src/add-ons/kernel/file_systems/shared/crc32.cpp index 944c154892..f4d6c0c42d 100644 --- a/src/add-ons/kernel/file_systems/shared/crc32.c +++ b/src/add-ons/kernel/file_systems/shared/crc32.cpp @@ -42,18 +42,32 @@ * CRC32 code derived from work by Gary S. Brown. */ +#ifndef FS_SHELL + #include #include #ifdef __HAIKU__ -#define rounddown(x, y) (((x)/(y))*(y)) #include +#include #include #include -uint32_t calculate_crc32c(uint32_t crc32c, const unsigned char *buffer, +uint32 calculate_crc32c(uint32 crc32c, const unsigned char *buffer, unsigned int length); #endif -const uint32_t crc32_tab[] = { +#else + +#include "fssh_api_wrapper.h" +#include "fssh_auto_deleter.h" +#include "fssh_kernel_priv.h" +#include "Debug.h" +uint32 calculate_crc32c(uint32 crc32c, const unsigned char *buffer, + unsigned int length); + +#endif + + +const uint32 crc32_tab[] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, @@ -105,11 +119,11 @@ const uint32_t crc32_tab[] = { * of this function that's actually used in the kernel can be found * in sys/libkern.h, where it can be inlined. * - * uint32_t + * uint32 * crc32(const void *buf, size_t size) * { * const uint8_t *p = buf; - * uint32_t crc; + * uint32 crc; * * crc = ~0U; * while (size--) @@ -139,7 +153,7 @@ const uint32_t crc32_tab[] = { /* */ /*****************************************************************/ -static const uint32_t crc32Table[256] = { +static const uint32 crc32Table[256] = { 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L, 0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL, 0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL, @@ -206,10 +220,10 @@ static const uint32_t crc32Table[256] = { 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L }; -static uint32_t -singletable_crc32c(uint32_t crc, const void *buf, size_t size) +static uint32 +singletable_crc32c(uint32 crc, const void *buf, size_t size) { - const uint8_t *p = buf; + const uint8_t *p = (const uint8_t *)buf; while (size--) @@ -245,7 +259,7 @@ singletable_crc32c(uint32_t crc, const void *buf, size_t size) * File Name = ............................ 8x256_tables.c */ -static const uint32_t sctp_crc_tableil8_o32[256] = +static const uint32 sctp_crc_tableil8_o32[256] = { 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB, 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24, @@ -301,7 +315,7 @@ static const uint32_t sctp_crc_tableil8_o32[256] = * File Name = ............................ 8x256_tables.c */ -static const uint32_t sctp_crc_tableil8_o40[256] = +static const uint32 sctp_crc_tableil8_o40[256] = { 0x00000000, 0x13A29877, 0x274530EE, 0x34E7A899, 0x4E8A61DC, 0x5D28F9AB, 0x69CF5132, 0x7A6DC945, 0x9D14C3B8, 0x8EB65BCF, 0xBA51F356, 0xA9F36B21, 0xD39EA264, 0xC03C3A13, 0xF4DB928A, 0xE7790AFD, @@ -357,7 +371,7 @@ static const uint32_t sctp_crc_tableil8_o40[256] = * File Name = ............................ 8x256_tables.c */ -static const uint32_t sctp_crc_tableil8_o48[256] = +static const uint32 sctp_crc_tableil8_o48[256] = { 0x00000000, 0xA541927E, 0x4F6F520D, 0xEA2EC073, 0x9EDEA41A, 0x3B9F3664, 0xD1B1F617, 0x74F06469, 0x38513EC5, 0x9D10ACBB, 0x773E6CC8, 0xD27FFEB6, 0xA68F9ADF, 0x03CE08A1, 0xE9E0C8D2, 0x4CA15AAC, @@ -413,7 +427,7 @@ static const uint32_t sctp_crc_tableil8_o48[256] = * File Name = ............................ 8x256_tables.c */ -static const uint32_t sctp_crc_tableil8_o56[256] = +static const uint32 sctp_crc_tableil8_o56[256] = { 0x00000000, 0xDD45AAB8, 0xBF672381, 0x62228939, 0x7B2231F3, 0xA6679B4B, 0xC4451272, 0x1900B8CA, 0xF64463E6, 0x2B01C95E, 0x49234067, 0x9466EADF, 0x8D665215, 0x5023F8AD, 0x32017194, 0xEF44DB2C, @@ -469,7 +483,7 @@ static const uint32_t sctp_crc_tableil8_o56[256] = * File Name = ............................ 8x256_tables.c */ -static const uint32_t sctp_crc_tableil8_o64[256] = +static const uint32 sctp_crc_tableil8_o64[256] = { 0x00000000, 0x38116FAC, 0x7022DF58, 0x4833B0F4, 0xE045BEB0, 0xD854D11C, 0x906761E8, 0xA8760E44, 0xC5670B91, 0xFD76643D, 0xB545D4C9, 0x8D54BB65, 0x2522B521, 0x1D33DA8D, 0x55006A79, 0x6D1105D5, @@ -525,7 +539,7 @@ static const uint32_t sctp_crc_tableil8_o64[256] = * File Name = ............................ 8x256_tables.c */ -static const uint32_t sctp_crc_tableil8_o72[256] = +static const uint32 sctp_crc_tableil8_o72[256] = { 0x00000000, 0xEF306B19, 0xDB8CA0C3, 0x34BCCBDA, 0xB2F53777, 0x5DC55C6E, 0x697997B4, 0x8649FCAD, 0x6006181F, 0x8F367306, 0xBB8AB8DC, 0x54BAD3C5, 0xD2F32F68, 0x3DC34471, 0x097F8FAB, 0xE64FE4B2, @@ -581,7 +595,7 @@ static const uint32_t sctp_crc_tableil8_o72[256] = * File Name = ............................ 8x256_tables.c */ -static const uint32_t sctp_crc_tableil8_o80[256] = +static const uint32 sctp_crc_tableil8_o80[256] = { 0x00000000, 0x68032CC8, 0xD0065990, 0xB8057558, 0xA5E0C5D1, 0xCDE3E919, 0x75E69C41, 0x1DE5B089, 0x4E2DFD53, 0x262ED19B, 0x9E2BA4C3, 0xF628880B, 0xEBCD3882, 0x83CE144A, 0x3BCB6112, 0x53C84DDA, @@ -637,7 +651,7 @@ static const uint32_t sctp_crc_tableil8_o80[256] = * File Name = ............................ 8x256_tables.c */ -static const uint32_t sctp_crc_tableil8_o88[256] = +static const uint32 sctp_crc_tableil8_o88[256] = { 0x00000000, 0x493C7D27, 0x9278FA4E, 0xDB448769, 0x211D826D, 0x6821FF4A, 0xB3657823, 0xFA590504, 0x423B04DA, 0x0B0779FD, 0xD043FE94, 0x997F83B3, 0x632686B7, 0x2A1AFB90, 0xF15E7CF9, 0xB86201DE, @@ -678,20 +692,19 @@ static const uint32_t sctp_crc_tableil8_o88[256] = */ -static uint32_t -crc32c_sb8_64_bit(uint32_t crc, +static uint32 +crc32c_sb8_64_bit(uint32 crc, const unsigned char *p_buf, - uint32_t length, - uint32_t init_bytes) + uint32 length, + uint32 init_bytes) { - uint32_t li; - uint32_t term1, term2; - uint32_t running_length; - uint32_t end_bytes; + uint32 li; + uint32 term1, term2; + uint32 running_length; + uint32 end_bytes; - running_length = rounddown(length - init_bytes, 8); + running_length = ROUNDDOWN(length - init_bytes, 8); end_bytes = length - init_bytes - running_length; - for (li = 0; li < init_bytes; li++) crc = sctp_crc_tableil8_o32[(crc ^ *p_buf++) & 0x000000FF] ^ (crc >> 8); @@ -702,7 +715,7 @@ crc32c_sb8_64_bit(uint32_t crc, crc ^= (*p_buf++) << 16; crc ^= (*p_buf++) << 24; #else - crc ^= *(const uint32_t *) p_buf; + crc ^= *(const uint32 *) p_buf; p_buf += 4; #endif term1 = sctp_crc_tableil8_o88[crc & 0x000000FF] ^ @@ -718,10 +731,9 @@ crc32c_sb8_64_bit(uint32_t crc, crc ^= sctp_crc_tableil8_o40[*p_buf++]; crc ^= sctp_crc_tableil8_o32[*p_buf++]; #else - term1 = sctp_crc_tableil8_o56[(*(const uint32_t *) p_buf) & 0x000000FF] ^ - sctp_crc_tableil8_o48[((*(const uint32_t *) p_buf) >> 8) & 0x000000FF]; - - term2 = (*(const uint32_t *) p_buf) >> 16; + term1 = sctp_crc_tableil8_o56[(*(const uint32 *) p_buf) & 0x000000FF] ^ + sctp_crc_tableil8_o48[((*(const uint32 *) p_buf) >> 8) & 0x000000FF]; + term2 = (*(const uint32 *) p_buf) >> 16; crc = crc ^ term1 ^ sctp_crc_tableil8_o40[term2 & 0x000000FF] ^ @@ -735,12 +747,12 @@ crc32c_sb8_64_bit(uint32_t crc, return crc; } -static uint32_t -multitable_crc32c(uint32_t crc32c, +static uint32 +multitable_crc32c(uint32 crc32c, const unsigned char *buffer, unsigned int length) { - uint32_t to_even_word; + uint32 to_even_word; if (length == 0) { return (crc32c); @@ -749,8 +761,8 @@ multitable_crc32c(uint32_t crc32c, return (crc32c_sb8_64_bit(crc32c, buffer, length, to_even_word)); } -uint32_t -calculate_crc32c(uint32_t crc32c, +uint32 +calculate_crc32c(uint32 crc32c, const unsigned char *buffer, unsigned int length) { diff --git a/src/add-ons/kernel/file_systems/xfs/Checksum.h b/src/add-ons/kernel/file_systems/xfs/Checksum.h new file mode 100644 index 0000000000..8aa1f1c6c9 --- /dev/null +++ b/src/add-ons/kernel/file_systems/xfs/Checksum.h @@ -0,0 +1,85 @@ +/* + * Copyright 2022, Raghav Sharma, raghavself28@gmail.com + * Distributed under the terms of the MIT License. + */ +#ifndef _XFS_CKSUM_H +#define _XFS_CKSUM_H + +#include "CRCTable.h" +#include "xfs_types.h" +#include "system_dependencies.h" + + +#define XFS_CRC_SEED (~(uint32)0) + + +/* + Calculate the intermediate checksum for a buffer that has the CRC field + inside it. The offset of the 32bit crc fields is passed as the + cksum_offset parameter. We do not modify the buffer during verification, + hence we have to split the CRC calculation across the cksum_offset. +*/ +static inline uint32 +xfs_start_cksum_safe(const char *buffer, size_t length, uint32 cksum_offset) +{ + uint32 zero = 0; + uint32 crc; + + // Calculate CRC up to the checksum. + crc = calculate_crc32c(XFS_CRC_SEED, (uint8*)buffer, cksum_offset); + + // Skip checksum field + crc = calculate_crc32c(crc, (uint8*)&zero, sizeof(uint32)); + + // Calculate the rest of the CRC. + return calculate_crc32c(crc, (uint8*)buffer + cksum_offset + sizeof(uint32), + length - (cksum_offset + sizeof(uint32))); +} + + +/* + Fast CRC method where the buffer is modified. Callers must have exclusive + access to the buffer while the calculation takes place. +*/ +static inline uint32 +xfs_start_cksum_update(char *buffer, size_t length, uint32 cksum_offset) +{ + // zero the CRC field + *(uint32 *)(buffer + cksum_offset) = 0; + + // single pass CRC calculation for the entire buffer + return calculate_crc32c(XFS_CRC_SEED, (uint8*)buffer, length); +} + + +/* + Helper to generate the checksum for a buffer. + + This modifies the buffer temporarily - callers must have exclusive + access to the buffer while the calculation takes place. +*/ +static inline void +xfs_update_cksum(char *buffer, size_t length, uint32 cksum_offset) +{ + uint32 crc = xfs_start_cksum_update(buffer, length, cksum_offset); + + *(uint32 *)(buffer + cksum_offset) = ~crc; +} + + +/* + Helper to verify the checksum for a buffer. +*/ +static inline int +xfs_verify_cksum(char *buffer, size_t length, uint32 cksum_offset) +{ + uint32 crc = xfs_start_cksum_safe(buffer, length, cksum_offset); + + TRACE("calculated crc: (%" B_PRIu32 ")\n", ~crc); + + TRACE("buffer = %s, cksum_offset: (%" B_PRIu32 ")\n", buffer, cksum_offset); + + return *(uint32 *)(buffer + cksum_offset) == (~crc); +} + +#endif \ No newline at end of file diff --git a/src/add-ons/kernel/file_systems/xfs/Inode.cpp b/src/add-ons/kernel/file_systems/xfs/Inode.cpp index 65895da7b8..a99d89ae1b 100644 --- a/src/add-ons/kernel/file_systems/xfs/Inode.cpp +++ b/src/add-ons/kernel/file_systems/xfs/Inode.cpp @@ -543,7 +543,7 @@ Inode::GetFromDisk() xfs_fsblock_t blockToRead = FSBLOCKS_TO_BASICBLOCKS(fVolume->BlockLog(), ((uint64)(agNo * numberOfBlocksInAg) + agBlock)); - xfs_daddr_t readPos = blockToRead * BASICBLOCKSIZE + offset * len; + xfs_daddr_t readPos = blockToRead * XFS_MIN_BLOCKSIZE + offset * len; if (read_pos(fVolume->Device(), readPos, fBuffer, len) != len) { ERROR("Inode::Inode(): IO Error"); @@ -570,7 +570,7 @@ Inode::FileSystemBlockToAddr(uint64 block) ((uint64)(agNo * numberOfBlocksInAg) + agBlockNo)); TRACE("blockToRead:(%" B_PRIu64 ")\n", actualBlockToRead); - uint64 readPos = actualBlockToRead * (BASICBLOCKSIZE); + uint64 readPos = actualBlockToRead * (XFS_MIN_BLOCKSIZE); return readPos; } diff --git a/src/add-ons/kernel/file_systems/xfs/Jamfile b/src/add-ons/kernel/file_systems/xfs/Jamfile index 54fc1dab5f..03e5e312b3 100644 --- a/src/add-ons/kernel/file_systems/xfs/Jamfile +++ b/src/add-ons/kernel/file_systems/xfs/Jamfile @@ -18,10 +18,10 @@ UsePrivateKernelHeaders ; DEFINES += DEBUG_APP="\\\"xfs\\\"" ; UseHeaders [ FDirName $(HAIKU_TOP) src libs uuid ] : true ; +UseHeaders [ FDirName $(HAIKU_TOP) src add-ons kernel file_systems shared ] : true ; local xfsSources = BPlusTree.cpp - DeviceOpener.cpp Directory.cpp Extent.cpp Inode.cpp @@ -33,8 +33,14 @@ local xfsSources = Volume.cpp xfs.cpp ; +local sharedSources = + crc32.cpp + CRCTable.cpp + DeviceOpener.cpp + ; KernelAddon xfs : $(xfsSources) + $(sharedSources) : libuuid_kernel.a ; @@ -42,8 +48,10 @@ KernelAddon xfs : SEARCH on [ FGristFiles $(xfsSources) ] = [ FDirName $(HAIKU_TOP) src add-ons kernel file_systems xfs ] ; -SEARCH on [ FGristFiles DeviceOpener.cpp ] +SEARCH on [ FGristFiles $(sharedSources) ] = [ FDirName $(HAIKU_TOP) src add-ons kernel file_systems shared ] ; SEARCH on [ FGristFiles kernel_cpp.cpp ] = [ FDirName $(HAIKU_TOP) src system kernel util ] ; + + diff --git a/src/add-ons/kernel/file_systems/xfs/Volume.cpp b/src/add-ons/kernel/file_systems/xfs/Volume.cpp index e63bd5164f..cd655530f1 100644 --- a/src/add-ons/kernel/file_systems/xfs/Volume.cpp +++ b/src/add-ons/kernel/file_systems/xfs/Volume.cpp @@ -7,6 +7,7 @@ #include "Volume.h" +#include "Checksum.h" #include "Inode.h" @@ -39,9 +40,28 @@ Volume::Identify(int fd, XfsSuperBlock *superBlock) TRACE("Volume::Identify() : Identifying Volume in progress"); - if (read_pos(fd, 0, superBlock, sizeof(XfsSuperBlock)) - != sizeof(XfsSuperBlock)) - return B_IO_ERROR; + //Create a buffer of 512 bytes for Crc verification + char buf[512]; + + if(read_pos(fd, 0, buf, 512) != 512) + return B_IO_ERROR; + + memcpy(superBlock, buf, sizeof(XfsSuperBlock)); + + int version = B_BENDIAN_TO_HOST_INT16(superBlock->Version()) & XFS_SB_VERSION_NUMBITS; + + // if its V5 filesystem check for superblock checksum + if (superBlock->MagicNum() == B_HOST_TO_BENDIAN_INT32(XFS_SB_MAGIC) + && (version == 5 || superBlock->Crc() != 0)) { + + TRACE("Superblock Crc: (%" B_PRIu32 ")\n", superBlock->Crc()); + + if(!xfs_verify_cksum(buf, 512, offsetof(XfsSuperBlock, sb_crc))) { + ERROR("Filesystem is corrupted"); + return B_BAD_VALUE; + } + + } superBlock->SwapEndian(); @@ -85,7 +105,11 @@ Volume::Mount(const char *deviceName, uint32 flags) return B_BAD_VALUE; } - TRACE("Volume::Mount(): Valid SuperBlock.\n"); + if ((fSuperBlock.Version() & XFS_SB_VERSION_NUMBITS) == 5) + TRACE("Volume::Mount(): Valid Version 5 SuperBlock.\n"); + else + TRACE("Volume::Mount(): Valid Version 4 SuperBlock.\n"); + // check if the device size is large enough to hold the file system off_t diskSize; diff --git a/src/add-ons/kernel/file_systems/xfs/Volume.h b/src/add-ons/kernel/file_systems/xfs/Volume.h index 408d68eb98..a213451ff0 100644 --- a/src/add-ons/kernel/file_systems/xfs/Volume.h +++ b/src/add-ons/kernel/file_systems/xfs/Volume.h @@ -11,7 +11,7 @@ #include "xfs.h" -#define FSBLOCK_SHIFT(fsBlockLog) (fsBlockLog - BASICBLOCKLOG); +#define FSBLOCK_SHIFT(fsBlockLog) (fsBlockLog - XFS_MIN_BLOCKSIZE_LOG); #define FSBLOCKS_TO_BASICBLOCKS(fsBlockLog, x) x << FSBLOCK_SHIFT(fsBlockLog); // Converting the FS Blocks to Basic Blocks diff --git a/src/add-ons/kernel/file_systems/xfs/xfs.cpp b/src/add-ons/kernel/file_systems/xfs/xfs.cpp index da59c446bd..2f43f882c8 100644 --- a/src/add-ons/kernel/file_systems/xfs/xfs.cpp +++ b/src/add-ons/kernel/file_systems/xfs/xfs.cpp @@ -13,23 +13,143 @@ XfsSuperBlock::Flags() const } +bool +XfsSuperBlock::IsValidVersion() const +{ + // Version 5 is supported + if ((Version() & XFS_SB_VERSION_NUMBITS) == 5) { + return true; + } + + // Version below 4 are not supported + if ((Version() & XFS_SB_VERSION_NUMBITS) < 4) { + ERROR("xfs version below 4 is not supported"); + return false; + } + + // V4 filesystems need v2 directories and unwritten extents + if (!(Version() & XFS_SB_VERSION_DIRV2BIT)) { + ERROR("xfs version 4 uses version 2 directories"); + return false; + } + if (!(Version() & XFS_SB_VERSION_EXTFLGBIT)) { + ERROR("xfs version 4 uses unwritten extents"); + return false; + } + + // V4 should not have any unknown v4 feature bits set + if ((Version() & ~XFS_SB_VERSION_OKBITS) || + ((Version() & XFS_SB_VERSION_MOREBITSBIT) && + (Features2() & ~XFS_SB_VERSION2_OKBITS))) { + ERROR("xfs version 4 unknown feature bit detected"); + return false; + } + + // Valid V4 filesytem + return true; +} + + +bool +XfsSuperBlock::IsValidFeatureMask() const +{ + // Version 5 superblock feature mask validation + if(sb_features_compat & XFS_SB_FEAT_COMPAT_UNKNOWN) { + ERROR("Superblock has unknown compatible features enabled"); + ERROR("Use more recent kernal"); + } + + // We cannot have write support if this is set + if(sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_UNKNOWN) { + ERROR("Superblock has unknown read-only compatible features enabled"); + ERROR("Filesystem is read-only"); + } + + // check for incompatible features + if(sb_features_incompat & XFS_SB_FEAT_INCOMPAT_UNKNOWN) { + ERROR("Superblock has unknown incompatible features enabled"); + return false; + } + + return true; +} + bool XfsSuperBlock::IsValid() const { - if (sb_magicnum != XFS_SB_MAGIC) + if (sb_magicnum != XFS_SB_MAGIC) { + ERROR("Invalid Superblock"); return false; + } - if (BASICBLOCKSIZE > sb_blocksize) { + // For version 4 + if (XFS_MIN_BLOCKSIZE > sb_blocksize) { ERROR("Basic block is less than 512 bytes!"); return false; } - // Checking version 4 file system - if ((Version() & 0x000f) > 4) { - ERROR("XFS version 5 or later is not yet supported"); + // Checking correct version of filesystem + if(!(IsValidVersion())) { return false; } + if ((Version() & XFS_SB_VERSION_NUMBITS) == 4) { + + if(sb_qflags & (XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD | + XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD)) { + ERROR("V4 Superblock has XFS_{P|G}QUOTA_{ENFD|CHKD} bits"); + return false; + } + + return true; + } + + if(!(IsValidFeatureMask())) { + return false; + } + + // For V5 + if (XFS_MIN_CRC_BLOCKSIZE > sb_blocksize) { + ERROR("Basic block is less than 1024 bytes!"); + return false; + } + + // V5 has a separate project quota inode + if (sb_qflags & (XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD)) { + ERROR("Version 5 of Super block has XFS_OQUOTA bits"); + return false; + } + + /*TODO: check if full Inode chunks are aligned to + inode chunk size when sparse inodes are + enabled to support the sparse chunk allocation + algorithm and prevent overlapping inode record. + */ + + // Sanity Checking + if( sb_agcount <= 0 || + sb_sectsize < XFS_MIN_SECTORSIZE || + sb_sectsize > XFS_MAX_SECTORSIZE || + sb_sectlog < XFS_MIN_SECTORSIZE_LOG || + sb_sectlog > XFS_MAX_SECTORSIZE_LOG || + sb_sectsize != (1 << sb_sectlog) || + sb_blocksize < XFS_MIN_BLOCKSIZE || + sb_blocksize > XFS_MAX_BLOCKSIZE || + sb_blocklog < XFS_MIN_BLOCKSIZE_LOG || + sb_blocklog > XFS_MAX_BLOCKSIZE_LOG || + sb_blocksize != (uint32)(1 << sb_blocklog) || + sb_dirblklog + sb_blocklog > XFS_MAX_BLOCKSIZE_LOG || + sb_inodesize < XFS_DINODE_MIN_SIZE || + sb_inodesize > XFS_DINODE_MAX_SIZE || + sb_inodelog < XFS_DINODE_MIN_LOG || + sb_inodelog > XFS_DINODE_MAX_LOG || + sb_inodesize != (1 << sb_inodelog) ) { + + ERROR("Sanity checking failed"); + return false; + } + + // Valid V5 Superblock return true; } @@ -167,38 +287,61 @@ XfsSuperBlock::AgBlocks() const } +uint32 +XfsSuperBlock::Crc() const +{ + return sb_crc; +} + +uint32 +XfsSuperBlock::MagicNum() const +{ + return sb_magicnum; +} + + void XfsSuperBlock::SwapEndian() { - sb_magicnum = B_BENDIAN_TO_HOST_INT32(sb_magicnum); - sb_blocksize = B_BENDIAN_TO_HOST_INT32(sb_blocksize); - sb_dblocks = B_BENDIAN_TO_HOST_INT64(sb_dblocks); - sb_rblocks = B_BENDIAN_TO_HOST_INT64(sb_rblocks); - sb_rextents = B_BENDIAN_TO_HOST_INT64(sb_rextents); - sb_logstart = B_BENDIAN_TO_HOST_INT64(sb_logstart); - sb_rootino = B_BENDIAN_TO_HOST_INT64(sb_rootino); - sb_rbmino = B_BENDIAN_TO_HOST_INT64(sb_rbmino); - sb_rsumino = B_BENDIAN_TO_HOST_INT64(sb_rsumino); - sb_rextsize = B_BENDIAN_TO_HOST_INT32(sb_rextsize); - sb_agblocks = B_BENDIAN_TO_HOST_INT32(sb_agblocks); - sb_agcount = B_BENDIAN_TO_HOST_INT32(sb_agcount); - sb_rbmblocks = B_BENDIAN_TO_HOST_INT32(sb_rbmblocks); - sb_logblocks = B_BENDIAN_TO_HOST_INT32(sb_logblocks); - sb_versionnum = B_BENDIAN_TO_HOST_INT16(sb_versionnum); - sb_sectsize = B_BENDIAN_TO_HOST_INT16(sb_sectsize); - sb_inodesize = B_BENDIAN_TO_HOST_INT16(sb_inodesize); - sb_inopblock = B_BENDIAN_TO_HOST_INT16(sb_inopblock); - sb_icount = B_BENDIAN_TO_HOST_INT64(sb_icount); - sb_ifree = B_BENDIAN_TO_HOST_INT64(sb_ifree); - sb_fdblocks = B_BENDIAN_TO_HOST_INT64(sb_fdblocks); - sb_frextents = B_BENDIAN_TO_HOST_INT64(sb_frextents); - sb_uquotino = B_BENDIAN_TO_HOST_INT64(sb_uquotino); - sb_gquotino = B_BENDIAN_TO_HOST_INT64(sb_gquotino); - sb_qflags = B_BENDIAN_TO_HOST_INT16(sb_qflags); - sb_inoalignmt = B_BENDIAN_TO_HOST_INT32(sb_inoalignmt); - sb_unit = B_BENDIAN_TO_HOST_INT32(sb_unit); - sb_width = B_BENDIAN_TO_HOST_INT32(sb_width); - sb_logsectsize = B_BENDIAN_TO_HOST_INT16(sb_logsectsize); - sb_logsunit = B_BENDIAN_TO_HOST_INT32(sb_logsunit); - sb_features2 = B_BENDIAN_TO_HOST_INT32(sb_features2); + sb_magicnum = B_BENDIAN_TO_HOST_INT32(sb_magicnum); + sb_blocksize = B_BENDIAN_TO_HOST_INT32(sb_blocksize); + sb_dblocks = B_BENDIAN_TO_HOST_INT64(sb_dblocks); + sb_rblocks = B_BENDIAN_TO_HOST_INT64(sb_rblocks); + sb_rextents = B_BENDIAN_TO_HOST_INT64(sb_rextents); + sb_logstart = B_BENDIAN_TO_HOST_INT64(sb_logstart); + sb_rootino = B_BENDIAN_TO_HOST_INT64(sb_rootino); + sb_rbmino = B_BENDIAN_TO_HOST_INT64(sb_rbmino); + sb_rsumino = B_BENDIAN_TO_HOST_INT64(sb_rsumino); + sb_rextsize = B_BENDIAN_TO_HOST_INT32(sb_rextsize); + sb_agblocks = B_BENDIAN_TO_HOST_INT32(sb_agblocks); + sb_agcount = B_BENDIAN_TO_HOST_INT32(sb_agcount); + sb_rbmblocks = B_BENDIAN_TO_HOST_INT32(sb_rbmblocks); + sb_logblocks = B_BENDIAN_TO_HOST_INT32(sb_logblocks); + sb_versionnum = B_BENDIAN_TO_HOST_INT16(sb_versionnum); + sb_sectsize = B_BENDIAN_TO_HOST_INT16(sb_sectsize); + sb_inodesize = B_BENDIAN_TO_HOST_INT16(sb_inodesize); + sb_inopblock = B_BENDIAN_TO_HOST_INT16(sb_inopblock); + sb_icount = B_BENDIAN_TO_HOST_INT64(sb_icount); + sb_ifree = B_BENDIAN_TO_HOST_INT64(sb_ifree); + sb_fdblocks = B_BENDIAN_TO_HOST_INT64(sb_fdblocks); + sb_frextents = B_BENDIAN_TO_HOST_INT64(sb_frextents); + sb_uquotino = B_BENDIAN_TO_HOST_INT64(sb_uquotino); + sb_gquotino = B_BENDIAN_TO_HOST_INT64(sb_gquotino); + sb_qflags = B_BENDIAN_TO_HOST_INT16(sb_qflags); + sb_inoalignmt = B_BENDIAN_TO_HOST_INT32(sb_inoalignmt); + sb_unit = B_BENDIAN_TO_HOST_INT32(sb_unit); + sb_width = B_BENDIAN_TO_HOST_INT32(sb_width); + sb_logsectsize = B_BENDIAN_TO_HOST_INT16(sb_logsectsize); + sb_logsunit = B_BENDIAN_TO_HOST_INT32(sb_logsunit); + sb_features2 = B_BENDIAN_TO_HOST_INT32(sb_features2); + sb_bad_features2 = B_BENDIAN_TO_HOST_INT32(sb_bad_features2); + sb_features_compat = B_BENDIAN_TO_HOST_INT32(sb_features_compat); + sb_features_ro_compat = B_BENDIAN_TO_HOST_INT32(sb_features_ro_compat); + sb_features_incompat = B_BENDIAN_TO_HOST_INT32(sb_features_incompat); + sb_features_log_incompat = B_BENDIAN_TO_HOST_INT32(sb_features_log_incompat); + // crc is only used on disk, not in memory; just init to 0 here + sb_crc = 0; + sb_spino_align = B_BENDIAN_TO_HOST_INT32(sb_spino_align); + sb_pquotino = B_BENDIAN_TO_HOST_INT64(sb_pquotino); + sb_lsn = B_BENDIAN_TO_HOST_INT64(sb_lsn); } diff --git a/src/add-ons/kernel/file_systems/xfs/xfs.h b/src/add-ons/kernel/file_systems/xfs/xfs.h index 3c6a904d89..e132fe65e4 100644 --- a/src/add-ons/kernel/file_systems/xfs/xfs.h +++ b/src/add-ons/kernel/file_systems/xfs/xfs.h @@ -24,13 +24,30 @@ extern fs_volume_ops gxfsVolumeOps; #define XFS_SB_MAGIC 0x58465342 - // Identifies XFS. "XFSB" +#define XFS_MIN_BLOCKSIZE_LOG 9 +#define XFS_MAX_BLOCKSIZE_LOG 16 +#define XFS_MIN_BLOCKSIZE (1 << XFS_MIN_BLOCKSIZE_LOG) +#define XFS_MAX_BLOCKSIZE (1 << XFS_MAX_BLOCKSIZE_LOG) +#define XFS_MIN_CRC_BLOCKSIZE (1 << (XFS_MIN_BLOCKSIZE_LOG + 1)) +#define XFS_MIN_SECTORSIZE_LOG 9 +#define XFS_MAX_SECTORSIZE_LOG 15 +#define XFS_MIN_SECTORSIZE (1 << XFS_MIN_SECTORSIZE_LOG) +#define XFS_MAX_SECTORSIZE (1 << XFS_MAX_SECTORSIZE_LOG) #define XFS_SB_MAXSIZE 512 -#define BASICBLOCKLOG 9 - // Log of block size should be 9 -#define BASICBLOCKSIZE (1 << BASICBLOCKLOG) - // The size of a basic block should be 512 + + #define XFS_OPEN_MODE_USER_MASK 0x7fffffff +#define XFS_SB_VERSION_NUMBITS 0x000f +#define XFS_SB_VERSION_ALLFBITS 0xfff0 +#define XFS_SB_VERSION_NUM(sb) ((sb)->sb_versionnum & XFS_SB_VERSION_NUMBITS) + +/* + Inode minimum and maximum sizes. +*/ +#define XFS_DINODE_MIN_LOG 8 +#define XFS_DINODE_MAX_LOG 11 +#define XFS_DINODE_MIN_SIZE (1 << XFS_DINODE_MIN_LOG) +#define XFS_DINODE_MAX_SIZE (1 << XFS_DINODE_MAX_LOG) /* B+Tree related macros */ @@ -50,11 +67,12 @@ struct file_cookie { }; -/* Version 4 superblock definition */ class XfsSuperBlock { public: bool IsValid() const; + bool IsValidVersion() const; + bool IsValidFeatureMask() const; const char* Name() const; uint32 BlockSize() const; uint8 BlockLog() const; @@ -77,6 +95,8 @@ public: uint8 Flags() const; uint16 Version() const; uint32 Features2() const; + uint32 Crc() const; + uint32 MagicNum() const; private: uint32 sb_magicnum; @@ -124,6 +144,22 @@ private: uint16 sb_logsectsize; uint32 sb_logsunit; uint32 sb_features2; + uint32 sb_bad_features2; + + // version 5 + + uint32 sb_features_compat; + uint32 sb_features_ro_compat; + uint32 sb_features_incompat; + uint32 sb_features_log_incompat; +public: + uint32 sb_crc; +private: + xfs_extlen_t sb_spino_align; + + xfs_ino_t sb_pquotino; + xfs_lsn_t sb_lsn; + uuid_t sb_meta_uuid; }; @@ -146,6 +182,9 @@ private: #define XFS_SB_VERSION_DIRV2BIT 0x2000 #define XFS_SB_VERSION_MOREBITSBIT 0x4000 +#define XFS_SB_VERSION_OKBITS \ + ((XFS_SB_VERSION_NUMBITS | XFS_SB_VERSION_ALLFBITS) & \ + ~XFS_SB_VERSION_SHAREDBIT) /* Superblock quota flags - sb_qflags @@ -182,4 +221,51 @@ Superblock quota flags - sb_qflags #define XFS_SB_VERSION2_CRCBIT 0x00000100 /* Metadata checksumming */ #define XFS_SB_VERSION2_FTYPE 0x00000200 +#define XFS_SB_VERSION2_OKBITS \ + (XFS_SB_VERSION2_LAZYSBCOUNTBIT | \ + XFS_SB_VERSION2_ATTR2BIT | \ + XFS_SB_VERSION2_PROJID32BIT | \ + XFS_SB_VERSION2_FTYPE) + +/* + Extended Version 5 Superblock Read-Only compatibility flags +*/ + +#define XFS_SB_FEAT_RO_COMPAT_FINOBT (1 << 0) /* free inode btree */ +#define XFS_SB_FEAT_RO_COMPAT_RMAPBT (1 << 1) /* reverse map btree */ +#define XFS_SB_FEAT_RO_COMPAT_REFLINK (1 << 2) /* reflinked files */ +#define XFS_SB_FEAT_RO_COMPAT_INOBTCNT (1 << 3) /* inobt block counts */ + +/* + Extended Version 5 Superblock Read-Write incompatibility flags +*/ + +#define XFS_SB_FEAT_INCOMPAT_FTYPE (1 << 0) /* filetype in dirent */ +#define XFS_SB_FEAT_INCOMPAT_SPINODES (1 << 1) /* sparse inode chunks */ +#define XFS_SB_FEAT_INCOMPAT_META_UUID (1 << 2) /* metadata UUID */ +#define XFS_SB_FEAT_INCOMPAT_BIGTIME (1 << 3) /* large timestamps */ + +/* + Extended v5 superblock feature masks. These are to be used for new v5 + superblock features only. +*/ + +#define XFS_SB_FEAT_COMPAT_ALL 0 +#define XFS_SB_FEAT_COMPAT_UNKNOWN ~XFS_SB_FEAT_COMPAT_ALL + +#define XFS_SB_FEAT_RO_COMPAT_ALL \ + (XFS_SB_FEAT_RO_COMPAT_FINOBT | \ + XFS_SB_FEAT_RO_COMPAT_RMAPBT | \ + XFS_SB_FEAT_RO_COMPAT_REFLINK| \ + XFS_SB_FEAT_RO_COMPAT_INOBTCNT) +#define XFS_SB_FEAT_RO_COMPAT_UNKNOWN ~XFS_SB_FEAT_RO_COMPAT_ALL + +#define XFS_SB_FEAT_INCOMPAT_ALL \ + (XFS_SB_FEAT_INCOMPAT_FTYPE| \ + XFS_SB_FEAT_INCOMPAT_SPINODES| \ + XFS_SB_FEAT_INCOMPAT_META_UUID| \ + XFS_SB_FEAT_INCOMPAT_BIGTIME) + +#define XFS_SB_FEAT_INCOMPAT_UNKNOWN ~XFS_SB_FEAT_INCOMPAT_ALL + #endif diff --git a/src/add-ons/kernel/file_systems/xfs/xfs_types.h b/src/add-ons/kernel/file_systems/xfs/xfs_types.h index 3892894264..5e8a8279d9 100644 --- a/src/add-ons/kernel/file_systems/xfs/xfs_types.h +++ b/src/add-ons/kernel/file_systems/xfs/xfs_types.h @@ -36,6 +36,7 @@ typedef uint64 xfs_rtblock_t; // extent number in the real-time sub-volume typedef uint64 xfs_fileoff_t; // block offset into a file typedef uint64 xfs_filblks_t; // block count for a file typedef int64 xfs_fsize_t; // byte size of a file +typedef int64 xfs_lsn_t; // log sequence number typedef xfs_fileoff_t TreeKey; typedef xfs_fsblock_t TreePointer; diff --git a/src/tests/add-ons/kernel/file_systems/xfs/xfs_shell/Jamfile b/src/tests/add-ons/kernel/file_systems/xfs/xfs_shell/Jamfile index c2eb14ac16..1dee2f14f3 100644 --- a/src/tests/add-ons/kernel/file_systems/xfs/xfs_shell/Jamfile +++ b/src/tests/add-ons/kernel/file_systems/xfs/xfs_shell/Jamfile @@ -1,6 +1,7 @@ SubDir HAIKU_TOP src tests add-ons kernel file_systems xfs xfs_shell ; SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src add-ons kernel file_systems xfs ] ; +SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src add-ons kernel file_systems shared ] ; # prevent inclusion of HaikuBuildCompatibility.h and _BSD_SOURCE headers DEFINES += HAIKU_BUILD_COMPATIBILITY_H __STRICT_ANSI__ ; @@ -37,10 +38,10 @@ UsePrivateHeaders fs_shell ; UsePrivateHeaders file_systems ; UseHeaders [ FDirName $(HAIKU_TOP) headers private ] : true ; UseHeaders [ FDirName $(HAIKU_TOP) src tools fs_shell ] ; +UseHeaders [ FDirName $(HAIKU_TOP) src add-ons kernel file_systems shared ] : true ; local xfsSource = BPlusTree.cpp - DeviceOpener.cpp Directory.cpp Extent.cpp Inode.cpp @@ -51,8 +52,13 @@ local xfsSource = Volume.cpp xfs.cpp ; +local sharedSources = + crc32.cpp + CRCTable.cpp + DeviceOpener.cpp +; -BuildPlatformMergeObject xfs_shell.o : $(xfsSource) ; +BuildPlatformMergeObject xfs_shell.o : $(xfsSource) $(sharedSources) ; BuildPlatformMain xfs_shell : @@ -74,5 +80,3 @@ BuildPlatformMain xfs_fuse SEARCH on [ FGristFiles QueryParserUtils.cpp ] += [ FDirName $(HAIKU_TOP) src add-ons kernel file_systems shared ] ; -SEARCH on [ FGristFiles DeviceOpener.cpp ] - += [ FDirName $(HAIKU_TOP) src add-ons kernel file_systems shared ] ;