diff --git a/Bdd/Targets/Common/BddTargetFreeRtosPipeline.c b/Bdd/Targets/Common/BddTargetFreeRtosPipeline.c index 91999f6b..a45485ec 100644 --- a/Bdd/Targets/Common/BddTargetFreeRtosPipeline.c +++ b/Bdd/Targets/Common/BddTargetFreeRtosPipeline.c @@ -559,13 +559,12 @@ static bool RebuildWithFileStore(void) DestroyCurrentStore(); storeFile = g_config->CreateStoreFile(); - storeBlockDevice = SolidSyslogFileBlockDevice_Create(storeFile, STORE_PATH_PREFIX); + storeBlockDevice = SolidSyslogFileBlockDevice_Create(storeFile, STORE_PATH_PREFIX, pendingMaxBlockSize); struct SolidSyslogSecurityPolicy* policy = CreateSecurityPolicy(); currentPolicy = policy; struct SolidSyslogBlockStoreConfig storeConfig = { .BlockDevice = storeBlockDevice, - .MaxBlockSize = pendingMaxBlockSize, .MaxBlocks = pendingMaxBlocks, .DiscardPolicy = MapDiscardPolicy(pendingDiscardPolicy), .SecurityPolicy = policy, diff --git a/Bdd/Targets/Linux/main.c b/Bdd/Targets/Linux/main.c index c6a11de6..5491c89f 100644 --- a/Bdd/Targets/Linux/main.c +++ b/Bdd/Targets/Linux/main.c @@ -221,14 +221,13 @@ static struct SolidSyslogStore* CreateStore(const struct BddTargetOptions* optio { storeFile = SolidSyslogPosixFile_Create(); - storeBlockDevice = SolidSyslogFileBlockDevice_Create(storeFile, STORE_PATH_PREFIX); + storeBlockDevice = SolidSyslogFileBlockDevice_Create(storeFile, STORE_PATH_PREFIX, options->MaxBlockSize); static size_t capacityThreshold; capacityThreshold = options->CapacityThreshold; securityPolicy = CreateSecurityPolicy(options); static struct SolidSyslogBlockStoreConfig storeConfig = {0}; storeConfig.BlockDevice = storeBlockDevice; - storeConfig.MaxBlockSize = options->MaxBlockSize; storeConfig.MaxBlocks = options->MaxBlocks; storeConfig.DiscardPolicy = MapDiscardPolicy(options->DiscardPolicy); storeConfig.SecurityPolicy = securityPolicy; diff --git a/Bdd/Targets/Windows/BddTargetWindows.c b/Bdd/Targets/Windows/BddTargetWindows.c index e0e8349a..43ddd5f2 100644 --- a/Bdd/Targets/Windows/BddTargetWindows.c +++ b/Bdd/Targets/Windows/BddTargetWindows.c @@ -284,14 +284,13 @@ static struct SolidSyslogStore* CreateStore(const struct BddTargetWindowsOptions { storeFile = SolidSyslogWindowsFile_Create(); - storeBlockDevice = SolidSyslogFileBlockDevice_Create(storeFile, STORE_PATH_PREFIX); + storeBlockDevice = SolidSyslogFileBlockDevice_Create(storeFile, STORE_PATH_PREFIX, options->MaxBlockSize); static size_t capacityThreshold; capacityThreshold = options->CapacityThreshold; securityPolicy = CreateSecurityPolicy(options); static struct SolidSyslogBlockStoreConfig storeConfig = {0}; storeConfig.BlockDevice = storeBlockDevice; - storeConfig.MaxBlockSize = options->MaxBlockSize; storeConfig.MaxBlocks = options->MaxBlocks; storeConfig.DiscardPolicy = MapDiscardPolicy(options->DiscardPolicy); storeConfig.SecurityPolicy = securityPolicy; diff --git a/CLAUDE.md b/CLAUDE.md index e7f32a77..3a1cac0b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -404,10 +404,10 @@ live under `Core/Interface/`; platform-specific helpers (the `SolidSyslogPosix*` | `SolidSyslogFileDefinition.h` | File implementors (extension point) | `SolidSyslogFile` vtable struct | | `SolidSyslogFile.h` | Any code using the file abstraction | `SolidSyslogFile_Open`, `_Close`, `_IsOpen`, `_Read`, `_Write`, `_SeekTo`, `_Size`, `_Truncate` | | `SolidSyslogNullFile.h` | Any code installing a no-op file slot (Open/IsOpen/Read/Exists return `false`, Write/Delete return `true` so callers' success paths are not tripped, SeekTo/Truncate/Close are no-ops, Size returns `0`) | `SolidSyslogNullFile_Get` | -| `SolidSyslogBlockDevice.h` | Library internals consuming a block device (BlockSequence inside BlockStore) and integrator code addressing blocks directly | `SolidSyslogBlockDevice_Acquire`, `_Dispose`, `_Exists`, `_Read`, `_Append`, `_WriteAt`, `_Size` (block-indexed I/O; Acquire makes a block ready for fresh writes, Dispose releases it) | +| `SolidSyslogBlockDevice.h` | Library internals consuming a block device (BlockSequence inside BlockStore) and integrator code addressing blocks directly | `SolidSyslogBlockDevice_Acquire`, `_Dispose`, `_Exists`, `_Read`, `_Append`, `_WriteAt`, `_Size`, `_GetBlockSize` (block-indexed I/O; Acquire makes a block ready for fresh writes, Dispose releases it; `_Size(blockIndex)` is a block's current occupancy, `_GetBlockSize()` is the device-wide per-block capacity — the device is the single source of truth a BlockStore reads at construction) | | `SolidSyslogNullBlockDevice.h` | Any code installing a no-op block device slot (every method returns `false` / `0` — disk doesn't exist) | `SolidSyslogNullBlockDevice_Get` | -| `SolidSyslogBlockDeviceDefinition.h` | BlockDevice implementors (extension point) | `SolidSyslogBlockDevice` vtable struct (`Acquire`, `Dispose`, `Exists`, `Read`, `Append`, `WriteAt`, `Size`) | -| `SolidSyslogFileBlockDevice.h` | System setup code wiring a file-backed block device | `SolidSyslogFileBlockDevice_Create(file, pathPrefix)` (sequence-numbered filenames `.log`, one cached file handle), `_Destroy(base)`. Instance struct lives in a library-internal static pool (E11); `_Destroy` takes the handle returned by `_Create`. Pool exhaustion resolves to the shared `SolidSyslogNullBlockDevice`. | +| `SolidSyslogBlockDeviceDefinition.h` | BlockDevice implementors (extension point) | `SolidSyslogBlockDevice` vtable struct (`Acquire`, `Dispose`, `Exists`, `Read`, `Append`, `WriteAt`, `Size`, `GetBlockSize`) | +| `SolidSyslogFileBlockDevice.h` | System setup code wiring a file-backed block device | `SolidSyslogFileBlockDevice_Create(file, pathPrefix, blockSize)` (sequence-numbered filenames `.log`, one cached file handle; `blockSize` is the per-block capacity reported via `GetBlockSize`, `0` selects the `SOLIDSYSLOG_FILE_DEFAULT_BLOCK_SIZE` tunable), `_Destroy(base)`. Instance struct lives in a library-internal static pool (E11); `_Destroy` takes the handle returned by `_Create`. Pool exhaustion resolves to the shared `SolidSyslogNullBlockDevice`. | | `SolidSyslogFileBlockDeviceErrors.h` | Any code installing an error handler that wants to react to FileBlockDevice-specific events (pointer-identity match on `FileBlockDeviceErrorSource`, switch on `enum SolidSyslogFileBlockDeviceErrors`) | `enum SolidSyslogFileBlockDeviceErrors` (`FILEBLOCKDEVICE_ERROR_*` codes + `FILEBLOCKDEVICE_ERROR_MAX` bookend), `extern const struct SolidSyslogErrorSource FileBlockDeviceErrorSource`. Integrators ignore if not handling errors per source. | | `SolidSyslogBlockStore.h` | System setup code using a BlockDevice-backed store | `SolidSyslogBlockStoreConfig` (with `blockDevice`, `storeFullContext`, `getCapacityThreshold`, `onThresholdCrossed`, `thresholdContext`), `SolidSyslogBlockStore_Create(config)`, `_Destroy(store)`, `SolidSyslogDiscardPolicy` (`SolidSyslogDiscardPolicy_Oldest` / `_Newest` / `_Halt`), `SolidSyslogStoreFullCallback(void* context)`, `SolidSyslogStoreThresholdFunction(void* context)` (returns threshold in bytes; 0 disables; queried each Write), `SolidSyslogStoreThresholdCallback(void* context)` (edge-triggered; PassthroughBuffer recursion gotcha — see header). Instance struct lives in a library-internal static pool (E11); each slot composes one inner RecordStore + BlockSequence drawn 1:1 from sibling pools sized off the same `SOLIDSYSLOG_BLOCK_STORE_POOL_SIZE` tunable. Pool exhaustion (or either inner Create failing) resolves to the shared `SolidSyslogNullStore`. | | `SolidSyslogBlockStoreErrors.h` | Any code installing an error handler that wants to react to BlockStore-specific events (pointer-identity match on `BlockStoreErrorSource`, switch on `enum SolidSyslogBlockStoreErrors`) | `enum SolidSyslogBlockStoreErrors` (`BLOCKSTORE_ERROR_*` codes + `BLOCKSTORE_ERROR_MAX` bookend), `extern const struct SolidSyslogErrorSource BlockStoreErrorSource`. Integrators ignore if not handling errors per source. | diff --git a/Core/Interface/SolidSyslogBlockDevice.h b/Core/Interface/SolidSyslogBlockDevice.h index 1267974f..e8b598d8 100644 --- a/Core/Interface/SolidSyslogBlockDevice.h +++ b/Core/Interface/SolidSyslogBlockDevice.h @@ -39,6 +39,12 @@ EXTERN_C_BEGIN ); size_t SolidSyslogBlockDevice_Size(struct SolidSyslogBlockDevice * device, size_t blockIndex); + /* The device-wide block capacity in bytes — how large each block can grow. Distinct from + * Size(blockIndex), which reports the current occupancy of one block. The device is the + * single source of truth for this value; a BlockStore reads it at construction rather than + * taking a separate configured size. */ + size_t SolidSyslogBlockDevice_GetBlockSize(struct SolidSyslogBlockDevice * device); + EXTERN_C_END #endif /* SOLIDSYSLOGBLOCKDEVICE_H */ diff --git a/Core/Interface/SolidSyslogBlockDeviceDefinition.h b/Core/Interface/SolidSyslogBlockDeviceDefinition.h index c88fb64e..2bf3ed36 100644 --- a/Core/Interface/SolidSyslogBlockDeviceDefinition.h +++ b/Core/Interface/SolidSyslogBlockDeviceDefinition.h @@ -23,6 +23,7 @@ EXTERN_C_BEGIN size_t count ); size_t (*Size)(struct SolidSyslogBlockDevice* base, size_t blockIndex); + size_t (*GetBlockSize)(struct SolidSyslogBlockDevice* base); }; EXTERN_C_END diff --git a/Core/Interface/SolidSyslogBlockStore.h b/Core/Interface/SolidSyslogBlockStore.h index 279a4774..1061a117 100644 --- a/Core/Interface/SolidSyslogBlockStore.h +++ b/Core/Interface/SolidSyslogBlockStore.h @@ -35,7 +35,6 @@ EXTERN_C_BEGIN /* Required. Caller-owned: must outlive the BlockStore. SolidSyslogBlockStore_Destroy * does NOT destroy the block device — that is the integrator's responsibility. */ struct SolidSyslogBlockDevice* BlockDevice; - size_t MaxBlockSize; size_t MaxBlocks; enum SolidSyslogDiscardPolicy DiscardPolicy; struct SolidSyslogSecurityPolicy* SecurityPolicy; diff --git a/Core/Interface/SolidSyslogBlockStoreErrors.h b/Core/Interface/SolidSyslogBlockStoreErrors.h index 025b1cb7..0753a928 100644 --- a/Core/Interface/SolidSyslogBlockStoreErrors.h +++ b/Core/Interface/SolidSyslogBlockStoreErrors.h @@ -11,6 +11,7 @@ EXTERN_C_BEGIN { BLOCKSTORE_ERROR_POOL_EXHAUSTED, BLOCKSTORE_ERROR_UNKNOWN_DESTROY, + BLOCKSTORE_ERROR_BLOCK_TOO_SMALL, BLOCKSTORE_ERROR_MAX }; diff --git a/Core/Interface/SolidSyslogFileBlockDevice.h b/Core/Interface/SolidSyslogFileBlockDevice.h index 626bf1aa..e0e4ea7d 100644 --- a/Core/Interface/SolidSyslogFileBlockDevice.h +++ b/Core/Interface/SolidSyslogFileBlockDevice.h @@ -1,6 +1,8 @@ #ifndef SOLIDSYSLOGFILEBLOCKDEVICE_H #define SOLIDSYSLOGFILEBLOCKDEVICE_H +#include + #include "ExternC.h" struct SolidSyslogBlockDevice; @@ -12,10 +14,15 @@ EXTERN_C_BEGIN * targeted blockIndex changes — same-block runs of Read and Append (and Append-then-WriteAt * during MarkSent) share the handle. The single-handle-per-path invariant the storage layer * depends on (E27 #345 / S27.01) is enforced by construction here: the driver physically - * holds one file. */ + * holds one file. + * + * blockSize is the per-block capacity the device reports via + * SolidSyslogBlockDevice_GetBlockSize. Pass SOLIDSYSLOG_FILE_DEFAULT_BLOCK_SIZE for the + * default. */ struct SolidSyslogBlockDevice* SolidSyslogFileBlockDevice_Create( struct SolidSyslogFile * file, - const char* pathPrefix + const char* pathPrefix, + size_t blockSize ); void SolidSyslogFileBlockDevice_Destroy(struct SolidSyslogBlockDevice * base); diff --git a/Core/Interface/SolidSyslogTunablesDefaults.h b/Core/Interface/SolidSyslogTunablesDefaults.h index a3398f25..c939e5c4 100644 --- a/Core/Interface/SolidSyslogTunablesDefaults.h +++ b/Core/Interface/SolidSyslogTunablesDefaults.h @@ -81,6 +81,29 @@ #error "SOLIDSYSLOG_MAX_INTEGRITY_SIZE must be >= 4" #endif +/* + * Default per-block capacity (bytes) for file-backed block devices + * (SolidSyslogFileBlockDevice and any FatFs / FreeRTOS-Plus-FAT-backed + * equivalent). Supplied to SolidSyslogFileBlockDevice_Create when the + * integrator has no specific size in mind; passing 0 to _Create selects + * this default. A larger block holds more records before rotating to a + * fresh file; a smaller block rotates (and fsyncs) more often. + * + * Floor: one worst-case record — the RFC 5424 max message plus the widest + * integrity tag plus the 5-byte record framing (2 magic + 2 length + + * 1 sent-flag). Below that a block could not hold a single record, so the + * default must clear it for every SecurityPolicy. Sub-floor values + * rejected at compile time. + */ +#ifndef SOLIDSYSLOG_FILE_DEFAULT_BLOCK_SIZE +#define SOLIDSYSLOG_FILE_DEFAULT_BLOCK_SIZE 8192U +#endif + +#if SOLIDSYSLOG_FILE_DEFAULT_BLOCK_SIZE < (SOLIDSYSLOG_MAX_MESSAGE_SIZE + SOLIDSYSLOG_MAX_INTEGRITY_SIZE + 5) +#error \ + "SOLIDSYSLOG_FILE_DEFAULT_BLOCK_SIZE must hold one worst-case record (MAX_MESSAGE_SIZE + MAX_INTEGRITY_SIZE + 5 framing bytes)" +#endif + /* * Number of SolidSyslog instances the library's internal static pool * can simultaneously hold. Each instance is a small bookkeeping struct diff --git a/Core/Source/SolidSyslogBlockDevice.c b/Core/Source/SolidSyslogBlockDevice.c index e0feee21..682b2eae 100644 --- a/Core/Source/SolidSyslogBlockDevice.c +++ b/Core/Source/SolidSyslogBlockDevice.c @@ -55,3 +55,8 @@ size_t SolidSyslogBlockDevice_Size(struct SolidSyslogBlockDevice* device, size_t { return device->Size(device, blockIndex); } + +size_t SolidSyslogBlockDevice_GetBlockSize(struct SolidSyslogBlockDevice* device) +{ + return device->GetBlockSize(device); +} diff --git a/Core/Source/SolidSyslogBlockStoreStatic.c b/Core/Source/SolidSyslogBlockStoreStatic.c index cba0b28b..176f711c 100644 --- a/Core/Source/SolidSyslogBlockStoreStatic.c +++ b/Core/Source/SolidSyslogBlockStoreStatic.c @@ -6,6 +6,7 @@ #include "BlockSequencePrivate.h" #include "RecordStorePrivate.h" +#include "SolidSyslogBlockDevice.h" #include "SolidSyslogBlockStoreErrors.h" #include "SolidSyslogBlockStorePrivate.h" #include "SolidSyslogError.h" @@ -26,6 +27,10 @@ static struct BlockSequenceConfig BlockStore_BuildBlockSequenceConfig( const struct SolidSyslogBlockStoreConfig* config, const struct RecordStore* recordStore ); +static bool BlockStore_DeviceCanHoldOneRecord( + const struct SolidSyslogBlockStoreConfig* config, + const struct RecordStore* recordStore +); static bool BlockStore_InUse[SOLIDSYSLOG_BLOCK_STORE_POOL_SIZE]; static struct SolidSyslogBlockStore BlockStore_Pool[SOLIDSYSLOG_BLOCK_STORE_POOL_SIZE]; @@ -43,6 +48,19 @@ struct SolidSyslogStore* SolidSyslogBlockStore_Create(const struct SolidSyslogBl if (recordStore != NULL) { + if (!BlockStore_DeviceCanHoldOneRecord(config, recordStore)) + { + /* The device's block is smaller than one worst-case record. The store + * still works — BuildBlockSequenceConfig grows the block to the minimum so + * a record always fits — but the device was configured below a usable size, + * so surface it as a WARNING (delivered, degraded) rather than failing. */ + BlockStore_Report( + SOLIDSYSLOG_SEVERITY_WARNING, + SOLIDSYSLOG_CAT_BAD_CONFIG, + BLOCKSTORE_ERROR_BLOCK_TOO_SMALL + ); + } + struct BlockSequenceConfig blockConfig = BlockStore_BuildBlockSequenceConfig(config, recordStore); struct BlockSequence* blockSequence = BlockSequence_Create(&blockConfig); @@ -88,8 +106,12 @@ static struct BlockSequenceConfig BlockStore_BuildBlockSequenceConfig( const struct RecordStore* recordStore ) { + /* The device is the single source of truth for block size, but a block smaller than + * one worst-case record is grown to that floor so a single record always fits (Create + * has already emitted a WARNING for that case). */ size_t minBlockSize = RecordStore_RecordSize(recordStore, SOLIDSYSLOG_MAX_MESSAGE_SIZE); - size_t maxBlockSize = (config->MaxBlockSize < minBlockSize) ? minBlockSize : config->MaxBlockSize; + size_t deviceBlockSize = SolidSyslogBlockDevice_GetBlockSize(config->BlockDevice); + size_t maxBlockSize = (deviceBlockSize < minBlockSize) ? minBlockSize : deviceBlockSize; struct BlockSequenceConfig blockConfig = { .BlockDevice = config->BlockDevice, @@ -105,6 +127,18 @@ static struct BlockSequenceConfig BlockStore_BuildBlockSequenceConfig( return blockConfig; } +/* True when the device's block can hold one worst-case record (max message + the active + * policy's trailer + record framing). When false the block is grown to that floor and a + * WARNING is emitted — the store works, but the device's configured size was degraded. */ +static bool BlockStore_DeviceCanHoldOneRecord( + const struct SolidSyslogBlockStoreConfig* config, + const struct RecordStore* recordStore +) +{ + size_t minBlockSize = RecordStore_RecordSize(recordStore, SOLIDSYSLOG_MAX_MESSAGE_SIZE); + return SolidSyslogBlockDevice_GetBlockSize(config->BlockDevice) >= minBlockSize; +} + void SolidSyslogBlockStore_Destroy(struct SolidSyslogStore* base) { size_t index = BlockStore_IndexFromHandle(base); diff --git a/Core/Source/SolidSyslogFileBlockDevice.c b/Core/Source/SolidSyslogFileBlockDevice.c index fb66c5cb..0f9498fb 100644 --- a/Core/Source/SolidSyslogFileBlockDevice.c +++ b/Core/Source/SolidSyslogFileBlockDevice.c @@ -64,6 +64,7 @@ static bool FileBlockDevice_WriteAt( ); // NOLINTEND(bugprone-easily-swappable-parameters) static size_t FileBlockDevice_Size(struct SolidSyslogBlockDevice* base, size_t blockIndex); +static size_t FileBlockDevice_GetBlockSize(struct SolidSyslogBlockDevice* base); static inline struct SolidSyslogFileBlockDevice* FileBlockDevice_SelfFromBase(struct SolidSyslogBlockDevice* base); static inline void FileBlockDevice_CloseIfOpen(struct OpenHandle* handle); @@ -71,7 +72,8 @@ static inline void FileBlockDevice_CloseIfOpen(struct OpenHandle* handle); void FileBlockDevice_Initialise( struct SolidSyslogBlockDevice* base, struct SolidSyslogFile* file, - const char* pathPrefix + const char* pathPrefix, + size_t blockSize ) { struct SolidSyslogFileBlockDevice* self = FileBlockDevice_SelfFromBase(base); @@ -82,8 +84,10 @@ void FileBlockDevice_Initialise( self->Base.Append = FileBlockDevice_Append; self->Base.WriteAt = FileBlockDevice_WriteAt; self->Base.Size = FileBlockDevice_Size; + self->Base.GetBlockSize = FileBlockDevice_GetBlockSize; self->Handle = (struct OpenHandle) {.File = file, .BlockIndex = 0, .IsOpen = false}; self->PathPrefix = pathPrefix; + self->BlockSize = blockSize; } void FileBlockDevice_Cleanup(struct SolidSyslogBlockDevice* base) @@ -361,3 +365,8 @@ static size_t FileBlockDevice_Size(struct SolidSyslogBlockDevice* base, size_t b return size; } + +static size_t FileBlockDevice_GetBlockSize(struct SolidSyslogBlockDevice* base) +{ + return FileBlockDevice_SelfFromBase(base)->BlockSize; +} diff --git a/Core/Source/SolidSyslogFileBlockDevicePrivate.h b/Core/Source/SolidSyslogFileBlockDevicePrivate.h index c59f7ea5..b426d97c 100644 --- a/Core/Source/SolidSyslogFileBlockDevicePrivate.h +++ b/Core/Source/SolidSyslogFileBlockDevicePrivate.h @@ -29,12 +29,14 @@ struct SolidSyslogFileBlockDevice struct SolidSyslogBlockDevice Base; struct OpenHandle Handle; const char* PathPrefix; + size_t BlockSize; }; void FileBlockDevice_Initialise( struct SolidSyslogBlockDevice* base, struct SolidSyslogFile* file, - const char* pathPrefix + const char* pathPrefix, + size_t blockSize ); void FileBlockDevice_Cleanup(struct SolidSyslogBlockDevice* base); diff --git a/Core/Source/SolidSyslogFileBlockDeviceStatic.c b/Core/Source/SolidSyslogFileBlockDeviceStatic.c index 3257496c..a3f03d2b 100644 --- a/Core/Source/SolidSyslogFileBlockDeviceStatic.c +++ b/Core/Source/SolidSyslogFileBlockDeviceStatic.c @@ -26,13 +26,18 @@ static struct SolidSyslogPoolAllocator FileBlockDevice_Allocator = { SOLIDSYSLOG_FILE_BLOCK_DEVICE_POOL_SIZE }; -struct SolidSyslogBlockDevice* SolidSyslogFileBlockDevice_Create(struct SolidSyslogFile* file, const char* pathPrefix) +struct SolidSyslogBlockDevice* SolidSyslogFileBlockDevice_Create( + struct SolidSyslogFile* file, + const char* pathPrefix, + size_t blockSize +) { struct SolidSyslogBlockDevice* result = SolidSyslogNullBlockDevice_Get(); + size_t resolvedBlockSize = (blockSize == 0U) ? (size_t) SOLIDSYSLOG_FILE_DEFAULT_BLOCK_SIZE : blockSize; size_t index = SolidSyslogPoolAllocator_AcquireFirstFree(&FileBlockDevice_Allocator); if (SolidSyslogPoolAllocator_IndexIsValid(&FileBlockDevice_Allocator, index)) { - FileBlockDevice_Initialise(&FileBlockDevice_Pool[index].Base, file, pathPrefix); + FileBlockDevice_Initialise(&FileBlockDevice_Pool[index].Base, file, pathPrefix, resolvedBlockSize); result = &FileBlockDevice_Pool[index].Base; } else diff --git a/Core/Source/SolidSyslogNullBlockDevice.c b/Core/Source/SolidSyslogNullBlockDevice.c index 26c70a57..64bdd6f9 100644 --- a/Core/Source/SolidSyslogNullBlockDevice.c +++ b/Core/Source/SolidSyslogNullBlockDevice.c @@ -31,6 +31,7 @@ static bool NullBlockDevice_Append( size_t count ); static size_t NullBlockDevice_Size(struct SolidSyslogBlockDevice* base, size_t blockIndex); +static size_t NullBlockDevice_GetBlockSize(struct SolidSyslogBlockDevice* base); struct SolidSyslogBlockDevice* SolidSyslogNullBlockDevice_Get(void) { @@ -42,6 +43,7 @@ struct SolidSyslogBlockDevice* SolidSyslogNullBlockDevice_Get(void) .Append = NullBlockDevice_Append, .WriteAt = NullBlockDevice_WriteAt, .Size = NullBlockDevice_Size, + .GetBlockSize = NullBlockDevice_GetBlockSize, }; return &instance; } @@ -125,3 +127,9 @@ static size_t NullBlockDevice_Size(struct SolidSyslogBlockDevice* base, size_t b (void) blockIndex; return 0; } + +static size_t NullBlockDevice_GetBlockSize(struct SolidSyslogBlockDevice* base) +{ + (void) base; + return 0; +} diff --git a/DEVLOG.md b/DEVLOG.md index c380ac29..9dc8c8cb 100644 --- a/DEVLOG.md +++ b/DEVLOG.md @@ -1,5 +1,60 @@ # Dev Log +## 2026-06-04 — S21.04 BlockDevice owns its block size + +Closes the last open thread under E21 (Port-Time Configurability). Block size moves +from `SolidSyslogBlockStoreConfig.MaxBlockSize` to a property of the +`SolidSyslogBlockDevice` — the device becomes the single source of truth, queried +once at `BlockStore_Create`. An API break, deliberately landed in the 0.x beta +window so 1.0.0 stays additive-only. + +### Decisions + +- **Device is the single source of truth, but the store keeps a usable floor and warns + (Design Z).** The block-size source moves from config to the device; what changes vs + the old code is only the *too-small* case. A first attempt (Design Y) rejected an + undersized block outright (`ERROR` → `NullStore`). CI showed the old + `max(deviceSize, oneRecord)` clamp was far more load-bearing than realised — it was a + *deliberate, documented* cross-target calibration mechanism (block size MAX-coupled + via the clamp), relied on by the drain-ordering tests **and** the + `store_capacity` / `capacity_threshold` / `block_lifecycle` BDD suites across host and + freertos-cross. Rejecting broke all of them, and re-deriving the per-target message-fit + math to keep them working is exactly the fragile calculation that has bitten this repo + before. So the clamp stays — a device whose block can't hold one worst-case record is + grown to that floor — but now emits a `WARNING` (`SOLIDSYSLOG_CAT_BAD_CONFIG` / + `BLOCKSTORE_ERROR_BLOCK_TOO_SMALL`): delivered, degraded, no longer silent. The store + still works; `GetBlockSize` reports the device's requested value. +- **`_Create(file, prefix, blockSize)` takes the size at construction**, preserving + the BDD targets' runtime `--max-block-size` knob (they route the parsed value into + the device instead of the store config). +- **`SOLIDSYSLOG_FILE_DEFAULT_BLOCK_SIZE` (8192), `0` selects it.** Floored at one + worst-case record; FatFs adapter adds a `defined()`-guarded compile-time `FF_MAX_SS` + floor on the default. + +### Sliced (strict red/green) + +1. `GetBlockSize` on the contract → 2. FileBlockDevice takes the size → 3. store +reads the device, `MaxBlockSize` dropped from config (clamp retained) → 4. default +tunable + `0→default` → 5. WARNING on clamp. 1396 host tests green throughout. + +### Worth remembering + +- **The clamp is a load-bearing, documented feature, not an accident.** + `syslog_steps.py` literally comments that the store_capacity scenarios *depend* on the + clamp making block size MAX-coupled. Design Y (reject) is wrong here precisely because + it removes that. Keep the clamp; make it loud, not silent. +- A `WARNING` is safe in the BDD targets: their stderr handler `_Exit(3)`s only on + `Severity <= ERROR`; a `WARNING` just prints and the process survives — which is why + the Y reject (ERROR) killed the BDD targets and Z (WARNING) does not. +- Size-varying BlockStore tests re-point the fixture device through an **idempotent** + `EnsureDeviceBlockSize` helper — same-size calls reuse the device so corruption- + recovery's single persistent file handle survives a destroy/recreate. + +### Not verified locally (CI's job) + +- FatFs `FF_MAX_SS` floor and the Windows / FreeRTOS BDD-target callers — the gcc + lane can't build them; their edits are symmetric to the green Linux target. + ## 2026-06-04 — S29.05 PlusFAT media driver + Plus-TCP target swap The last functional story of E29: a FreeRTOS-Plus-FAT `FF_Disk_t` semihosting diff --git a/Platform/FatFs/Source/SolidSyslogFatFsFile.c b/Platform/FatFs/Source/SolidSyslogFatFsFile.c index e60de6bb..4d21a031 100644 --- a/Platform/FatFs/Source/SolidSyslogFatFsFile.c +++ b/Platform/FatFs/Source/SolidSyslogFatFsFile.c @@ -8,8 +8,18 @@ #include "SolidSyslogFatFsFilePrivate.h" #include "SolidSyslogFileDefinition.h" #include "SolidSyslogNullFile.h" +#include "SolidSyslogTunables.h" #include "ff.h" +/* The shared file-block-size default must clear one FatFs sector — a block + * smaller than the underlying sector cannot back a coherent on-disk record + * layout. FF_MAX_SS comes from the integrator's ffconf.h; guard with defined() + * so the check is skipped (rather than evaluating an undefined identifier) on + * any configuration that does not expose it. */ +#if defined(FF_MAX_SS) && (SOLIDSYSLOG_FILE_DEFAULT_BLOCK_SIZE < FF_MAX_SS) +#error "SOLIDSYSLOG_FILE_DEFAULT_BLOCK_SIZE must be >= FF_MAX_SS (one FatFs sector)" +#endif + const struct SolidSyslogErrorSource FatFsFileErrorSource = {"FatFsFile"}; #define READ_WRITE_OR_CREATE (FA_READ | FA_WRITE | FA_OPEN_ALWAYS) diff --git a/Tests/SolidSyslogBlockStoreDrainOrderingTest.cpp b/Tests/SolidSyslogBlockStoreDrainOrderingTest.cpp index 78c6234d..fb6c6fde 100644 --- a/Tests/SolidSyslogBlockStoreDrainOrderingTest.cpp +++ b/Tests/SolidSyslogBlockStoreDrainOrderingTest.cpp @@ -19,6 +19,7 @@ extern "C" { #include "FileFake.h" #include "SolidSyslog.h" +#include "SolidSyslogBlockDevice.h" #include "SolidSyslogBlockStore.h" #include "SolidSyslogBuffer.h" #include "SolidSyslogCircularBuffer.h" @@ -118,10 +119,22 @@ TEST_BASE(DrainTestFixtureBase) void setupBlockDeviceAndPolicy() { file = FileFake_Create(&fileStorage); - device = SolidSyslogFileBlockDevice_Create(file, TEST_PATH_PREFIX); + device = SolidSyslogFileBlockDevice_Create(file, TEST_PATH_PREFIX, 4096); policy = SolidSyslogNullSecurityPolicy_Get(); } + /* Block size is a property of the device; re-point it (pool size 1, so + * destroy-then-recreate on the same FileFake) at the scenario's size. + * Idempotent — unchanged size reuses the existing device. */ + void ensureDeviceBlockSize(size_t blockSize) + { + if (SolidSyslogBlockDevice_GetBlockSize(device) != blockSize) + { + SolidSyslogFileBlockDevice_Destroy(device); + device = SolidSyslogFileBlockDevice_Create(file, TEST_PATH_PREFIX, blockSize); + } + } + void teardownBlockDeviceAndPolicy() const { SolidSyslogFileBlockDevice_Destroy(device); @@ -152,9 +165,9 @@ TEST_GROUP_BASE(BlockStoreDrainOrdering, DrainTestFixtureBase) void CreateStore(const DrainTestConfig& cfg) { + ensureDeviceBlockSize(cfg.MaxBlockSize); struct SolidSyslogBlockStoreConfig config = {}; config.BlockDevice = device; - config.MaxBlockSize = cfg.MaxBlockSize; config.MaxBlocks = cfg.MaxBlocks; config.DiscardPolicy = cfg.DiscardPolicy; config.SecurityPolicy = policy; @@ -248,9 +261,9 @@ TEST_GROUP_BASE(ServiceDrainInterleave, DrainTestFixtureBase) /* Build BlockStore + wire SolidSyslog facade with buffer + store + spy. */ void Setup(const DrainTestConfig& cfg) { + ensureDeviceBlockSize(cfg.MaxBlockSize); struct SolidSyslogBlockStoreConfig storeCfg = {}; storeCfg.BlockDevice = device; - storeCfg.MaxBlockSize = cfg.MaxBlockSize; storeCfg.MaxBlocks = cfg.MaxBlocks; storeCfg.DiscardPolicy = cfg.DiscardPolicy; storeCfg.SecurityPolicy = policy; @@ -298,7 +311,7 @@ TEST(ServiceDrainInterleave, DiscardNewestDoesNotLetNewestBypassOldestOnRecovery * with just a couple of messages. */ DrainTestConfig cfg = { /*maxBlocks=*/2, - /*maxBlockSize=*/200 /*will clamp up*/, + /*maxBlockSize=*/200 /*grown to one record by the store*/, /*payloadSize=*/SOLIDSYSLOG_MAX_MESSAGE_SIZE - 100U, SOLIDSYSLOG_DISCARD_POLICY_NEWEST }; diff --git a/Tests/SolidSyslogBlockStorePosixTest.cpp b/Tests/SolidSyslogBlockStorePosixTest.cpp index 7f08a42a..ceec7a33 100644 --- a/Tests/SolidSyslogBlockStorePosixTest.cpp +++ b/Tests/SolidSyslogBlockStorePosixTest.cpp @@ -4,6 +4,7 @@ #include #include "CppUTest/TestHarness.h" +#include "SolidSyslogBlockDevice.h" #include "SolidSyslogFileBlockDevice.h" #include "SolidSyslogBlockStore.h" #include "SolidSyslogPosixFile.h" @@ -46,7 +47,7 @@ TEST_GROUP(SolidSyslogBlockStorePosix) { CleanStoreFiles(); file = SolidSyslogPosixFile_Create(); - device = SolidSyslogFileBlockDevice_Create(file, TEST_PATH_PREFIX); + device = SolidSyslogFileBlockDevice_Create(file, TEST_PATH_PREFIX, 4096); std::memset(maxMsg, 'A', sizeof(maxMsg)); } @@ -61,9 +62,13 @@ TEST_GROUP(SolidSyslogBlockStorePosix) // NOLINTNEXTLINE(bugprone-easily-swappable-parameters) -- test helper mirrors rotation test group signature void CreateStore(size_t maxBlockSize = ONE_MAX_MSG_RECORD, size_t maxBlocks = 2) { + if (SolidSyslogBlockDevice_GetBlockSize(device) != maxBlockSize) + { + SolidSyslogFileBlockDevice_Destroy(device); + device = SolidSyslogFileBlockDevice_Create(file, TEST_PATH_PREFIX, maxBlockSize); + } struct SolidSyslogBlockStoreConfig config = {}; config.BlockDevice = device; - config.MaxBlockSize = maxBlockSize; config.MaxBlocks = maxBlocks; config.DiscardPolicy = SOLIDSYSLOG_DISCARD_POLICY_OLDEST; store = SolidSyslogBlockStore_Create(&config); diff --git a/Tests/SolidSyslogBlockStoreTest.cpp b/Tests/SolidSyslogBlockStoreTest.cpp index 911c9ebe..93d4b0ce 100644 --- a/Tests/SolidSyslogBlockStoreTest.cpp +++ b/Tests/SolidSyslogBlockStoreTest.cpp @@ -3,14 +3,19 @@ #include #include "CppUTest/TestHarness.h" +#include "SolidSyslogBlockDevice.h" #include "SolidSyslogBlockStore.h" +#include "SolidSyslogBlockStoreErrors.h" #include "SolidSyslogCrc16Policy.h" +#include "SolidSyslogError.h" +#include "SolidSyslogErrorCategory.h" #include "SolidSyslogFile.h" #include "SolidSyslogFileBlockDevice.h" #include "SolidSyslogNullStore.h" #include "SolidSyslogSecurityPolicyDefinition.h" #include "SolidSyslogStore.h" #include "SolidSyslogTunables.h" +#include "ErrorHandlerFake.h" #include "FileFake.h" #include "TestUtils.h" @@ -39,7 +44,6 @@ enum static const struct SolidSyslogBlockStoreConfig DEFAULT_CONFIG = { nullptr, - TEST_MAX_BLOCK_SIZE, TEST_MAX_BLOCKS, SOLIDSYSLOG_DISCARD_POLICY_OLDEST, nullptr, @@ -75,7 +79,7 @@ TEST_BASE(BlockDeviceTestBase) void setupBlockDeviceFakes() { file = FileFake_Create(&storage); - device = SolidSyslogFileBlockDevice_Create(file, TEST_PATH_PREFIX); + device = SolidSyslogFileBlockDevice_Create(file, TEST_PATH_PREFIX, TEST_MAX_BLOCK_SIZE); } void teardownBlockDeviceFakes() const @@ -86,6 +90,21 @@ TEST_BASE(BlockDeviceTestBase) } FileFake_Destroy(); } + + /* Block size is now a property of the device, not the store config. Tests that + * exercise a specific block size re-point the fixture device at it (pool size 1, + * so destroy-then-recreate on the same FileFake, mirroring CreateWithPathPrefix). + * Idempotent: when the size is unchanged the existing device is reused, so tests + * that rebuild the store on the same device (e.g. corruption recovery) keep their + * single persistent file handle. */ + void EnsureDeviceBlockSize(size_t blockSize) + { + if (SolidSyslogBlockDevice_GetBlockSize(device) != blockSize) + { + SolidSyslogFileBlockDevice_Destroy(device); + device = SolidSyslogFileBlockDevice_Create(file, TEST_PATH_PREFIX, blockSize); + } + } }; // clang-format on @@ -469,6 +488,7 @@ TEST_GROUP_BASE(SolidSyslogBlockStoreConfig, BlockDeviceTestBase) void teardown() override { + SolidSyslog_SetErrorHandler(nullptr, nullptr); SolidSyslogBlockStore_Destroy(store); teardownBlockDeviceFakes(); } @@ -482,15 +502,15 @@ TEST_GROUP_BASE(SolidSyslogBlockStoreConfig, BlockDeviceTestBase) void CreateWithMaxBlockSize(size_t maxBlockSize) { + EnsureDeviceBlockSize(maxBlockSize); struct SolidSyslogBlockStoreConfig config = MakeConfig(device); - config.MaxBlockSize = maxBlockSize; store = SolidSyslogBlockStore_Create(&config); } void CreateWithPathPrefix(const char* prefix) { SolidSyslogFileBlockDevice_Destroy(device); - device = SolidSyslogFileBlockDevice_Create(file, prefix); + device = SolidSyslogFileBlockDevice_Create(file, prefix, 4096); struct SolidSyslogBlockStoreConfig config = MakeConfig(device); store = SolidSyslogBlockStore_Create(&config); } @@ -525,18 +545,28 @@ TEST(SolidSyslogBlockStoreConfig, MaxBlocksHundredClampedToMaximum) VerifyWriteAndReadBack(); } -TEST(SolidSyslogBlockStoreConfig, MaxBlockSizeZeroClampedToMinimum) +TEST(SolidSyslogBlockStoreConfig, ZeroBlockSizeUsesDeviceDefault) { CreateWithMaxBlockSize(0); VerifyWriteAndReadBack(); } -TEST(SolidSyslogBlockStoreConfig, MaxBlockSizeOneClampedToMinimum) +TEST(SolidSyslogBlockStoreConfig, BelowMinimumBlockSizeIsGrownAndStoreWorks) { CreateWithMaxBlockSize(1); + CHECK(store != SolidSyslogNullStore_Get()); VerifyWriteAndReadBack(); } +TEST(SolidSyslogBlockStoreConfig, BelowMinimumBlockSizeReportsWarning) +{ + ErrorHandlerFake_Install(nullptr); + CreateWithMaxBlockSize(1); + LONGS_EQUAL(SOLIDSYSLOG_SEVERITY_WARNING, ErrorHandlerFake_LastSeverity()); + UNSIGNED_LONGS_EQUAL(SOLIDSYSLOG_CAT_BAD_CONFIG, ErrorHandlerFake_LastCategory()); + UNSIGNED_LONGS_EQUAL(BLOCKSTORE_ERROR_BLOCK_TOO_SMALL, ErrorHandlerFake_LastDetail()); +} + TEST(SolidSyslogBlockStoreConfig, FilenameExactlyAtMaxPath) { /* SOLIDSYSLOG_MAX_PATH_SIZE=128, suffix "00.log"=6, null=1, so max prefix=121 chars */ @@ -703,9 +733,9 @@ TEST_GROUP_BASE(SolidSyslogBlockStoreRotation, BlockDeviceTestBase) size_t maxBlocks = 2, SolidSyslogStoreFullCallback onStoreFull = nullptr, void* storeFullContext = nullptr) { + EnsureDeviceBlockSize(maxBlockSize); struct SolidSyslogBlockStoreConfig config = DEFAULT_CONFIG; config.BlockDevice = device; - config.MaxBlockSize = maxBlockSize; config.MaxBlocks = maxBlocks; config.DiscardPolicy = policy; config.OnStoreFull = onStoreFull; @@ -1685,9 +1715,9 @@ TEST_GROUP_BASE(SolidSyslogBlockStoreCorruptionRecovery, BlockDeviceTestBase) // NOLINTNEXTLINE(bugprone-easily-swappable-parameters) -- maxBlockSize and maxBlocks have distinct semantics void CreateWithMaxBlockSize(size_t maxBlockSize, size_t maxBlocks = 2) { + EnsureDeviceBlockSize(maxBlockSize); struct SolidSyslogBlockStoreConfig config = DEFAULT_CONFIG; config.BlockDevice = device; - config.MaxBlockSize = maxBlockSize; config.MaxBlocks = maxBlocks; config.SecurityPolicy = policy; store = SolidSyslogBlockStore_Create(&config); @@ -1787,8 +1817,8 @@ TEST_GROUP_BASE(SolidSyslogBlockStoreCapacity, BlockDeviceTestBase) void CreateWithCapacity(size_t maxBlockSize, size_t maxBlocks, enum SolidSyslogDiscardPolicy policy = SOLIDSYSLOG_DISCARD_POLICY_OLDEST) { + EnsureDeviceBlockSize(maxBlockSize); struct SolidSyslogBlockStoreConfig config = MakeConfig(device); - config.MaxBlockSize = maxBlockSize; config.MaxBlocks = maxBlocks; config.DiscardPolicy = policy; store = SolidSyslogBlockStore_Create(&config); @@ -1817,6 +1847,13 @@ TEST(SolidSyslogBlockStoreCapacity, GetTotalBytesScalesWithConfig) LONGS_EQUAL(3 * 10000, SolidSyslogStore_GetTotalBytes(store)); } +TEST(SolidSyslogBlockStoreCapacity, TotalBytesDerivesFromDeviceBlockSize) +{ + EnsureDeviceBlockSize(8192); + CreateDefault(); + LONGS_EQUAL(TEST_MAX_BLOCKS * 8192, SolidSyslogStore_GetTotalBytes(store)); +} + /* Given an empty store, * When GetUsedBytes is queried, * Then it returns 0. */ @@ -1964,8 +2001,8 @@ TEST(SolidSyslogBlockStoreCapacityThreshold, ReArmsAfterFallingEdgeOnDiscardOlde char maxMsg[SOLIDSYSLOG_MAX_MESSAGE_SIZE]; memset(maxMsg, 'A', sizeof(maxMsg)); + EnsureDeviceBlockSize(TWO_RECORDS); struct SolidSyslogBlockStoreConfig config = MakeConfig(device); - config.MaxBlockSize = TWO_RECORDS; config.MaxBlocks = 2; config.DiscardPolicy = SOLIDSYSLOG_DISCARD_POLICY_OLDEST; config.GetCapacityThreshold = ReturnsConfiguredThreshold; @@ -2076,8 +2113,8 @@ TEST(SolidSyslogBlockStoreCapacityThreshold, AtFullCapacityWithHaltThresholdFire thresholdFireOrder = 0; storeFullFireOrder = 0; + EnsureDeviceBlockSize(MAX_MSG_RECORD + SLACK); struct SolidSyslogBlockStoreConfig config = MakeConfig(device); - config.MaxBlockSize = MAX_MSG_RECORD + SLACK; config.MaxBlocks = 2; config.DiscardPolicy = SOLIDSYSLOG_DISCARD_POLICY_HALT; config.OnStoreFull = RecordStoreFullFireOrder; @@ -2107,8 +2144,8 @@ TEST(SolidSyslogBlockStoreCapacityThreshold, StickyHundredPercentDoesNotRefireTh char maxMsg[SOLIDSYSLOG_MAX_MESSAGE_SIZE]; memset(maxMsg, 'A', sizeof(maxMsg)); + EnsureDeviceBlockSize(MAX_MSG_RECORD + SLACK); struct SolidSyslogBlockStoreConfig config = MakeConfig(device); - config.MaxBlockSize = MAX_MSG_RECORD + SLACK; config.MaxBlocks = 2; config.DiscardPolicy = SOLIDSYSLOG_DISCARD_POLICY_HALT; config.GetCapacityThreshold = ReturnsConfiguredThreshold; diff --git a/Tests/SolidSyslogFileBlockDeviceTest.cpp b/Tests/SolidSyslogFileBlockDeviceTest.cpp index d9943cfe..2e9e1772 100644 --- a/Tests/SolidSyslogFileBlockDeviceTest.cpp +++ b/Tests/SolidSyslogFileBlockDeviceTest.cpp @@ -37,7 +37,7 @@ TEST_GROUP(SolidSyslogFileBlockDevice) void setup() override { file = FileFake_Create(&fileStorage); - device = SolidSyslogFileBlockDevice_Create(file, TEST_PATH_PREFIX); + device = SolidSyslogFileBlockDevice_Create(file, TEST_PATH_PREFIX, 4096); } void teardown() override @@ -57,6 +57,18 @@ TEST(SolidSyslogFileBlockDevice, CreateReturnsNonNull) CHECK_TRUE(device != nullptr); } +TEST(SolidSyslogFileBlockDevice, GetBlockSizeReturnsCreatedSize) +{ + LONGS_EQUAL(4096, SolidSyslogBlockDevice_GetBlockSize(device)); +} + +TEST(SolidSyslogFileBlockDevice, ZeroBlockSizeUsesDefault) +{ + SolidSyslogFileBlockDevice_Destroy(device); + device = SolidSyslogFileBlockDevice_Create(file, TEST_PATH_PREFIX, 0); + LONGS_EQUAL(SOLIDSYSLOG_FILE_DEFAULT_BLOCK_SIZE, SolidSyslogBlockDevice_GetBlockSize(device)); +} + TEST(SolidSyslogFileBlockDevice, ExistsReturnsFalseOnFreshSlate) { CHECK_FALSE(SolidSyslogBlockDevice_Exists(device, 0)); @@ -308,7 +320,7 @@ TEST_GROUP(SolidSyslogFileBlockDevicePool) [[nodiscard]] struct SolidSyslogBlockDevice* MakeDevice() const { - return SolidSyslogFileBlockDevice_Create(file, TEST_PATH_PREFIX); + return SolidSyslogFileBlockDevice_Create(file, TEST_PATH_PREFIX, 4096); } void FillPool() diff --git a/Tests/SolidSyslogNullBlockDeviceTest.cpp b/Tests/SolidSyslogNullBlockDeviceTest.cpp index ebc187cc..6f3f54a9 100644 --- a/Tests/SolidSyslogNullBlockDeviceTest.cpp +++ b/Tests/SolidSyslogNullBlockDeviceTest.cpp @@ -56,6 +56,11 @@ TEST(SolidSyslogNullBlockDevice, SizeReturnsZero) LONGS_EQUAL(0, SolidSyslogBlockDevice_Size(device, 0)); } +TEST(SolidSyslogNullBlockDevice, GetBlockSizeReturnsZero) +{ + LONGS_EQUAL(0, SolidSyslogBlockDevice_GetBlockSize(device)); +} + TEST(SolidSyslogNullBlockDevice, GetIsIdempotentAndReturnsSameInstance) { POINTERS_EQUAL(device, SolidSyslogNullBlockDevice_Get()); diff --git a/misra_suppressions.txt b/misra_suppressions.txt index b55acc09..3cbc2454 100644 --- a/misra_suppressions.txt +++ b/misra_suppressions.txt @@ -26,7 +26,7 @@ misra-c2012-11.2:Platform/Windows/Source/SolidSyslogWinsockAddressPrivate.h:30 misra-c2012-11.3:Core/Interface/SolidSyslogFormatter.h:28 misra-c2012-11.3:Core/Source/SolidSyslogBlockStore.c:73 misra-c2012-11.3:Core/Source/SolidSyslogCircularBuffer.c:91 -misra-c2012-11.3:Core/Source/SolidSyslogFileBlockDevice.c:102 +misra-c2012-11.3:Core/Source/SolidSyslogFileBlockDevice.c:106 misra-c2012-11.3:Core/Source/SolidSyslogFormatter.c:79 misra-c2012-11.3:Core/Source/SolidSyslogMetaSd.c:55 misra-c2012-11.3:Core/Source/SolidSyslogOriginSd.c:73 @@ -36,7 +36,7 @@ misra-c2012-11.3:Core/Source/SolidSyslogSwitchingSender.c:63 misra-c2012-11.3:Core/Source/SolidSyslogTimeQualitySd.c:63 misra-c2012-11.3:Core/Source/SolidSyslogUdpSender.c:100 misra-c2012-11.3:Platform/Atomics/Source/SolidSyslogStdAtomicCounter.c:29 -misra-c2012-11.3:Platform/FatFs/Source/SolidSyslogFatFsFile.c:49 +misra-c2012-11.3:Platform/FatFs/Source/SolidSyslogFatFsFile.c:59 misra-c2012-11.3:Platform/PlusFat/Source/SolidSyslogPlusFatFile.c:47 misra-c2012-11.3:Platform/LwipRaw/Source/SolidSyslogLwipRawAddressPrivate.h:29 misra-c2012-11.3:Platform/LwipRaw/Source/SolidSyslogLwipRawAddressPrivate.h:36 @@ -116,7 +116,9 @@ misra-c2012-11.8:Core/Source/SolidSyslogMessageFormatter.c:59 misra-c2012-11.8:Core/Source/SolidSyslogMessageFormatter.c:61 misra-c2012-11.8:Core/Source/SolidSyslogMessageFormatter.c:63 misra-c2012-11.8:Core/Source/SolidSyslogMessageFormatter.c:67 -misra-c2012-11.8:Core/Source/SolidSyslogBlockStoreStatic.c:41 +misra-c2012-11.8:Core/Source/SolidSyslogBlockStoreStatic.c:46 +misra-c2012-11.8:Core/Source/SolidSyslogBlockStoreStatic.c:113 +misra-c2012-11.8:Core/Source/SolidSyslogBlockStoreStatic.c:139 misra-c2012-11.8:Platform/LwipRaw/Source/SolidSyslogLwipRawDatagram.c:159 misra-c2012-11.8:Platform/Windows/Source/SolidSyslogWinsockTcpStream.c:97