lx_nor_flash_free_physical_sectors == 0, reclaim not possible although there is space on the device #48

Description

@Iktek

Dear List,
i got an issue with LevelX 6.1.7 ( ) used in conjunction with FileX + ThreadX on an STM32H563 connected to a serial Flash via a custom driver.

Describe the bug

I somehow managed it to come into a situation where lx_nor_flash_free_physical_sectors == 0, which means that a write may end in an (nearly endless) loop, because the block may not be reclaimed ( which is tried until lx_nor_flash_total_block only but will continue again on next write-try ). The Flash-Structure still shows 276 obsolete sectors ( see nor_flash struct on the bottom of this page )

I'm just wondering if this can happen because of some erroneous condition from outside of levelX which is not catched gracefully or if i caught a bug in levelX code here.

I found out that the while loop checking if a reclaim is to be made is only existing in "lx_nor_flash_sector_write.c" @ line 114, which in my opinion would mean that it's possible to reach a lx_nor_flash_free_physical_sectors of 0 by reading sectors that are not mapped ( read routine also allocates sectors in lx_nor_flash_sector_read.c @ line 140 ) .

If this happened sometime before the reclaim routine may walk through all the blocks trying to reclaim but will fail each time because there are no physical blocks to copy the content to. This may also be checked in advance to not block the system all the time.

