-
-
Notifications
You must be signed in to change notification settings - Fork 345
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix/spiffs format #1313
Fix/spiffs format #1313
Conversation
@jonnykl How the issue that you are fixing can be reproduced? |
As you can see the "available" flash memory will be formatted and everything works. But when you power off the board and reconnect it nothing works anymore. It sends random bytes and also other code do not execute properly.
I'm using a ESP-01 with 8Mbit flash memory. |
@slaff Why did you close this PR? The bug is still not fixed yet .. |
Sorry, I will re-open it and try to test it till the end of the week. |
@@ -64,10 +64,10 @@ bool spiffs_format_internal(spiffs_config *cfg) | |||
sect_first = cfg->phys_addr; | |||
sect_first = flashmem_get_sector_of_address(sect_first); | |||
sect_last = cfg->phys_addr + cfg->phys_size; | |||
sect_last = flashmem_get_sector_of_address(sect_last); | |||
sect_last = flashmem_get_sector_of_address(sect_last) - 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the correct code would be:
sect_last = cfg->phys_addr + cfg->phys_size - 1;
sect_last = flashmem_get_sector_of_address(sect_last);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The first value assigned to sect_last
is the physical address of the first byte which does not belong the the SpifFS. If cfg->phys_addr + cfg->phys_size
is a multiple of INTERNAL_FLASH_SECTOR_SIZE
(which is 4096), then it would make no difference but it would be logically wrong.
Assume phys_addr+phys_size
would not be a multiple of INTERNAL_FLASH_SECTOR_SIZE
(e.g. INTERNAL_FLASH_SECTOR_SIZE/2
). Then you subtract one byte from sect_last
- now sect_last
points to the last byte which belongs to SpifFS. Now flashmem_get_sector_of_address()
calculates the sector as follows: address / INTERNAL_FLASH_SECTOR_SIZE
. The resulting sector is the same as if you did not subtract 1 before (because of the division of integers). In this case you would override/delete the data from the address cfg->phys_addr + cfg->phys_size
to the end of the sector.
If you subtract one from sect_last
after the "second step" (calculating the sector) you will not override other data.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like good discussions especially when they lead to results. I still think that Mike is right here. I will post below my reasoning and you can follow up with your arguments.
Let's have the following setup:
Sector size: 5
Start address: 4
Size: 2
Mike's calculation:
sect_last = cfg->phys_addr + cfg->phys_size - 1; // 4 + 2 - 1 = 5 <-- last byte inclusive is the 5th one
sect_last = flashmem_get_sector_of_address(sect_last); // 5/5 = 1 <-- the sector for the 5th byte is 1.
Which means that sector 0 and sector 1 have to be erased. Which IMHO is correct.
Now your solution suggest the following
sect_last = cfg->phys_addr + cfg->phys_size; // 4 + 2 = 6
sect_last = flashmem_get_sector_of_address(sect_last) - 1; // (6/5) - 1 = 1 -1 = 0 <-- the sector that has to be erased is 0
Which means that only sector 0 has to be erased. But that cannot be right because byte 5 has to be written to sector 1, which will not be erased here. Am I missing something here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No you are not missing something. But I think it's better to not use a block instead of deleting other data (here bytes 6,7,8,9). Another thing I didn't consider is the same aspect but for cfg->phys_addr
(so also bytes 0,1,2,3 are deleted). In your example should no block be erased, because both blocks may contain other data which may not be erased. I think it would be reasonable to check this in overrides.c
:
#ifdef RBOOT_SPIFFS_0
#if (((RBOOT_SPIFFS_0) % (INTERNAL_FLASH_SECTOR_SIZE)) != 0)
#error "RBOOT_SPIFFS_0 has to be a multiple of INTERNAL_FLASH_SECTOR_SIZE" // or warning
#endif
#endif
#ifdef RBOOT_SPIFFS_1
#if (((RBOOT_SPIFFS_1) % (INTERNAL_FLASH_SECTOR_SIZE)) != 0)
#error "RBOOT_SPIFFS_0 has to be a multiple of INTERNAL_FLASH_SECTOR_SIZE" // or warning
#endif
#endif
#if (((SPIFF_SIZE) % (INTERNAL_FLASH_SECTOR_SIZE)) != 0)
#error "SPIFF_SIZE has to be a multiple of INTERNAL_FLASH_SECTOR_SIZE" // or warning
#endif
When the developer tries using values which will delete other data it prevents him from doing this or just get warned and does not have to search for the problem.
@jonnykl Have you added |
Ok, I analyzed the problem a bit and here is what I can say: There is a problem with the automatic formatting, but this PR does not suggest proper fix. The problem originates in the overrides.c and the function below. /*
* rBoot uses different spiffs organization and we need to override this method
* during application compile time in order to make automatic
* mounting with `spiffs_mount()` work as expected.
*/
spiffs_config spiffs_get_storage_config()
{
spiffs_config cfg = {0};
#ifdef RBOOT_SPIFFS_0
cfg.phys_addr = RBOOT_SPIFFS_0;
#elif RBOOT_SPIFFS_1
cfg.phys_addr = RBOOT_SPIFFS_1;
#else
#error "Define either RBOOT_SPIFFS_0 or RBOOT_SPIFFS_1"
#endif
cfg.phys_size = SPIFF_SIZE;
cfg.phys_erase_block = INTERNAL_FLASH_SECTOR_SIZE; // according to datasheet
cfg.log_block_size = INTERNAL_FLASH_SECTOR_SIZE * 2; // Important to make large
cfg.log_page_size = LOG_PAGE_SIZE; // as we said
return cfg;
} In it the A better solution would be to change the cfg.phys_size to be calculated as: cfg.phys_size = INTERNAL_FLASH_SIZE - ( ( u32_t )cfg.phys_addr); In that case the SPIFFS will start from the desired location and will use all available FLASH memory minus the system four sectors and minus the start offset. That code can be improved further. Instead of auto-creating a SPIFF that takes all available and allowed FLASH the SPIFF_SIZE can be used to provide a sane default for the SpifFS length. So we can have something like this: u32_t maxAllowedEndAddress = INTERNAL_FLASH_SIZE;
u32_t requestedEndAddress = cfg.phys_addr + SPIFF_SIZE;
if(requestedEndAddress > maxAllowedEndAddress) {
debug_w("The requested SPIFFS size is too big.");
cfg.phys_size = maxAllowedEndAddress - ( ( u32_t )cfg.phys_addr);
}
else {
cfg.phys_size = SPIFF_SIZE;
} Any comments? |
Without checking your fix (i will do it later and comment it) there is still a logic error in |
I might be wrong but for me the formatting itself is correct. The total and the percentage calculations are wrong if they have to represent the percentage after an erase and not before that. Zero size
I agree, zero sizes are special case that should be handled better. The following needs to be added:
For the total and percentage fixes:Further the calculation of the total is not exactly correct. It should be:
And the percentage calculation needs updating:
We can test if the changes will work using the following test setup: Pre: Sector size is 5 bytes (for easier calculation) Use-case 1Will return false due to invalid start address Use-case 2Will return false due to invalid size Use-case 3Start address 5, Size 13 The total calculation:
Gives us 3 - 1 + 1 = 3. Total of 3 sectors have to be erased. Sectors with indexes 1, 2 and 3. Which is correct. For the first iteration the percentage will be calculated using:
1 * 100/ 3 = 33 %. Which is correct. |
What about size=1 ? |
At the time of creation of this PR I did not use rBoot. So I also did not add
No the calculation of the total was correct. I think the name of the variable
This makes sense -> you would only then have to add 1 if
That's correct. This also indicates that there is bug at the formatting. Now (with
This seems correct but then you would erase And what about size=n*sector_size (n is a natural number including zero)?
That's not correct because we set |
The code erased one sector of the memory too many