littlefs-project / littlefs

A little fail-safe filesystem designed for microcontrollers
BSD 3-Clause "New" or "Revised" License
5.25k stars 803 forks source link

USB MTP responder: Maintaining file-system-unique, stable IDs for LFS file system objects #781

Open hattesen opened 1 year ago

hattesen commented 1 year ago

I will shortly be add MTP (Media Transfer Protocol) USB-Device (MTP responder) support to TinyUSB to allow a USB Host to transparently access (read/write) LittleFS as a remotely mounted file system, and am looking for some design assistance of how to achieve this integration most efficiently and securely with LittleFS.

The MTP interface which is widely used to interface Digital Cameras and Android Smart Phones, tablets and MP3 players with host PCs allows a stable, wear-leveling file system to be installed in the internal Flash on an embedded device such as the Raspberry Pi Pico, and provide a much safer file-level interface with a USB Host compared to accessing a FAT file system exposed as a USB Mass Storage Device, with all the synchronization, integrity and Flash wear issues that it entails. While wear leveling could be added to a FAT file system by introducing a wear-leveling layer between the raw NOR/NAND Flash and the FAT file system (example: ESPRESSIF Wear Levelling API) this does not solve the other problems of using a block-level interface file system that has not been designed with Flash storage in mind.

MTP Object Handles

However, MTP requires unique and session-stable 32-bit IDs (Object Handles) to be maintained for each file system object (i.e. files and directories). I am looking into ways to obtain/generate such unique file system object IDs when integrating to a LittleFS file system, while maintaining the LittleFS design principle of bounded memory usage.

Generating MTP Object Handles

Existing MTP responder implementations, e.g. MTP_Teensy, have chosen to scan the file system when an MTP initiator mounts the it and store ID mappings in an index file in the file system root. While this is compatible with any (writable) file system, it is neither elegant, nor very efficient, and causes writes to Flash even when just reading the mounted file system.

Maintaining the ID to file system object mappings in RAM, would be efficient, but neither scalable nor memory bounded.

My current plan for generating MTP Object ID is:

Questions

After reviewing the LittleFS DESIGN and SPEC documents, I am uncertain of the uniqueness and stability of the LFS_TYPE_NAME.tag.id property:

Media Transfer Protocol specification

Excerpts from the Media Transfer Protocol specification, version 1.1, April 6th, 2011:

3.4 Object Handles Object handles are 32-bit identifiers that provide a device- and session-unique consistent reference to a logical object on a device. All handles are represented using the UINT32 simple type. There is no special meaning attached to the value of object handles; they may be chosen in any manner that facilitates device implementation.

Object handles are used in MTP transactions to reference a logical object on the device, but do not necessarily reference actual data constructs on the device. As identified in section 1.3, objects may be exposed through MTP that will be created on-demand. Object handles are only persistent within an MTP session; once a session has been re-opened, all previous values shall be assumed to be invalid, and the contents of the Responder must be re-enumerated if object handles are needed.

The values "0xFFFFFFFF" and "0x00000000" have special meaning and shall not be assigned to objects. The meanings of those values are context-specific.

3.4.1 Assigning Object Handles Object Handles are assigned by the responder. They must be globally unique across all storages on the device.

Object Handles are only defined within an open session. If the Initiator has not yet opened a session, object handles do not have any meaning and cannot be used. When a session is closed, either intentionally by the initiator or as a result of an error or USB interruption, all Object Handles are invalidated and must be re-acquired by the Initiator. Object Handles do not persist between sessions.

If an object is deleted in a session, the Responder shall not re-use the deleted object’s Object Handle in the same session.

MWP commented 2 weeks ago

Have you made any progress on this?