I also had a short look at the current development code if some of the issues may be fixed now, but i did not find fixes here up to now ( maybe I've overlooked something )

To Reproduce
Hard to reproduce.
This may only being reproduced on a rather small serial flash where writes and reads are done randomly over a longer time reaching the end of the flash, having no physical sectors free any more. I'll continue try reproducing in the next days and update the issue when there are more clear steps to do so.

Expected behavior
I excpect that the levelX does not run into the situation when there are no free sectors any more before a reclaim takes place. ( except filesystem is really full and fx routines will therefore fail directly ) May this be fixed by introducing another reclaim-while-loop to the read routine, or are there sill other pitfalls?

I also expect that the reclaim will fail when there are not enough free sectors outside of the block to reclaim (checked in lx_nor-flash_block_reclaim.c @ line 238) which then should break the reclaim loop in the write routine to not block the whole system.

** Impact **
Showstopper -> Filesystem unuseable

** Logs and Console Output **

On a sector write we try to reclame same erase_block all the time:

_lx_nor_flash_sector_write: free phys: 0 sect/block: 7
_lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
_lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
_lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
_lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
_lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
... // this runns nearly endless

** Additional Context **
The Filesystem still shows 968 kB of free space on a 4M serial-flash.

Contents of LEVELX nor-flash struct:

lx_nor_flash_state ULONG 1313821263
lx_nor_flash_total_blocks ULONG 1024
lx_nor_flash_words_per_block ULONG 1024
lx_nor_flash_total_physical_sectors ULONG 7168
lx_nor_flash_physical_sectors_per_block ULONG 7
lx_nor_flash_base_address ULONG * 0x0
lx_nor_flash_block_free_bit_map_offset ULONG 3
lx_nor_flash_block_bit_map_words ULONG 1
lx_nor_flash_block_bit_map_mask ULONG 127
lx_nor_flash_block_physical_sector_mapping_offset ULONG 4
lx_nor_flash_block_physical_sector_offset ULONG 128
lx_nor_flash_free_physical_sectors ULONG 0
lx_nor_flash_mapped_physical_sectors ULONG 6892
lx_nor_flash_obsolete_physical_sectors ULONG 276
lx_nor_flash_minimum_erase_count ULONG 3
lx_nor_flash_maximum_erase_count ULONG 9
lx_nor_flash_free_block_search ULONG 0
lx_nor_flash_found_block_search ULONG 997
lx_nor_flash_found_sector_search ULONG 0
lx_nor_flash_write_requests ULONG 0
lx_nor_flash_read_requests ULONG 42
lx_nor_flash_sector_mapping_cache_hits ULONG 22
lx_nor_flash_sector_mapping_cache_misses ULONG 20
lx_nor_flash_physical_block_allocates ULONG 0
lx_nor_flash_physical_block_allocate_errors ULONG 0
lx_nor_flash_diagnostic_system_errors ULONG 0
lx_nor_flash_diagnostic_system_error ULONG 0
lx_nor_flash_diagnostic_initial_format ULONG 0
lx_nor_flash_diagnostic_erased_block ULONG 0
lx_nor_flash_diagnostic_re_erase_block ULONG 0
lx_nor_flash_diagnostic_sector_being_obsoleted ULONG 0
lx_nor_flash_diagnostic_sector_obsoleted ULONG 0
lx_nor_flash_diagnostic_mapping_invalidated ULONG 0
lx_nor_flash_diagnostic_mapping_write_interrupted ULONG 0
lx_nor_flash_diagnostic_sector_not_free ULONG 0
lx_nor_flash_diagnostic_sector_data_not_free ULONG 0
lx_nor_flash_driver_read UINT (*)(ULONG , ULONG , ULONG) 0x803208d <FxSerialFlash_Read>
lx_nor_flash_driver_write UINT (
)(ULONG , ULONG , ULONG) 0x80320f9 <FxSerialFlash_Write>
lx_nor_flash_driver_block_erase UINT (
)(ULONG, ULONG) 0x80321dd <FxSerialFlash_BlockErase>
lx_nor_flash_driver_block_erased_verify UINT (
)(ULONG) 0x8032165 <FxSerialFlash_BlockEraseVerify>
lx_nor_flash_driver_system_error UINT (
)(UINT) 0x0
lx_nor_flash_sector_buffer ULONG * 0x20042c14 <g_fx_serial_flash+9412>
lx_nor_flash_sector_mapping_cache_enabled UINT 1
lx_nor_flash_sector_mapping_cache LX_NOR_SECTOR_MAPPING_CACHE_ENTRY [16] 0x200000e0 <fx_lx_nor_drivers+172>
lx_nor_flash_extended_cache_entries UINT 0
lx_nor_flash_extended_cache LX_NOR_FLASH_EXTENDED_CACHE_ENTRY [8] 0x200001a4 <fx_lx_nor_drivers+368>
lx_nor_flash_extended_cache_hits ULONG 0
lx_nor_flash_extended_cache_misses ULONG 0
lx_nor_flash_mutex TX_MUTEX {...}
lx_nor_flash_open_next struct LX_NOR_FLASH_STRUCT * 0x20000034 <fx_lx_nor_drivers>
lx_nor_flash_open_previous struct LX_NOR_FLASH_STRUCT * 0x20000034 <fx_lx_nor_drivers>

LevelX, ThreadX, FileX coming from STM32Cube_FW_H5_V1.2.0

LX_NOR_SECTOR_SIZE (512/sizeof(ULONG))

FX is initialzed as follows:
#define SF_SECTOR_SIZE (LX_NOR_SECTOR_SIZE * sizeof(ULONG))
#define SF_NUM_FATS (1)
#define SF_DIR_ENTRIES (32)
#define SF_HIDDEN_SECTORS (0)
#define SF_SECTORS_PER_CLUSTER (8)
#define SF_HEADS (1)
#define SF_SECTORS_PER_TRACK (1)

status = fx_media_format(&fsf->media, // nor_simulator_flash_disk pointer
fx_stm32_levelx_nor_driver, // Driver entry
(void*)NOR_CUSTOM_DRIVER_ID, // Device info pointer
(UCHAR *) fsf->media_mem, // Media buffer pointer
SF_SECTOR_SIZE, // Media buffer size
SF_VOLUME_NAME, // Volume Name
SF_NUM_FATS, // Number of FATs
SF_DIR_ENTRIES, // Directory Entries
SF_HIDDEN_SECTORS, // Hidden sectors
(flash_size / SF_SECTOR_SIZE), // Total sectors
SF_SECTOR_SIZE, // Sector size
SF_SECTORS_PER_CLUSTER, // Sectors per cluster
SF_HEADS, // Heads
SF_SECTORS_PER_TRACK);

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
       blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
      }
      } catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
      })();
      (function(){
      try {
      var __m = "github.com";
      var __re = new RegExp('^' + "github\\.com" + '
      
      Skip to content

      lx_nor_flash_free_physical_sectors == 0, reclaim not possible although there is space on the device #48

      Description

      @Iktek

      Dear List,
      i got an issue with LevelX 6.1.7 ( ) used in conjunction with FileX + ThreadX on an STM32H563 connected to a serial Flash via a custom driver.

      Describe the bug

      I somehow managed it to come into a situation where lx_nor_flash_free_physical_sectors == 0, which means that a write may end in an (nearly endless) loop, because the block may not be reclaimed ( which is tried until lx_nor_flash_total_block only but will continue again on next write-try ). The Flash-Structure still shows 276 obsolete sectors ( see nor_flash struct on the bottom of this page )

      I'm just wondering if this can happen because of some erroneous condition from outside of levelX which is not catched gracefully or if i caught a bug in levelX code here.

      I found out that the while loop checking if a reclaim is to be made is only existing in "lx_nor_flash_sector_write.c" @ line 114, which in my opinion would mean that it's possible to reach a lx_nor_flash_free_physical_sectors of 0 by reading sectors that are not mapped ( read routine also allocates sectors in lx_nor_flash_sector_read.c @ line 140 ) .

      If this happened sometime before the reclaim routine may walk through all the blocks trying to reclaim but will fail each time because there are no physical blocks to copy the content to. This may also be checked in advance to not block the system all the time.

      I also had a short look at the current development code if some of the issues may be fixed now, but i did not find fixes here up to now ( maybe I've overlooked something )

      To Reproduce
      Hard to reproduce.
      This may only being reproduced on a rather small serial flash where writes and reads are done randomly over a longer time reaching the end of the flash, having no physical sectors free any more. I'll continue try reproducing in the next days and update the issue when there are more clear steps to do so.

      Expected behavior
      I excpect that the levelX does not run into the situation when there are no free sectors any more before a reclaim takes place. ( except filesystem is really full and fx routines will therefore fail directly ) May this be fixed by introducing another reclaim-while-loop to the read routine, or are there sill other pitfalls?

      I also expect that the reclaim will fail when there are not enough free sectors outside of the block to reclaim (checked in lx_nor-flash_block_reclaim.c @ line 238) which then should break the reclaim loop in the write routine to not block the whole system.

      ** Impact **
      Showstopper -> Filesystem unuseable

      ** Logs and Console Output **

      On a sector write we try to reclame same erase_block all the time:

      _lx_nor_flash_sector_write: free phys: 0 sect/block: 7
      _lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
      _lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
      _lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
      _lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
      _lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
      ... // this runns nearly endless

      ** Additional Context **
      The Filesystem still shows 968 kB of free space on a 4M serial-flash.

      Contents of LEVELX nor-flash struct:

      lx_nor_flash_state ULONG 1313821263
      lx_nor_flash_total_blocks ULONG 1024
      lx_nor_flash_words_per_block ULONG 1024
      lx_nor_flash_total_physical_sectors ULONG 7168
      lx_nor_flash_physical_sectors_per_block ULONG 7
      lx_nor_flash_base_address ULONG * 0x0
      lx_nor_flash_block_free_bit_map_offset ULONG 3
      lx_nor_flash_block_bit_map_words ULONG 1
      lx_nor_flash_block_bit_map_mask ULONG 127
      lx_nor_flash_block_physical_sector_mapping_offset ULONG 4
      lx_nor_flash_block_physical_sector_offset ULONG 128
      lx_nor_flash_free_physical_sectors ULONG 0
      lx_nor_flash_mapped_physical_sectors ULONG 6892
      lx_nor_flash_obsolete_physical_sectors ULONG 276
      lx_nor_flash_minimum_erase_count ULONG 3
      lx_nor_flash_maximum_erase_count ULONG 9
      lx_nor_flash_free_block_search ULONG 0
      lx_nor_flash_found_block_search ULONG 997
      lx_nor_flash_found_sector_search ULONG 0
      lx_nor_flash_write_requests ULONG 0
      lx_nor_flash_read_requests ULONG 42
      lx_nor_flash_sector_mapping_cache_hits ULONG 22
      lx_nor_flash_sector_mapping_cache_misses ULONG 20
      lx_nor_flash_physical_block_allocates ULONG 0
      lx_nor_flash_physical_block_allocate_errors ULONG 0
      lx_nor_flash_diagnostic_system_errors ULONG 0
      lx_nor_flash_diagnostic_system_error ULONG 0
      lx_nor_flash_diagnostic_initial_format ULONG 0
      lx_nor_flash_diagnostic_erased_block ULONG 0
      lx_nor_flash_diagnostic_re_erase_block ULONG 0
      lx_nor_flash_diagnostic_sector_being_obsoleted ULONG 0
      lx_nor_flash_diagnostic_sector_obsoleted ULONG 0
      lx_nor_flash_diagnostic_mapping_invalidated ULONG 0
      lx_nor_flash_diagnostic_mapping_write_interrupted ULONG 0
      lx_nor_flash_diagnostic_sector_not_free ULONG 0
      lx_nor_flash_diagnostic_sector_data_not_free ULONG 0
      lx_nor_flash_driver_read UINT (*)(ULONG , ULONG , ULONG) 0x803208d <FxSerialFlash_Read>
      lx_nor_flash_driver_write UINT (
      )(ULONG , ULONG , ULONG) 0x80320f9 <FxSerialFlash_Write>
      lx_nor_flash_driver_block_erase UINT (
      )(ULONG, ULONG) 0x80321dd <FxSerialFlash_BlockErase>
      lx_nor_flash_driver_block_erased_verify UINT (
      )(ULONG) 0x8032165 <FxSerialFlash_BlockEraseVerify>
      lx_nor_flash_driver_system_error UINT (
      )(UINT) 0x0
      lx_nor_flash_sector_buffer ULONG * 0x20042c14 <g_fx_serial_flash+9412>
      lx_nor_flash_sector_mapping_cache_enabled UINT 1
      lx_nor_flash_sector_mapping_cache LX_NOR_SECTOR_MAPPING_CACHE_ENTRY [16] 0x200000e0 <fx_lx_nor_drivers+172>
      lx_nor_flash_extended_cache_entries UINT 0
      lx_nor_flash_extended_cache LX_NOR_FLASH_EXTENDED_CACHE_ENTRY [8] 0x200001a4 <fx_lx_nor_drivers+368>
      lx_nor_flash_extended_cache_hits ULONG 0
      lx_nor_flash_extended_cache_misses ULONG 0
      lx_nor_flash_mutex TX_MUTEX {...}
      lx_nor_flash_open_next struct LX_NOR_FLASH_STRUCT * 0x20000034 <fx_lx_nor_drivers>
      lx_nor_flash_open_previous struct LX_NOR_FLASH_STRUCT * 0x20000034 <fx_lx_nor_drivers>

      LevelX, ThreadX, FileX coming from STM32Cube_FW_H5_V1.2.0

      LX_NOR_SECTOR_SIZE (512/sizeof(ULONG))

      FX is initialzed as follows:
      #define SF_SECTOR_SIZE (LX_NOR_SECTOR_SIZE * sizeof(ULONG))
      #define SF_NUM_FATS (1)
      #define SF_DIR_ENTRIES (32)
      #define SF_HIDDEN_SECTORS (0)
      #define SF_SECTORS_PER_CLUSTER (8)
      #define SF_HEADS (1)
      #define SF_SECTORS_PER_TRACK (1)

      status = fx_media_format(&fsf->media, // nor_simulator_flash_disk pointer
      fx_stm32_levelx_nor_driver, // Driver entry
      (void*)NOR_CUSTOM_DRIVER_ID, // Device info pointer
      (UCHAR *) fsf->media_mem, // Media buffer pointer
      SF_SECTOR_SIZE, // Media buffer size
      SF_VOLUME_NAME, // Volume Name
      SF_NUM_FATS, // Number of FATs
      SF_DIR_ENTRIES, // Directory Entries
      SF_HIDDEN_SECTORS, // Hidden sectors
      (flash_size / SF_SECTOR_SIZE), // Total sectors
      SF_SECTOR_SIZE, // Sector size
      SF_SECTORS_PER_CLUSTER, // Sectors per cluster
      SF_HEADS, // Heads
      SF_SECTORS_PER_TRACK);

      Metadata

      Metadata

      Assignees

      No one assigned

        Labels

        bugSomething isn't working

        Type

        No type

        Projects

        No projects

          Milestone

          No milestone

          Relationships

          None yet

          Development

          No branches or pull requests

          Issue actions

          , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
          Skip to content

          lx_nor_flash_free_physical_sectors == 0, reclaim not possible although there is space on the device #48

          Description

          @Iktek

          Dear List,
          i got an issue with LevelX 6.1.7 ( ) used in conjunction with FileX + ThreadX on an STM32H563 connected to a serial Flash via a custom driver.

          Describe the bug

          I somehow managed it to come into a situation where lx_nor_flash_free_physical_sectors == 0, which means that a write may end in an (nearly endless) loop, because the block may not be reclaimed ( which is tried until lx_nor_flash_total_block only but will continue again on next write-try ). The Flash-Structure still shows 276 obsolete sectors ( see nor_flash struct on the bottom of this page )

          I'm just wondering if this can happen because of some erroneous condition from outside of levelX which is not catched gracefully or if i caught a bug in levelX code here.

          I found out that the while loop checking if a reclaim is to be made is only existing in "lx_nor_flash_sector_write.c" @ line 114, which in my opinion would mean that it's possible to reach a lx_nor_flash_free_physical_sectors of 0 by reading sectors that are not mapped ( read routine also allocates sectors in lx_nor_flash_sector_read.c @ line 140 ) .

          If this happened sometime before the reclaim routine may walk through all the blocks trying to reclaim but will fail each time because there are no physical blocks to copy the content to. This may also be checked in advance to not block the system all the time.

          I also had a short look at the current development code if some of the issues may be fixed now, but i did not find fixes here up to now ( maybe I've overlooked something )

          To Reproduce
          Hard to reproduce.
          This may only being reproduced on a rather small serial flash where writes and reads are done randomly over a longer time reaching the end of the flash, having no physical sectors free any more. I'll continue try reproducing in the next days and update the issue when there are more clear steps to do so.

          Expected behavior
          I excpect that the levelX does not run into the situation when there are no free sectors any more before a reclaim takes place. ( except filesystem is really full and fx routines will therefore fail directly ) May this be fixed by introducing another reclaim-while-loop to the read routine, or are there sill other pitfalls?

          I also expect that the reclaim will fail when there are not enough free sectors outside of the block to reclaim (checked in lx_nor-flash_block_reclaim.c @ line 238) which then should break the reclaim loop in the write routine to not block the whole system.

          ** Impact **
          Showstopper -> Filesystem unuseable

          ** Logs and Console Output **

          On a sector write we try to reclame same erase_block all the time:

          _lx_nor_flash_sector_write: free phys: 0 sect/block: 7
          _lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
          _lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
          _lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
          _lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
          _lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
          ... // this runns nearly endless

          ** Additional Context **
          The Filesystem still shows 968 kB of free space on a 4M serial-flash.

          Contents of LEVELX nor-flash struct:

          lx_nor_flash_state ULONG 1313821263
          lx_nor_flash_total_blocks ULONG 1024
          lx_nor_flash_words_per_block ULONG 1024
          lx_nor_flash_total_physical_sectors ULONG 7168
          lx_nor_flash_physical_sectors_per_block ULONG 7
          lx_nor_flash_base_address ULONG * 0x0
          lx_nor_flash_block_free_bit_map_offset ULONG 3
          lx_nor_flash_block_bit_map_words ULONG 1
          lx_nor_flash_block_bit_map_mask ULONG 127
          lx_nor_flash_block_physical_sector_mapping_offset ULONG 4
          lx_nor_flash_block_physical_sector_offset ULONG 128
          lx_nor_flash_free_physical_sectors ULONG 0
          lx_nor_flash_mapped_physical_sectors ULONG 6892
          lx_nor_flash_obsolete_physical_sectors ULONG 276
          lx_nor_flash_minimum_erase_count ULONG 3
          lx_nor_flash_maximum_erase_count ULONG 9
          lx_nor_flash_free_block_search ULONG 0
          lx_nor_flash_found_block_search ULONG 997
          lx_nor_flash_found_sector_search ULONG 0
          lx_nor_flash_write_requests ULONG 0
          lx_nor_flash_read_requests ULONG 42
          lx_nor_flash_sector_mapping_cache_hits ULONG 22
          lx_nor_flash_sector_mapping_cache_misses ULONG 20
          lx_nor_flash_physical_block_allocates ULONG 0
          lx_nor_flash_physical_block_allocate_errors ULONG 0
          lx_nor_flash_diagnostic_system_errors ULONG 0
          lx_nor_flash_diagnostic_system_error ULONG 0
          lx_nor_flash_diagnostic_initial_format ULONG 0
          lx_nor_flash_diagnostic_erased_block ULONG 0
          lx_nor_flash_diagnostic_re_erase_block ULONG 0
          lx_nor_flash_diagnostic_sector_being_obsoleted ULONG 0
          lx_nor_flash_diagnostic_sector_obsoleted ULONG 0
          lx_nor_flash_diagnostic_mapping_invalidated ULONG 0
          lx_nor_flash_diagnostic_mapping_write_interrupted ULONG 0
          lx_nor_flash_diagnostic_sector_not_free ULONG 0
          lx_nor_flash_diagnostic_sector_data_not_free ULONG 0
          lx_nor_flash_driver_read UINT (*)(ULONG , ULONG , ULONG) 0x803208d <FxSerialFlash_Read>
          lx_nor_flash_driver_write UINT (
          )(ULONG , ULONG , ULONG) 0x80320f9 <FxSerialFlash_Write>
          lx_nor_flash_driver_block_erase UINT (
          )(ULONG, ULONG) 0x80321dd <FxSerialFlash_BlockErase>
          lx_nor_flash_driver_block_erased_verify UINT (
          )(ULONG) 0x8032165 <FxSerialFlash_BlockEraseVerify>
          lx_nor_flash_driver_system_error UINT (
          )(UINT) 0x0
          lx_nor_flash_sector_buffer ULONG * 0x20042c14 <g_fx_serial_flash+9412>
          lx_nor_flash_sector_mapping_cache_enabled UINT 1
          lx_nor_flash_sector_mapping_cache LX_NOR_SECTOR_MAPPING_CACHE_ENTRY [16] 0x200000e0 <fx_lx_nor_drivers+172>
          lx_nor_flash_extended_cache_entries UINT 0
          lx_nor_flash_extended_cache LX_NOR_FLASH_EXTENDED_CACHE_ENTRY [8] 0x200001a4 <fx_lx_nor_drivers+368>
          lx_nor_flash_extended_cache_hits ULONG 0
          lx_nor_flash_extended_cache_misses ULONG 0
          lx_nor_flash_mutex TX_MUTEX {...}
          lx_nor_flash_open_next struct LX_NOR_FLASH_STRUCT * 0x20000034 <fx_lx_nor_drivers>
          lx_nor_flash_open_previous struct LX_NOR_FLASH_STRUCT * 0x20000034 <fx_lx_nor_drivers>

          LevelX, ThreadX, FileX coming from STM32Cube_FW_H5_V1.2.0

          LX_NOR_SECTOR_SIZE (512/sizeof(ULONG))

          FX is initialzed as follows:
          #define SF_SECTOR_SIZE (LX_NOR_SECTOR_SIZE * sizeof(ULONG))
          #define SF_NUM_FATS (1)
          #define SF_DIR_ENTRIES (32)
          #define SF_HIDDEN_SECTORS (0)
          #define SF_SECTORS_PER_CLUSTER (8)
          #define SF_HEADS (1)
          #define SF_SECTORS_PER_TRACK (1)

          status = fx_media_format(&fsf->media, // nor_simulator_flash_disk pointer
          fx_stm32_levelx_nor_driver, // Driver entry
          (void*)NOR_CUSTOM_DRIVER_ID, // Device info pointer
          (UCHAR *) fsf->media_mem, // Media buffer pointer
          SF_SECTOR_SIZE, // Media buffer size
          SF_VOLUME_NAME, // Volume Name
          SF_NUM_FATS, // Number of FATs
          SF_DIR_ENTRIES, // Directory Entries
          SF_HIDDEN_SECTORS, // Hidden sectors
          (flash_size / SF_SECTOR_SIZE), // Total sectors
          SF_SECTOR_SIZE, // Sector size
          SF_SECTORS_PER_CLUSTER, // Sectors per cluster
          SF_HEADS, // Heads
          SF_SECTORS_PER_TRACK);

          Metadata

          Metadata

          Assignees

          No one assigned

            Labels

            bugSomething isn't working

            Type

            No type

            Projects

            No projects

              Milestone

              No milestone

              Relationships

              None yet

              Development

              No branches or pull requests

              Issue actions

              , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
              Skip to content

              lx_nor_flash_free_physical_sectors == 0, reclaim not possible although there is space on the device #48

              Description

              @Iktek

              Dear List,
              i got an issue with LevelX 6.1.7 ( ) used in conjunction with FileX + ThreadX on an STM32H563 connected to a serial Flash via a custom driver.

              Describe the bug

              I somehow managed it to come into a situation where lx_nor_flash_free_physical_sectors == 0, which means that a write may end in an (nearly endless) loop, because the block may not be reclaimed ( which is tried until lx_nor_flash_total_block only but will continue again on next write-try ). The Flash-Structure still shows 276 obsolete sectors ( see nor_flash struct on the bottom of this page )

              I'm just wondering if this can happen because of some erroneous condition from outside of levelX which is not catched gracefully or if i caught a bug in levelX code here.

              I found out that the while loop checking if a reclaim is to be made is only existing in "lx_nor_flash_sector_write.c" @ line 114, which in my opinion would mean that it's possible to reach a lx_nor_flash_free_physical_sectors of 0 by reading sectors that are not mapped ( read routine also allocates sectors in lx_nor_flash_sector_read.c @ line 140 ) .

              If this happened sometime before the reclaim routine may walk through all the blocks trying to reclaim but will fail each time because there are no physical blocks to copy the content to. This may also be checked in advance to not block the system all the time.

              I also had a short look at the current development code if some of the issues may be fixed now, but i did not find fixes here up to now ( maybe I've overlooked something )

              To Reproduce
              Hard to reproduce.
              This may only being reproduced on a rather small serial flash where writes and reads are done randomly over a longer time reaching the end of the flash, having no physical sectors free any more. I'll continue try reproducing in the next days and update the issue when there are more clear steps to do so.

              Expected behavior
              I excpect that the levelX does not run into the situation when there are no free sectors any more before a reclaim takes place. ( except filesystem is really full and fx routines will therefore fail directly ) May this be fixed by introducing another reclaim-while-loop to the read routine, or are there sill other pitfalls?

              I also expect that the reclaim will fail when there are not enough free sectors outside of the block to reclaim (checked in lx_nor-flash_block_reclaim.c @ line 238) which then should break the reclaim loop in the write routine to not block the whole system.

              ** Impact **
              Showstopper -> Filesystem unuseable

              ** Logs and Console Output **

              On a sector write we try to reclame same erase_block all the time:

              _lx_nor_flash_sector_write: free phys: 0 sect/block: 7
              _lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
              _lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
              _lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
              _lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
              _lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
              ... // this runns nearly endless

              ** Additional Context **
              The Filesystem still shows 968 kB of free space on a 4M serial-flash.

              Contents of LEVELX nor-flash struct:

              lx_nor_flash_state ULONG 1313821263
              lx_nor_flash_total_blocks ULONG 1024
              lx_nor_flash_words_per_block ULONG 1024
              lx_nor_flash_total_physical_sectors ULONG 7168
              lx_nor_flash_physical_sectors_per_block ULONG 7
              lx_nor_flash_base_address ULONG * 0x0
              lx_nor_flash_block_free_bit_map_offset ULONG 3
              lx_nor_flash_block_bit_map_words ULONG 1
              lx_nor_flash_block_bit_map_mask ULONG 127
              lx_nor_flash_block_physical_sector_mapping_offset ULONG 4
              lx_nor_flash_block_physical_sector_offset ULONG 128
              lx_nor_flash_free_physical_sectors ULONG 0
              lx_nor_flash_mapped_physical_sectors ULONG 6892
              lx_nor_flash_obsolete_physical_sectors ULONG 276
              lx_nor_flash_minimum_erase_count ULONG 3
              lx_nor_flash_maximum_erase_count ULONG 9
              lx_nor_flash_free_block_search ULONG 0
              lx_nor_flash_found_block_search ULONG 997
              lx_nor_flash_found_sector_search ULONG 0
              lx_nor_flash_write_requests ULONG 0
              lx_nor_flash_read_requests ULONG 42
              lx_nor_flash_sector_mapping_cache_hits ULONG 22
              lx_nor_flash_sector_mapping_cache_misses ULONG 20
              lx_nor_flash_physical_block_allocates ULONG 0
              lx_nor_flash_physical_block_allocate_errors ULONG 0
              lx_nor_flash_diagnostic_system_errors ULONG 0
              lx_nor_flash_diagnostic_system_error ULONG 0
              lx_nor_flash_diagnostic_initial_format ULONG 0
              lx_nor_flash_diagnostic_erased_block ULONG 0
              lx_nor_flash_diagnostic_re_erase_block ULONG 0
              lx_nor_flash_diagnostic_sector_being_obsoleted ULONG 0
              lx_nor_flash_diagnostic_sector_obsoleted ULONG 0
              lx_nor_flash_diagnostic_mapping_invalidated ULONG 0
              lx_nor_flash_diagnostic_mapping_write_interrupted ULONG 0
              lx_nor_flash_diagnostic_sector_not_free ULONG 0
              lx_nor_flash_diagnostic_sector_data_not_free ULONG 0
              lx_nor_flash_driver_read UINT (*)(ULONG , ULONG , ULONG) 0x803208d <FxSerialFlash_Read>
              lx_nor_flash_driver_write UINT (
              )(ULONG , ULONG , ULONG) 0x80320f9 <FxSerialFlash_Write>
              lx_nor_flash_driver_block_erase UINT (
              )(ULONG, ULONG) 0x80321dd <FxSerialFlash_BlockErase>
              lx_nor_flash_driver_block_erased_verify UINT (
              )(ULONG) 0x8032165 <FxSerialFlash_BlockEraseVerify>
              lx_nor_flash_driver_system_error UINT (
              )(UINT) 0x0
              lx_nor_flash_sector_buffer ULONG * 0x20042c14 <g_fx_serial_flash+9412>
              lx_nor_flash_sector_mapping_cache_enabled UINT 1
              lx_nor_flash_sector_mapping_cache LX_NOR_SECTOR_MAPPING_CACHE_ENTRY [16] 0x200000e0 <fx_lx_nor_drivers+172>
              lx_nor_flash_extended_cache_entries UINT 0
              lx_nor_flash_extended_cache LX_NOR_FLASH_EXTENDED_CACHE_ENTRY [8] 0x200001a4 <fx_lx_nor_drivers+368>
              lx_nor_flash_extended_cache_hits ULONG 0
              lx_nor_flash_extended_cache_misses ULONG 0
              lx_nor_flash_mutex TX_MUTEX {...}
              lx_nor_flash_open_next struct LX_NOR_FLASH_STRUCT * 0x20000034 <fx_lx_nor_drivers>
              lx_nor_flash_open_previous struct LX_NOR_FLASH_STRUCT * 0x20000034 <fx_lx_nor_drivers>

              LevelX, ThreadX, FileX coming from STM32Cube_FW_H5_V1.2.0

              LX_NOR_SECTOR_SIZE (512/sizeof(ULONG))

              FX is initialzed as follows:
              #define SF_SECTOR_SIZE (LX_NOR_SECTOR_SIZE * sizeof(ULONG))
              #define SF_NUM_FATS (1)
              #define SF_DIR_ENTRIES (32)
              #define SF_HIDDEN_SECTORS (0)
              #define SF_SECTORS_PER_CLUSTER (8)
              #define SF_HEADS (1)
              #define SF_SECTORS_PER_TRACK (1)

              status = fx_media_format(&fsf->media, // nor_simulator_flash_disk pointer
              fx_stm32_levelx_nor_driver, // Driver entry
              (void*)NOR_CUSTOM_DRIVER_ID, // Device info pointer
              (UCHAR *) fsf->media_mem, // Media buffer pointer
              SF_SECTOR_SIZE, // Media buffer size
              SF_VOLUME_NAME, // Volume Name
              SF_NUM_FATS, // Number of FATs
              SF_DIR_ENTRIES, // Directory Entries
              SF_HIDDEN_SECTORS, // Hidden sectors
              (flash_size / SF_SECTOR_SIZE), // Total sectors
              SF_SECTOR_SIZE, // Sector size
              SF_SECTORS_PER_CLUSTER, // Sectors per cluster
              SF_HEADS, // Heads
              SF_SECTORS_PER_TRACK);

              Metadata

              Metadata

              Assignees

              No one assigned

                Labels

                bugSomething isn't working

                Type

                No type

                Projects

                No projects

                  Milestone

                  No milestone

                  Relationships

                  None yet

                  Development

                  No branches or pull requests

                  Issue actions

                  , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
                  Skip to content

                  lx_nor_flash_free_physical_sectors == 0, reclaim not possible although there is space on the device #48

                  Description

                  @Iktek

                  Dear List,
                  i got an issue with LevelX 6.1.7 ( ) used in conjunction with FileX + ThreadX on an STM32H563 connected to a serial Flash via a custom driver.

                  Describe the bug

                  I somehow managed it to come into a situation where lx_nor_flash_free_physical_sectors == 0, which means that a write may end in an (nearly endless) loop, because the block may not be reclaimed ( which is tried until lx_nor_flash_total_block only but will continue again on next write-try ). The Flash-Structure still shows 276 obsolete sectors ( see nor_flash struct on the bottom of this page )

                  I'm just wondering if this can happen because of some erroneous condition from outside of levelX which is not catched gracefully or if i caught a bug in levelX code here.

                  I found out that the while loop checking if a reclaim is to be made is only existing in "lx_nor_flash_sector_write.c" @ line 114, which in my opinion would mean that it's possible to reach a lx_nor_flash_free_physical_sectors of 0 by reading sectors that are not mapped ( read routine also allocates sectors in lx_nor_flash_sector_read.c @ line 140 ) .

                  If this happened sometime before the reclaim routine may walk through all the blocks trying to reclaim but will fail each time because there are no physical blocks to copy the content to. This may also be checked in advance to not block the system all the time.

                  I also had a short look at the current development code if some of the issues may be fixed now, but i did not find fixes here up to now ( maybe I've overlooked something )

                  To Reproduce
                  Hard to reproduce.
                  This may only being reproduced on a rather small serial flash where writes and reads are done randomly over a longer time reaching the end of the flash, having no physical sectors free any more. I'll continue try reproducing in the next days and update the issue when there are more clear steps to do so.

                  Expected behavior
                  I excpect that the levelX does not run into the situation when there are no free sectors any more before a reclaim takes place. ( except filesystem is really full and fx routines will therefore fail directly ) May this be fixed by introducing another reclaim-while-loop to the read routine, or are there sill other pitfalls?

                  I also expect that the reclaim will fail when there are not enough free sectors outside of the block to reclaim (checked in lx_nor-flash_block_reclaim.c @ line 238) which then should break the reclaim loop in the write routine to not block the whole system.

                  ** Impact **
                  Showstopper -> Filesystem unuseable

                  ** Logs and Console Output **

                  On a sector write we try to reclame same erase_block all the time:

                  _lx_nor_flash_sector_write: free phys: 0 sect/block: 7
                  _lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
                  _lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
                  _lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
                  _lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
                  _lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
                  ... // this runns nearly endless

                  ** Additional Context **
                  The Filesystem still shows 968 kB of free space on a 4M serial-flash.

                  Contents of LEVELX nor-flash struct:

                  lx_nor_flash_state ULONG 1313821263
                  lx_nor_flash_total_blocks ULONG 1024
                  lx_nor_flash_words_per_block ULONG 1024
                  lx_nor_flash_total_physical_sectors ULONG 7168
                  lx_nor_flash_physical_sectors_per_block ULONG 7
                  lx_nor_flash_base_address ULONG * 0x0
                  lx_nor_flash_block_free_bit_map_offset ULONG 3
                  lx_nor_flash_block_bit_map_words ULONG 1
                  lx_nor_flash_block_bit_map_mask ULONG 127
                  lx_nor_flash_block_physical_sector_mapping_offset ULONG 4
                  lx_nor_flash_block_physical_sector_offset ULONG 128
                  lx_nor_flash_free_physical_sectors ULONG 0
                  lx_nor_flash_mapped_physical_sectors ULONG 6892
                  lx_nor_flash_obsolete_physical_sectors ULONG 276
                  lx_nor_flash_minimum_erase_count ULONG 3
                  lx_nor_flash_maximum_erase_count ULONG 9
                  lx_nor_flash_free_block_search ULONG 0
                  lx_nor_flash_found_block_search ULONG 997
                  lx_nor_flash_found_sector_search ULONG 0
                  lx_nor_flash_write_requests ULONG 0
                  lx_nor_flash_read_requests ULONG 42
                  lx_nor_flash_sector_mapping_cache_hits ULONG 22
                  lx_nor_flash_sector_mapping_cache_misses ULONG 20
                  lx_nor_flash_physical_block_allocates ULONG 0
                  lx_nor_flash_physical_block_allocate_errors ULONG 0
                  lx_nor_flash_diagnostic_system_errors ULONG 0
                  lx_nor_flash_diagnostic_system_error ULONG 0
                  lx_nor_flash_diagnostic_initial_format ULONG 0
                  lx_nor_flash_diagnostic_erased_block ULONG 0
                  lx_nor_flash_diagnostic_re_erase_block ULONG 0
                  lx_nor_flash_diagnostic_sector_being_obsoleted ULONG 0
                  lx_nor_flash_diagnostic_sector_obsoleted ULONG 0
                  lx_nor_flash_diagnostic_mapping_invalidated ULONG 0
                  lx_nor_flash_diagnostic_mapping_write_interrupted ULONG 0
                  lx_nor_flash_diagnostic_sector_not_free ULONG 0
                  lx_nor_flash_diagnostic_sector_data_not_free ULONG 0
                  lx_nor_flash_driver_read UINT (*)(ULONG , ULONG , ULONG) 0x803208d <FxSerialFlash_Read>
                  lx_nor_flash_driver_write UINT (
                  )(ULONG , ULONG , ULONG) 0x80320f9 <FxSerialFlash_Write>
                  lx_nor_flash_driver_block_erase UINT (
                  )(ULONG, ULONG) 0x80321dd <FxSerialFlash_BlockErase>
                  lx_nor_flash_driver_block_erased_verify UINT (
                  )(ULONG) 0x8032165 <FxSerialFlash_BlockEraseVerify>
                  lx_nor_flash_driver_system_error UINT (
                  )(UINT) 0x0
                  lx_nor_flash_sector_buffer ULONG * 0x20042c14 <g_fx_serial_flash+9412>
                  lx_nor_flash_sector_mapping_cache_enabled UINT 1
                  lx_nor_flash_sector_mapping_cache LX_NOR_SECTOR_MAPPING_CACHE_ENTRY [16] 0x200000e0 <fx_lx_nor_drivers+172>
                  lx_nor_flash_extended_cache_entries UINT 0
                  lx_nor_flash_extended_cache LX_NOR_FLASH_EXTENDED_CACHE_ENTRY [8] 0x200001a4 <fx_lx_nor_drivers+368>
                  lx_nor_flash_extended_cache_hits ULONG 0
                  lx_nor_flash_extended_cache_misses ULONG 0
                  lx_nor_flash_mutex TX_MUTEX {...}
                  lx_nor_flash_open_next struct LX_NOR_FLASH_STRUCT * 0x20000034 <fx_lx_nor_drivers>
                  lx_nor_flash_open_previous struct LX_NOR_FLASH_STRUCT * 0x20000034 <fx_lx_nor_drivers>

                  LevelX, ThreadX, FileX coming from STM32Cube_FW_H5_V1.2.0

                  LX_NOR_SECTOR_SIZE (512/sizeof(ULONG))

                  FX is initialzed as follows:
                  #define SF_SECTOR_SIZE (LX_NOR_SECTOR_SIZE * sizeof(ULONG))
                  #define SF_NUM_FATS (1)
                  #define SF_DIR_ENTRIES (32)
                  #define SF_HIDDEN_SECTORS (0)
                  #define SF_SECTORS_PER_CLUSTER (8)
                  #define SF_HEADS (1)
                  #define SF_SECTORS_PER_TRACK (1)

                  status = fx_media_format(&fsf->media, // nor_simulator_flash_disk pointer
                  fx_stm32_levelx_nor_driver, // Driver entry
                  (void*)NOR_CUSTOM_DRIVER_ID, // Device info pointer
                  (UCHAR *) fsf->media_mem, // Media buffer pointer
                  SF_SECTOR_SIZE, // Media buffer size
                  SF_VOLUME_NAME, // Volume Name
                  SF_NUM_FATS, // Number of FATs
                  SF_DIR_ENTRIES, // Directory Entries
                  SF_HIDDEN_SECTORS, // Hidden sectors
                  (flash_size / SF_SECTOR_SIZE), // Total sectors
                  SF_SECTOR_SIZE, // Sector size
                  SF_SECTORS_PER_CLUSTER, // Sectors per cluster
                  SF_HEADS, // Heads
                  SF_SECTORS_PER_TRACK);

                  Metadata

                  Metadata

                  Assignees

                  No one assigned

                    Labels

                    bugSomething isn't working

                    Type

                    No type

                    Projects

                    No projects

                      Milestone

                      No milestone

                      Relationships

                      None yet

                      Development

                      No branches or pull requests

                      Issue actions

                      , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
                      Skip to content

                      lx_nor_flash_free_physical_sectors == 0, reclaim not possible although there is space on the device #48

                      Description

                      @Iktek

                      Dear List,
                      i got an issue with LevelX 6.1.7 ( ) used in conjunction with FileX + ThreadX on an STM32H563 connected to a serial Flash via a custom driver.

                      Describe the bug

                      I somehow managed it to come into a situation where lx_nor_flash_free_physical_sectors == 0, which means that a write may end in an (nearly endless) loop, because the block may not be reclaimed ( which is tried until lx_nor_flash_total_block only but will continue again on next write-try ). The Flash-Structure still shows 276 obsolete sectors ( see nor_flash struct on the bottom of this page )

                      I'm just wondering if this can happen because of some erroneous condition from outside of levelX which is not catched gracefully or if i caught a bug in levelX code here.

                      I found out that the while loop checking if a reclaim is to be made is only existing in "lx_nor_flash_sector_write.c" @ line 114, which in my opinion would mean that it's possible to reach a lx_nor_flash_free_physical_sectors of 0 by reading sectors that are not mapped ( read routine also allocates sectors in lx_nor_flash_sector_read.c @ line 140 ) .

                      If this happened sometime before the reclaim routine may walk through all the blocks trying to reclaim but will fail each time because there are no physical blocks to copy the content to. This may also be checked in advance to not block the system all the time.

                      I also had a short look at the current development code if some of the issues may be fixed now, but i did not find fixes here up to now ( maybe I've overlooked something )

                      To Reproduce
                      Hard to reproduce.
                      This may only being reproduced on a rather small serial flash where writes and reads are done randomly over a longer time reaching the end of the flash, having no physical sectors free any more. I'll continue try reproducing in the next days and update the issue when there are more clear steps to do so.

                      Expected behavior
                      I excpect that the levelX does not run into the situation when there are no free sectors any more before a reclaim takes place. ( except filesystem is really full and fx routines will therefore fail directly ) May this be fixed by introducing another reclaim-while-loop to the read routine, or are there sill other pitfalls?

                      I also expect that the reclaim will fail when there are not enough free sectors outside of the block to reclaim (checked in lx_nor-flash_block_reclaim.c @ line 238) which then should break the reclaim loop in the write routine to not block the whole system.

                      ** Impact **
                      Showstopper -> Filesystem unuseable

                      ** Logs and Console Output **

                      On a sector write we try to reclame same erase_block all the time:

                      _lx_nor_flash_sector_write: free phys: 0 sect/block: 7
                      _lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
                      _lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
                      _lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
                      _lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
                      _lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
                      ... // this runns nearly endless

                      ** Additional Context **
                      The Filesystem still shows 968 kB of free space on a 4M serial-flash.

                      Contents of LEVELX nor-flash struct:

                      lx_nor_flash_state ULONG 1313821263
                      lx_nor_flash_total_blocks ULONG 1024
                      lx_nor_flash_words_per_block ULONG 1024
                      lx_nor_flash_total_physical_sectors ULONG 7168
                      lx_nor_flash_physical_sectors_per_block ULONG 7
                      lx_nor_flash_base_address ULONG * 0x0
                      lx_nor_flash_block_free_bit_map_offset ULONG 3
                      lx_nor_flash_block_bit_map_words ULONG 1
                      lx_nor_flash_block_bit_map_mask ULONG 127
                      lx_nor_flash_block_physical_sector_mapping_offset ULONG 4
                      lx_nor_flash_block_physical_sector_offset ULONG 128
                      lx_nor_flash_free_physical_sectors ULONG 0
                      lx_nor_flash_mapped_physical_sectors ULONG 6892
                      lx_nor_flash_obsolete_physical_sectors ULONG 276
                      lx_nor_flash_minimum_erase_count ULONG 3
                      lx_nor_flash_maximum_erase_count ULONG 9
                      lx_nor_flash_free_block_search ULONG 0
                      lx_nor_flash_found_block_search ULONG 997
                      lx_nor_flash_found_sector_search ULONG 0
                      lx_nor_flash_write_requests ULONG 0
                      lx_nor_flash_read_requests ULONG 42
                      lx_nor_flash_sector_mapping_cache_hits ULONG 22
                      lx_nor_flash_sector_mapping_cache_misses ULONG 20
                      lx_nor_flash_physical_block_allocates ULONG 0
                      lx_nor_flash_physical_block_allocate_errors ULONG 0
                      lx_nor_flash_diagnostic_system_errors ULONG 0
                      lx_nor_flash_diagnostic_system_error ULONG 0
                      lx_nor_flash_diagnostic_initial_format ULONG 0
                      lx_nor_flash_diagnostic_erased_block ULONG 0
                      lx_nor_flash_diagnostic_re_erase_block ULONG 0
                      lx_nor_flash_diagnostic_sector_being_obsoleted ULONG 0
                      lx_nor_flash_diagnostic_sector_obsoleted ULONG 0
                      lx_nor_flash_diagnostic_mapping_invalidated ULONG 0
                      lx_nor_flash_diagnostic_mapping_write_interrupted ULONG 0
                      lx_nor_flash_diagnostic_sector_not_free ULONG 0
                      lx_nor_flash_diagnostic_sector_data_not_free ULONG 0
                      lx_nor_flash_driver_read UINT (*)(ULONG , ULONG , ULONG) 0x803208d <FxSerialFlash_Read>
                      lx_nor_flash_driver_write UINT (
                      )(ULONG , ULONG , ULONG) 0x80320f9 <FxSerialFlash_Write>
                      lx_nor_flash_driver_block_erase UINT (
                      )(ULONG, ULONG) 0x80321dd <FxSerialFlash_BlockErase>
                      lx_nor_flash_driver_block_erased_verify UINT (
                      )(ULONG) 0x8032165 <FxSerialFlash_BlockEraseVerify>
                      lx_nor_flash_driver_system_error UINT (
                      )(UINT) 0x0
                      lx_nor_flash_sector_buffer ULONG * 0x20042c14 <g_fx_serial_flash+9412>
                      lx_nor_flash_sector_mapping_cache_enabled UINT 1
                      lx_nor_flash_sector_mapping_cache LX_NOR_SECTOR_MAPPING_CACHE_ENTRY [16] 0x200000e0 <fx_lx_nor_drivers+172>
                      lx_nor_flash_extended_cache_entries UINT 0
                      lx_nor_flash_extended_cache LX_NOR_FLASH_EXTENDED_CACHE_ENTRY [8] 0x200001a4 <fx_lx_nor_drivers+368>
                      lx_nor_flash_extended_cache_hits ULONG 0
                      lx_nor_flash_extended_cache_misses ULONG 0
                      lx_nor_flash_mutex TX_MUTEX {...}
                      lx_nor_flash_open_next struct LX_NOR_FLASH_STRUCT * 0x20000034 <fx_lx_nor_drivers>
                      lx_nor_flash_open_previous struct LX_NOR_FLASH_STRUCT * 0x20000034 <fx_lx_nor_drivers>

                      LevelX, ThreadX, FileX coming from STM32Cube_FW_H5_V1.2.0

                      LX_NOR_SECTOR_SIZE (512/sizeof(ULONG))

                      FX is initialzed as follows:
                      #define SF_SECTOR_SIZE (LX_NOR_SECTOR_SIZE * sizeof(ULONG))
                      #define SF_NUM_FATS (1)
                      #define SF_DIR_ENTRIES (32)
                      #define SF_HIDDEN_SECTORS (0)
                      #define SF_SECTORS_PER_CLUSTER (8)
                      #define SF_HEADS (1)
                      #define SF_SECTORS_PER_TRACK (1)

                      status = fx_media_format(&fsf->media, // nor_simulator_flash_disk pointer
                      fx_stm32_levelx_nor_driver, // Driver entry
                      (void*)NOR_CUSTOM_DRIVER_ID, // Device info pointer
                      (UCHAR *) fsf->media_mem, // Media buffer pointer
                      SF_SECTOR_SIZE, // Media buffer size
                      SF_VOLUME_NAME, // Volume Name
                      SF_NUM_FATS, // Number of FATs
                      SF_DIR_ENTRIES, // Directory Entries
                      SF_HIDDEN_SECTORS, // Hidden sectors
                      (flash_size / SF_SECTOR_SIZE), // Total sectors
                      SF_SECTOR_SIZE, // Sector size
                      SF_SECTORS_PER_CLUSTER, // Sectors per cluster
                      SF_HEADS, // Heads
                      SF_SECTORS_PER_TRACK);

                      Metadata

                      Metadata

                      Assignees

                      No one assigned

                        Labels

                        bugSomething isn't working

                        Type

                        No type

                        Projects

                        No projects

                          Milestone

                          No milestone

                          Relationships

                          None yet

                          Development

                          No branches or pull requests

                          Issue actions

                          , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
                          Skip to content

                          lx_nor_flash_free_physical_sectors == 0, reclaim not possible although there is space on the device #48

                          Description

                          @Iktek

                          Dear List,
                          i got an issue with LevelX 6.1.7 ( ) used in conjunction with FileX + ThreadX on an STM32H563 connected to a serial Flash via a custom driver.

                          Describe the bug

                          I somehow managed it to come into a situation where lx_nor_flash_free_physical_sectors == 0, which means that a write may end in an (nearly endless) loop, because the block may not be reclaimed ( which is tried until lx_nor_flash_total_block only but will continue again on next write-try ). The Flash-Structure still shows 276 obsolete sectors ( see nor_flash struct on the bottom of this page )

                          I'm just wondering if this can happen because of some erroneous condition from outside of levelX which is not catched gracefully or if i caught a bug in levelX code here.

                          I found out that the while loop checking if a reclaim is to be made is only existing in "lx_nor_flash_sector_write.c" @ line 114, which in my opinion would mean that it's possible to reach a lx_nor_flash_free_physical_sectors of 0 by reading sectors that are not mapped ( read routine also allocates sectors in lx_nor_flash_sector_read.c @ line 140 ) .

                          If this happened sometime before the reclaim routine may walk through all the blocks trying to reclaim but will fail each time because there are no physical blocks to copy the content to. This may also be checked in advance to not block the system all the time.

                          I also had a short look at the current development code if some of the issues may be fixed now, but i did not find fixes here up to now ( maybe I've overlooked something )

                          To Reproduce
                          Hard to reproduce.
                          This may only being reproduced on a rather small serial flash where writes and reads are done randomly over a longer time reaching the end of the flash, having no physical sectors free any more. I'll continue try reproducing in the next days and update the issue when there are more clear steps to do so.

                          Expected behavior
                          I excpect that the levelX does not run into the situation when there are no free sectors any more before a reclaim takes place. ( except filesystem is really full and fx routines will therefore fail directly ) May this be fixed by introducing another reclaim-while-loop to the read routine, or are there sill other pitfalls?

                          I also expect that the reclaim will fail when there are not enough free sectors outside of the block to reclaim (checked in lx_nor-flash_block_reclaim.c @ line 238) which then should break the reclaim loop in the write routine to not block the whole system.

                          ** Impact **
                          Showstopper -> Filesystem unuseable

                          ** Logs and Console Output **

                          On a sector write we try to reclame same erase_block all the time:

                          _lx_nor_flash_sector_write: free phys: 0 sect/block: 7
                          _lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
                          _lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
                          _lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
                          _lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
                          _lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
                          ... // this runns nearly endless

                          ** Additional Context **
                          The Filesystem still shows 968 kB of free space on a 4M serial-flash.

                          Contents of LEVELX nor-flash struct:

                          lx_nor_flash_state ULONG 1313821263
                          lx_nor_flash_total_blocks ULONG 1024
                          lx_nor_flash_words_per_block ULONG 1024
                          lx_nor_flash_total_physical_sectors ULONG 7168
                          lx_nor_flash_physical_sectors_per_block ULONG 7
                          lx_nor_flash_base_address ULONG * 0x0
                          lx_nor_flash_block_free_bit_map_offset ULONG 3
                          lx_nor_flash_block_bit_map_words ULONG 1
                          lx_nor_flash_block_bit_map_mask ULONG 127
                          lx_nor_flash_block_physical_sector_mapping_offset ULONG 4
                          lx_nor_flash_block_physical_sector_offset ULONG 128
                          lx_nor_flash_free_physical_sectors ULONG 0
                          lx_nor_flash_mapped_physical_sectors ULONG 6892
                          lx_nor_flash_obsolete_physical_sectors ULONG 276
                          lx_nor_flash_minimum_erase_count ULONG 3
                          lx_nor_flash_maximum_erase_count ULONG 9
                          lx_nor_flash_free_block_search ULONG 0
                          lx_nor_flash_found_block_search ULONG 997
                          lx_nor_flash_found_sector_search ULONG 0
                          lx_nor_flash_write_requests ULONG 0
                          lx_nor_flash_read_requests ULONG 42
                          lx_nor_flash_sector_mapping_cache_hits ULONG 22
                          lx_nor_flash_sector_mapping_cache_misses ULONG 20
                          lx_nor_flash_physical_block_allocates ULONG 0
                          lx_nor_flash_physical_block_allocate_errors ULONG 0
                          lx_nor_flash_diagnostic_system_errors ULONG 0
                          lx_nor_flash_diagnostic_system_error ULONG 0
                          lx_nor_flash_diagnostic_initial_format ULONG 0
                          lx_nor_flash_diagnostic_erased_block ULONG 0
                          lx_nor_flash_diagnostic_re_erase_block ULONG 0
                          lx_nor_flash_diagnostic_sector_being_obsoleted ULONG 0
                          lx_nor_flash_diagnostic_sector_obsoleted ULONG 0
                          lx_nor_flash_diagnostic_mapping_invalidated ULONG 0
                          lx_nor_flash_diagnostic_mapping_write_interrupted ULONG 0
                          lx_nor_flash_diagnostic_sector_not_free ULONG 0
                          lx_nor_flash_diagnostic_sector_data_not_free ULONG 0
                          lx_nor_flash_driver_read UINT (*)(ULONG , ULONG , ULONG) 0x803208d <FxSerialFlash_Read>
                          lx_nor_flash_driver_write UINT (
                          )(ULONG , ULONG , ULONG) 0x80320f9 <FxSerialFlash_Write>
                          lx_nor_flash_driver_block_erase UINT (
                          )(ULONG, ULONG) 0x80321dd <FxSerialFlash_BlockErase>
                          lx_nor_flash_driver_block_erased_verify UINT (
                          )(ULONG) 0x8032165 <FxSerialFlash_BlockEraseVerify>
                          lx_nor_flash_driver_system_error UINT (
                          )(UINT) 0x0
                          lx_nor_flash_sector_buffer ULONG * 0x20042c14 <g_fx_serial_flash+9412>
                          lx_nor_flash_sector_mapping_cache_enabled UINT 1
                          lx_nor_flash_sector_mapping_cache LX_NOR_SECTOR_MAPPING_CACHE_ENTRY [16] 0x200000e0 <fx_lx_nor_drivers+172>
                          lx_nor_flash_extended_cache_entries UINT 0
                          lx_nor_flash_extended_cache LX_NOR_FLASH_EXTENDED_CACHE_ENTRY [8] 0x200001a4 <fx_lx_nor_drivers+368>
                          lx_nor_flash_extended_cache_hits ULONG 0
                          lx_nor_flash_extended_cache_misses ULONG 0
                          lx_nor_flash_mutex TX_MUTEX {...}
                          lx_nor_flash_open_next struct LX_NOR_FLASH_STRUCT * 0x20000034 <fx_lx_nor_drivers>
                          lx_nor_flash_open_previous struct LX_NOR_FLASH_STRUCT * 0x20000034 <fx_lx_nor_drivers>

                          LevelX, ThreadX, FileX coming from STM32Cube_FW_H5_V1.2.0

                          LX_NOR_SECTOR_SIZE (512/sizeof(ULONG))

                          FX is initialzed as follows:
                          #define SF_SECTOR_SIZE (LX_NOR_SECTOR_SIZE * sizeof(ULONG))
                          #define SF_NUM_FATS (1)
                          #define SF_DIR_ENTRIES (32)
                          #define SF_HIDDEN_SECTORS (0)
                          #define SF_SECTORS_PER_CLUSTER (8)
                          #define SF_HEADS (1)
                          #define SF_SECTORS_PER_TRACK (1)

                          status = fx_media_format(&fsf->media, // nor_simulator_flash_disk pointer
                          fx_stm32_levelx_nor_driver, // Driver entry
                          (void*)NOR_CUSTOM_DRIVER_ID, // Device info pointer
                          (UCHAR *) fsf->media_mem, // Media buffer pointer
                          SF_SECTOR_SIZE, // Media buffer size
                          SF_VOLUME_NAME, // Volume Name
                          SF_NUM_FATS, // Number of FATs
                          SF_DIR_ENTRIES, // Directory Entries
                          SF_HIDDEN_SECTORS, // Hidden sectors
                          (flash_size / SF_SECTOR_SIZE), // Total sectors
                          SF_SECTOR_SIZE, // Sector size
                          SF_SECTORS_PER_CLUSTER, // Sectors per cluster
                          SF_HEADS, // Heads
                          SF_SECTORS_PER_TRACK);

                          Metadata

                          Metadata

                          Assignees

                          No one assigned

                            Labels

                            bugSomething isn't working

                            Type

                            No type

                            Projects

                            No projects

                              Milestone

                              No milestone

                              Relationships

                              None yet

                              Development

                              No branches or pull requests

                              Issue actions

                              , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
                              Skip to content

                              lx_nor_flash_free_physical_sectors == 0, reclaim not possible although there is space on the device #48

                              Description

                              @Iktek

                              Dear List,
                              i got an issue with LevelX 6.1.7 ( ) used in conjunction with FileX + ThreadX on an STM32H563 connected to a serial Flash via a custom driver.

                              Describe the bug

                              I somehow managed it to come into a situation where lx_nor_flash_free_physical_sectors == 0, which means that a write may end in an (nearly endless) loop, because the block may not be reclaimed ( which is tried until lx_nor_flash_total_block only but will continue again on next write-try ). The Flash-Structure still shows 276 obsolete sectors ( see nor_flash struct on the bottom of this page )

                              I'm just wondering if this can happen because of some erroneous condition from outside of levelX which is not catched gracefully or if i caught a bug in levelX code here.

                              I found out that the while loop checking if a reclaim is to be made is only existing in "lx_nor_flash_sector_write.c" @ line 114, which in my opinion would mean that it's possible to reach a lx_nor_flash_free_physical_sectors of 0 by reading sectors that are not mapped ( read routine also allocates sectors in lx_nor_flash_sector_read.c @ line 140 ) .

                              If this happened sometime before the reclaim routine may walk through all the blocks trying to reclaim but will fail each time because there are no physical blocks to copy the content to. This may also be checked in advance to not block the system all the time.

                              I also had a short look at the current development code if some of the issues may be fixed now, but i did not find fixes here up to now ( maybe I've overlooked something )

                              To Reproduce
                              Hard to reproduce.
                              This may only being reproduced on a rather small serial flash where writes and reads are done randomly over a longer time reaching the end of the flash, having no physical sectors free any more. I'll continue try reproducing in the next days and update the issue when there are more clear steps to do so.

                              Expected behavior
                              I excpect that the levelX does not run into the situation when there are no free sectors any more before a reclaim takes place. ( except filesystem is really full and fx routines will therefore fail directly ) May this be fixed by introducing another reclaim-while-loop to the read routine, or are there sill other pitfalls?

                              I also expect that the reclaim will fail when there are not enough free sectors outside of the block to reclaim (checked in lx_nor-flash_block_reclaim.c @ line 238) which then should break the reclaim loop in the write routine to not block the whole system.

                              ** Impact **
                              Showstopper -> Filesystem unuseable

                              ** Logs and Console Output **

                              On a sector write we try to reclame same erase_block all the time:

                              _lx_nor_flash_sector_write: free phys: 0 sect/block: 7
                              _lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
                              _lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
                              _lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
                              _lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
                              _lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
                              ... // this runns nearly endless

                              ** Additional Context **
                              The Filesystem still shows 968 kB of free space on a 4M serial-flash.

                              Contents of LEVELX nor-flash struct:

                              lx_nor_flash_state ULONG 1313821263
                              lx_nor_flash_total_blocks ULONG 1024
                              lx_nor_flash_words_per_block ULONG 1024
                              lx_nor_flash_total_physical_sectors ULONG 7168
                              lx_nor_flash_physical_sectors_per_block ULONG 7
                              lx_nor_flash_base_address ULONG * 0x0
                              lx_nor_flash_block_free_bit_map_offset ULONG 3
                              lx_nor_flash_block_bit_map_words ULONG 1
                              lx_nor_flash_block_bit_map_mask ULONG 127
                              lx_nor_flash_block_physical_sector_mapping_offset ULONG 4
                              lx_nor_flash_block_physical_sector_offset ULONG 128
                              lx_nor_flash_free_physical_sectors ULONG 0
                              lx_nor_flash_mapped_physical_sectors ULONG 6892
                              lx_nor_flash_obsolete_physical_sectors ULONG 276
                              lx_nor_flash_minimum_erase_count ULONG 3
                              lx_nor_flash_maximum_erase_count ULONG 9
                              lx_nor_flash_free_block_search ULONG 0
                              lx_nor_flash_found_block_search ULONG 997
                              lx_nor_flash_found_sector_search ULONG 0
                              lx_nor_flash_write_requests ULONG 0
                              lx_nor_flash_read_requests ULONG 42
                              lx_nor_flash_sector_mapping_cache_hits ULONG 22
                              lx_nor_flash_sector_mapping_cache_misses ULONG 20
                              lx_nor_flash_physical_block_allocates ULONG 0
                              lx_nor_flash_physical_block_allocate_errors ULONG 0
                              lx_nor_flash_diagnostic_system_errors ULONG 0
                              lx_nor_flash_diagnostic_system_error ULONG 0
                              lx_nor_flash_diagnostic_initial_format ULONG 0
                              lx_nor_flash_diagnostic_erased_block ULONG 0
                              lx_nor_flash_diagnostic_re_erase_block ULONG 0
                              lx_nor_flash_diagnostic_sector_being_obsoleted ULONG 0
                              lx_nor_flash_diagnostic_sector_obsoleted ULONG 0
                              lx_nor_flash_diagnostic_mapping_invalidated ULONG 0
                              lx_nor_flash_diagnostic_mapping_write_interrupted ULONG 0
                              lx_nor_flash_diagnostic_sector_not_free ULONG 0
                              lx_nor_flash_diagnostic_sector_data_not_free ULONG 0
                              lx_nor_flash_driver_read UINT (*)(ULONG , ULONG , ULONG) 0x803208d <FxSerialFlash_Read>
                              lx_nor_flash_driver_write UINT (
                              )(ULONG , ULONG , ULONG) 0x80320f9 <FxSerialFlash_Write>
                              lx_nor_flash_driver_block_erase UINT (
                              )(ULONG, ULONG) 0x80321dd <FxSerialFlash_BlockErase>
                              lx_nor_flash_driver_block_erased_verify UINT (
                              )(ULONG) 0x8032165 <FxSerialFlash_BlockEraseVerify>
                              lx_nor_flash_driver_system_error UINT (
                              )(UINT) 0x0
                              lx_nor_flash_sector_buffer ULONG * 0x20042c14 <g_fx_serial_flash+9412>
                              lx_nor_flash_sector_mapping_cache_enabled UINT 1
                              lx_nor_flash_sector_mapping_cache LX_NOR_SECTOR_MAPPING_CACHE_ENTRY [16] 0x200000e0 <fx_lx_nor_drivers+172>
                              lx_nor_flash_extended_cache_entries UINT 0
                              lx_nor_flash_extended_cache LX_NOR_FLASH_EXTENDED_CACHE_ENTRY [8] 0x200001a4 <fx_lx_nor_drivers+368>
                              lx_nor_flash_extended_cache_hits ULONG 0
                              lx_nor_flash_extended_cache_misses ULONG 0
                              lx_nor_flash_mutex TX_MUTEX {...}
                              lx_nor_flash_open_next struct LX_NOR_FLASH_STRUCT * 0x20000034 <fx_lx_nor_drivers>
                              lx_nor_flash_open_previous struct LX_NOR_FLASH_STRUCT * 0x20000034 <fx_lx_nor_drivers>

                              LevelX, ThreadX, FileX coming from STM32Cube_FW_H5_V1.2.0

                              LX_NOR_SECTOR_SIZE (512/sizeof(ULONG))

                              FX is initialzed as follows:
                              #define SF_SECTOR_SIZE (LX_NOR_SECTOR_SIZE * sizeof(ULONG))
                              #define SF_NUM_FATS (1)
                              #define SF_DIR_ENTRIES (32)
                              #define SF_HIDDEN_SECTORS (0)
                              #define SF_SECTORS_PER_CLUSTER (8)
                              #define SF_HEADS (1)
                              #define SF_SECTORS_PER_TRACK (1)

                              status = fx_media_format(&fsf->media, // nor_simulator_flash_disk pointer
                              fx_stm32_levelx_nor_driver, // Driver entry
                              (void*)NOR_CUSTOM_DRIVER_ID, // Device info pointer
                              (UCHAR *) fsf->media_mem, // Media buffer pointer
                              SF_SECTOR_SIZE, // Media buffer size
                              SF_VOLUME_NAME, // Volume Name
                              SF_NUM_FATS, // Number of FATs
                              SF_DIR_ENTRIES, // Directory Entries
                              SF_HIDDEN_SECTORS, // Hidden sectors
                              (flash_size / SF_SECTOR_SIZE), // Total sectors
                              SF_SECTOR_SIZE, // Sector size
                              SF_SECTORS_PER_CLUSTER, // Sectors per cluster
                              SF_HEADS, // Heads
                              SF_SECTORS_PER_TRACK);

                              Metadata

                              Metadata

                              Assignees

                              No one assigned

                                Labels

                                bugSomething isn't working

                                Type

                                No type

                                Projects

                                No projects

                                  Milestone

                                  No milestone

                                  Relationships

                                  None yet

                                  Development

                                  No branches or pull requests

                                  Issue actions