Hi Stefan,
This error does not occur on arm platform as no error reports when flush in case of no write is called in these platforms. You have found the root cause of the error on your platform. The its_flash_fs_ops_t’ flush API does not define the
case of empty data to flush as an error. So I am not sure whether the flash driver should support that or not. But what the ITS file system layer can do is avoid flushing in this case. The data block should be switched to the scratch data block even if the
calculated remaining data length is 0 after deletion. The reason is that the asset data is not actually erased from the data block yet. It is expected to be erased in its_mblock_erase_scratch_blocks when calling its_flash_fs_mblock_meta_update_finalize later.
An easy fix should be checking the move data into scratch data block. If no data is moved, the skip the flush.
I created
this patch for the fix. Would you like help review and test it on your board? Thanks.
Regards,
Sherry Zhang
From: Stefan Krug via TF-M <tf-m@lists.trustedfirmware.org>
Sent: Wednesday, November 16, 2022 10:55 PM
To: TF-M mailing list <tf-m@lists.trustedfirmware.org>
Subject: [TF-M] Deleting last object in a data block in ITS filesystem
Hello!
Seemingly, there is an issue with file deletion in ITS. I would think it is not
possible to delete the last object in a data block (so that the data
block becomes empty).
It’s easiest to reproduce with using large objects (because then the number of
involved objects is small), but would also happen with multiple
smaller objects:
With the following flash configuration:
ITS_MAX_ASSET_SIZE=0x1000
TFM_HAL_ITS_SECTORS_PER_BLOCK=1
TFM_HAL_ITS_FLASH_AREA_SIZE=0x20000
TFM_HAL_ITS_PROGRAM_UNIT=0x100
ITS_FLASH_NAND_BUF_SIZE=1*0x1000
In a sequence of writing and deleting an object like:
const uint8_t big_file[ITS_MAX_ASSET_SIZE] = {0};
status = psa_its_set(uid, sizeof(big_file), big_file, flags);
status = psa_its_remove(uid);
deleting the file fails with the status of PSA_ERROR_GENERIC_ERROR.
What I think happens is:
Due to the size of the file, it does not fit in the metadata block, and is put a
second (data only) block. The object is written there as expected.
When the data block is deleted later, an attempt is being made to compact it
with its_flash_fs_dblock_compact_block(). However, there is no data to keep
before the object to be deleted and also no data to keep after it, this block
will become empty, so no call to its_flash_fs_block_to_block_move() happens,
which causes no call to fs_ctx->ops->write() happens. Now the flash driver in
my case is a buffering its_flash_nand.c. In the write() call it would associate
a buffer for the physical sector to write. But since there is no write() call
the subsequent fs_ctx->ops->flush() fails as it has no buffer to flush out.
I believe no compaction of the block should even be attempted - it is known
that the block will be empty beforehand. Perhaps similar to
https://review.trustedfirmware.org/c/TF-M/trusted-firmware-m/+/17578, this is
yet another reason to skip compacting of the block?
It would be very much appreciated if one of the experts could confirm this
suspicious behavior or point out a mistake I am making.
Thank you very much, best regards
Stefan Krug