• Keine Ergebnisse gefunden

The usability of the APIs a software system provides can have a significant impact on its adoption and sustained use. As such, the design of usable APIs can be seen as critical for any software project, but especially for open-source projects which aim at widespread adoption. Designing an API involves many stakeholders, such as API producers, consumers and testers, all of which need to write software based on API prototypes, evaluating whether the API meets their needs [23]. As a result, the APIs presented in this thesis are prototypes based on feedback from the RIOT community. For final inclusion in the RIOT kernel, the API is expected to change based on further feedback from kernel developers and the community. In case of the FTL, the amount of functionality that needs to be exposed is relatively small:

• System initialization

• Writing, reading and erasing data

• Storing metadata

• Configuring the ECC algorithm

System initialization is performed by populating a struct with the required con-figuration parameters and invoking the FTL initialization function. An example is shown in Listing 9. The configuration parameters consist of basic information about the flash device (L6–11), function pointers for the flash device driver inter-face (L13–16) as well as the necessary buffers (L18–19). In addition, all partitions must be defined before the FTL is initialized (L22–43) and a list of partitions must be made available in the configuration (L46). Finally, "ftl_init" initializes the stor-age system, such that data can be read or written once it returns successfully.

52

5.7 Application Programming Interface

When examining the flash driver interface, one might notice that there are two different functions for the erase operation, “erase” and “erase_bulk". Since eras-ing blocks in bulk is not supported by all flash storage devices, the FTL will de-tect whether or not this feature is supported by checking if the function pointer to ”erase_bulk" is set. If not, block erasure will be performed with the “erase”

function.

Writing data is performed using either “ftl_write_raw", ”ftl_write" or "ftl_write_ecc"

(see Listing 10). These functions correspond to the three options for writing data described in Section 5.3. While writing in raw mode requires the selection of a target subpage, writing in managed mode will automatically write to the next free subpage and return its number. When specifying pages (or blocks), these are al-ways relative to the beginning of their respective partition, making it impossible to accidentally modify data outside of the selected partition.

Listing 10: Example usage of the API for writing data using the FTL

1 // Signature

2 int ftl_write_raw(const ftl_partition_s *partition, unsigned char *buffer,

3 uint32_t subpage);

4 // Example

5 int ret = ftl_write_raw(&firmware_partition, &buffer, 42);

6

7 // Signature

8 int ftl_write(const ftl_partition_s *partition, const unsigned char *buffer,

9 uint16_t data_length);

10 // Example

11 int subpage = ftl_write(&data_partition, &buffer, 100);

12

13 // Signature

14 int ftl_write_ecc(const ftl_partition_s *partition, const unsigned char *buffer,

15 uint16_t data_length);

16 // Example

17 int subpage = ftl_write_ecc(&data_partition, &buffer, 100);

Reading data is also possible in either raw or managed mode using “ftl_read_raw"

or ”ftl_read" (see Listing 11). The only relevant difference is that, when reading in managed mode, a header struct must be passed to the "ftl_read" function so that the header information can be returned. The managed read call will automatically

5 Design of the Flash Translation Layer

recognize if an ECC is present and verify the integrity of the subpage. Erasing data can be performed per erase block (used in garbage collection) or per partition (see Listing 12).

Listing 11: Example usage of the API for reading data using the FTL

1 // Signature

2 int ftl_read_raw(const ftl_partition_s *partition, unsigned char *buffer,

3 uint32_t subpage);

4 // Example

5 int ret = ftl_read_raw(&firmware_partition, &buffer, 42);

6

7 // Signature

8 int ftl_read(const ftl_partition_s *partition, unsigned char *buffer,

9 subpageheader_s *header, uint32_t subpage);

10 // Example

11 subpageheader_s header;

12 int ret = ftl_read(&data_partition, &buffer, &header, 42);

Listing 12: Example usage of the API for erasing data using the FTL

1 // Signature

2 int ftl_erase(const ftl_partition_s *partition, uint32_t block);

3 // Example

4 int ret = ftl_erase(&data_partition, 123);

5

6 // Signature

7 int ftl_format(const ftl_partition_s *partition);

8 // Example

9 int ret = ftl_format(&firmware_partition);

For metadata storage (see Section 5.6) the functions shown in Listing 13 were designed. “ftl_write_metadata" stores the FTLs metadata in a dedicated partition.

Through the ”foreign_metadata" parameter, it allows to store additional data not re-lated to the FTL. This mechanism is used, for example, to store the state of the OSL.

Storing both states using the same mechanism ensures that both states represent the same point in time. After storing it, the FTL can either load the latest metadata or a certain metadata version (“ftl_load_latest_metadata" and ”ftl_load_metadata"

54

5.7 Application Programming Interface

respectively). The "set_ftl_state" parameter dictates whether or not the state stored in the retrieved metadata should supersede the current state of the FTL.

Listing 13: Example usage of the API for storing metadata using the FTL

1 // Signature

2 int ftl_write_metadata(ftl_device_s *device, const void *foreign_metadata,

3 uint16_t length);

4 // Example which stores only the FTL’s metadata

5 int ret = ftl_write_metadata(&device, NULL, 0);

6

7 // Signature

8 int ftl_load_latest_metadata(ftl_device_s *device, void *buffer,

9 ftl_metadata_header_s *header, bool set_ftl_state);

10 // Example which will update the FTL’s state to the latest metadata

11 ftl_metadata_header_s header;

12 int ret = ftl_load_latest_metadata(device, foreign_metadata_buffer, &header, true);

13

14 // Signature

15 int ftl_load_metadata(ftl_device_s *device, void *buffer, ftl_metadata_header_s *header,

16 uint32_t version, bool set_ftl_state);

17 // Example which retrieves a specific metadata version but

18 // does not update the FTL’s state

19 ftl_metadata_header_s header;

20 int ret = ftl_load_metadata(&device, foreign_metadata_buffer, &header, 123, false);

Finally, the FTL allows the specification of a custom ECC computing and verifica-tion funcverifica-tion as well as the size of the resulting ECC (see Listing 14). Both are passed a data buffer of given size, for which the ECC is computed or verified. Note that it is only possible to change the ECC algorithm before any data has been writ-ten. If the ECC was changed after data has been written to the storage system, the data would be assumed to be corrupt when next checked because the ECC written using the previous algorithm would be verified using the new algorithm.

5 Design of the Flash Translation Layer

Listing 14: Example usage of the API for changing the ECC algorithm of the FTL

1 typedef int (*ecc_compute)(const unsigned char *data, uint32_t size,

2 unsigned char *code);

3 typedef int (*ecc_verify) (unsigned char *data, uint32_t size,

4 const unsigned char *code);

5 // Signature

6 int ftl_set_ecc(ftl_device_s *device, uint16_t size,

7 ecc_compute compute_fn, ecc_verify verify_fn);