ringfs.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. /*
  2. * Copyright © 2014 Kosma Moczek <kosma@cloudyourcar.com>
  3. * This program is free software. It comes without any warranty, to the extent
  4. * permitted by applicable law. You can redistribute it and/or modify it under
  5. * the terms of the Do What The Fuck You Want To Public License, Version 2, as
  6. * published by Sam Hocevar. See the COPYING file for more details.
  7. */
  8. /**
  9. * @defgroup ringfs_impl RingFS implementation
  10. * @details
  11. *
  12. * @{
  13. */
  14. #include <ringfs.h>
  15. #include <inttypes.h>
  16. #include <stdbool.h>
  17. #include <stddef.h>
  18. //#include "main.h"
  19. #include "common_config.h"
  20. /**
  21. * @defgroup sector
  22. * @{
  23. */
  24. enum sector_status {
  25. SECTOR_ERASED = 0xFFFFFFFF, /**< Default state after NOR flash erase. */
  26. SECTOR_FREE = 0xFFFFFF00, /**< Sector erased. */
  27. SECTOR_IN_USE = 0xFFFF0000, /**< Sector contains valid data. */
  28. SECTOR_ERASING = 0xFF000000, /**< Sector should be erased. */
  29. SECTOR_FORMATTING = 0x00000000, /**< The entire partition is being formatted. */
  30. };
  31. struct sector_header {
  32. uint32_t status;
  33. uint32_t version;
  34. };
  35. static int _sector_address(struct ringfs *fs, int sector_offset)
  36. {
  37. return (fs->flash->sector_offset + sector_offset) * fs->flash->sector_size;
  38. }
  39. static int _sector_get_status(struct ringfs *fs, int sector, uint32_t *status)
  40. {
  41. return fs->flash->read(fs->flash,
  42. _sector_address(fs, sector) + offsetof(struct sector_header, status),
  43. status, sizeof(*status));
  44. }
  45. static int _sector_set_status(struct ringfs *fs, int sector, uint32_t status)
  46. {
  47. return fs->flash->program(fs->flash,
  48. _sector_address(fs, sector) + offsetof(struct sector_header, status),
  49. &status, sizeof(status));
  50. }
  51. static int _sector_free(struct ringfs *fs, int sector)
  52. {
  53. int sector_addr = _sector_address(fs, sector);
  54. _sector_set_status(fs, sector, SECTOR_ERASING);
  55. fs->flash->sector_erase(fs->flash, sector_addr);
  56. fs->flash->program(fs->flash,
  57. sector_addr + offsetof(struct sector_header, version),
  58. &fs->version, sizeof(fs->version));
  59. _sector_set_status(fs, sector, SECTOR_FREE);
  60. return 0;
  61. }
  62. /**
  63. * @}
  64. * @defgroup slot
  65. * @{
  66. */
  67. enum slot_status {
  68. SLOT_ERASED = 0xFFFFFFFF, /**< Default state after NOR flash erase. */
  69. SLOT_RESERVED = 0xFFFFFF00, /**< Write started but not yet committed. */
  70. SLOT_VALID = 0xFFFF0000, /**< Write committed, slot contains valid data. */
  71. SLOT_GARBAGE = 0xFF000000, /**< Slot contents discarded and no longer valid. */
  72. };
  73. struct slot_header {
  74. uint32_t status;
  75. };
  76. static int _slot_address(struct ringfs *fs, struct ringfs_loc *loc)
  77. {
  78. return _sector_address(fs, loc->sector) +
  79. sizeof(struct sector_header) +
  80. (sizeof(struct slot_header) + fs->object_size) * loc->slot;
  81. }
  82. static int _slot_get_status(struct ringfs *fs, struct ringfs_loc *loc, uint32_t *status)
  83. {
  84. return fs->flash->read(fs->flash,
  85. _slot_address(fs, loc) + offsetof(struct slot_header, status),
  86. status, sizeof(*status));
  87. }
  88. static int _slot_set_status(struct ringfs *fs, struct ringfs_loc *loc, uint32_t status)
  89. {
  90. return fs->flash->program(fs->flash,
  91. _slot_address(fs, loc) + offsetof(struct slot_header, status),
  92. &status, sizeof(status));
  93. }
  94. /**
  95. * @}
  96. * @defgroup loc
  97. * @{
  98. */
  99. static bool _loc_equal(struct ringfs_loc *a, struct ringfs_loc *b)
  100. {
  101. return (a->sector == b->sector) && (a->slot == b->slot);
  102. }
  103. /** Advance a location to the beginning of the next sector. */
  104. static void _loc_advance_sector(struct ringfs *fs, struct ringfs_loc *loc)
  105. {
  106. loc->slot = 0;
  107. loc->sector++;
  108. if (loc->sector >= fs->flash->sector_count)
  109. loc->sector = 0;
  110. }
  111. /** Advance a location to the next slot, advancing the sector too if needed. */
  112. static void _loc_advance_slot(struct ringfs *fs, struct ringfs_loc *loc)
  113. {
  114. loc->slot++;
  115. if (loc->slot >= fs->slots_per_sector)
  116. _loc_advance_sector(fs, loc);
  117. }
  118. /**
  119. * @}
  120. */
  121. /* And here we go. */
  122. int ringfs_init(struct ringfs *fs, struct ringfs_flash_partition *flash, uint32_t version, int object_size)
  123. {
  124. /* Copy arguments to instance. */
  125. fs->flash = flash;
  126. fs->version = version;
  127. fs->object_size = object_size;
  128. /* Precalculate commonly used values. */
  129. #if 0
  130. fs->slots_per_sector = (fs->flash->sector_size - sizeof(struct sector_header)) /
  131. (sizeof(struct slot_header) + fs->object_size);
  132. #endif
  133. fs->slots_per_sector = 2;
  134. return 0;
  135. }
  136. int ringfs_format(struct ringfs *fs)
  137. {
  138. /* Mark all sectors to prevent half-erased filesystems. */
  139. for (int sector=0; sector<fs->flash->sector_count; sector++)
  140. _sector_set_status(fs, sector, SECTOR_FORMATTING);
  141. /* Erase, update version, mark as free. */
  142. for (int sector=0; sector<fs->flash->sector_count; sector++)
  143. _sector_free(fs, sector);
  144. /* Start reading & writing at the first sector. */
  145. fs->read.sector = 0;
  146. fs->read.slot = 0;
  147. fs->write.sector = 0;
  148. fs->write.slot = 0;
  149. fs->cursor.sector = 0;
  150. fs->cursor.slot = 0;
  151. fs->cursor_position = 0;
  152. return 0;
  153. }
  154. int ringfs_scan(struct ringfs *fs)
  155. {
  156. uint32_t previous_sector_status = SECTOR_FREE;
  157. /* The read sector is the first IN_USE sector *after* a FREE sector
  158. * (or the first one). */
  159. int read_sector = 0;
  160. /* The write sector is the last IN_USE sector *before* a FREE sector
  161. * (or the last one). */
  162. int write_sector = fs->flash->sector_count - 1;
  163. /* There must be at least one FREE sector available at all times. */
  164. bool free_seen = false;
  165. /* If there's no IN_USE sector, we start at the first one. */
  166. bool used_seen = false;
  167. bool err_sector = true;
  168. /* Iterate over sectors. */
  169. for (int sector=0; sector<fs->flash->sector_count; sector++) {
  170. int addr = _sector_address(fs, sector);
  171. /* Read sector header. */
  172. struct sector_header header;
  173. fs->flash->read(fs->flash, addr, &header, sizeof(header));
  174. /* Detect partially-formatted partitions. */
  175. if (header.status == SECTOR_FORMATTING) {
  176. DBG printf("ringfs_scan: partially formatted partition\r\n");
  177. if(err_sector){
  178. err_sector = false;
  179. _sector_free(fs, addr);
  180. //fs->flash->read(fs->flash, addr, &header, sizeof(header));
  181. header.status = SECTOR_FREE;
  182. header.version = fs->version;
  183. }else{
  184. return -1;
  185. }
  186. }
  187. /* Detect and fix partially erased sectors. */
  188. if (header.status == SECTOR_ERASING || header.status == SECTOR_ERASED) {
  189. _sector_free(fs, addr);
  190. header.status = SECTOR_FREE;
  191. }
  192. /* Detect corrupted sectors. */
  193. if (header.status != SECTOR_FREE && header.status != SECTOR_IN_USE) {
  194. DBG printf("ringfs_scan: corrupted sector %d\r\n", sector);
  195. if(err_sector){
  196. err_sector = false;
  197. _sector_free(fs, addr);
  198. //fs->flash->read(fs->flash, addr, &header, sizeof(header));
  199. header.status = SECTOR_FREE;
  200. header.version = fs->version;
  201. }else{
  202. return -1;
  203. }
  204. }
  205. /* Detect obsolete versions. We can't do this earlier because the version
  206. * could have been invalid due to a partial erase. */
  207. if (header.version != fs->version) {
  208. DBG printf("ringfs_scan: corrupted sector %d\r\n", sector);
  209. DBG printf("ringfs_scan: incompatible version 0x%08"PRIx32"\r\n", header.version);
  210. if(err_sector){
  211. err_sector = false;
  212. _sector_free(fs, addr);
  213. //fs->flash->read(fs->flash, addr, &header, sizeof(header));
  214. DBG printf("ringfs_scan: incompatible version 0x%08"PRIx32"\r\n", header.version);
  215. header.status = SECTOR_FREE;
  216. header.version = fs->version;
  217. }else{
  218. return -1;
  219. }
  220. }
  221. /* Record the presence of a FREE sector. */
  222. if (header.status == SECTOR_FREE)
  223. free_seen = true;
  224. /* Record the presence of a IN_USE sector. */
  225. if (header.status == SECTOR_IN_USE)
  226. used_seen = true;
  227. /* Update read & write sectors according to the above rules. */
  228. if (header.status == SECTOR_IN_USE && previous_sector_status == SECTOR_FREE)
  229. read_sector = sector;
  230. if (header.status == SECTOR_FREE && previous_sector_status == SECTOR_IN_USE)
  231. write_sector = sector-1;
  232. previous_sector_status = header.status;
  233. }
  234. /* Detect the lack of a FREE sector. */
  235. if (!free_seen) {
  236. DBG printf("ringfs_scan: invariant violated: no FREE sector found\r\n");
  237. return -1;
  238. }
  239. /* Start writing at the first sector if the filesystem is empty. */
  240. if (!used_seen) {
  241. write_sector = 0;
  242. }
  243. /* Scan the write sector and skip all occupied slots at the beginning. */
  244. fs->write.sector = write_sector;
  245. fs->write.slot = 0;
  246. while (fs->write.sector == write_sector) {
  247. uint32_t status;
  248. _slot_get_status(fs, &fs->write, &status);
  249. if (status == SLOT_ERASED)
  250. break;
  251. _loc_advance_slot(fs, &fs->write);
  252. }
  253. /* If the sector was full, we're at the beginning of a FREE sector now. */
  254. /* Position the read head at the start of the first IN_USE sector, then skip
  255. * over garbage/invalid slots until something of value is found or we reach
  256. * the write head which means there's no data. */
  257. fs->read.sector = read_sector;
  258. fs->read.slot = 0;
  259. while (!_loc_equal(&fs->read, &fs->write)) {
  260. uint32_t status;
  261. _slot_get_status(fs, &fs->read, &status);
  262. if (status == SLOT_VALID)
  263. break;
  264. _loc_advance_slot(fs, &fs->read);
  265. }
  266. /* Move the read cursor to the read head position. */
  267. ringfs_rewind(fs);
  268. return 0;
  269. }
  270. int ringfs_capacity(struct ringfs *fs)
  271. {
  272. return fs->slots_per_sector * (fs->flash->sector_count - 1);
  273. }
  274. int ringfs_count_estimate(struct ringfs *fs)
  275. {
  276. int sector_diff = (fs->write.sector - fs->read.sector + fs->flash->sector_count) %
  277. fs->flash->sector_count;
  278. return sector_diff * fs->slots_per_sector + fs->write.slot - fs->read.slot;
  279. }
  280. int ringfs_count_exact(struct ringfs *fs)
  281. {
  282. int count = 0;
  283. /* Use a temporary loc for iteration. */
  284. struct ringfs_loc loc = fs->read;
  285. while (!_loc_equal(&loc, &fs->write)) {
  286. uint32_t status;
  287. _slot_get_status(fs, &loc, &status);
  288. if (status == SLOT_VALID)
  289. count++;
  290. _loc_advance_slot(fs, &loc);
  291. }
  292. return count;
  293. }
  294. int ringfs_cursor_position(struct ringfs *fs) {
  295. return fs->cursor_position;
  296. }
  297. int ringfs_append(struct ringfs *fs, const void *object)
  298. {
  299. uint32_t status;
  300. /*
  301. * There are three sectors involved in appending a value:
  302. * - the sector where the append happens: it has to be writable
  303. * - the next sector: it must be free (invariant)
  304. * - the next-next sector: read & cursor heads are moved there if needed
  305. */
  306. /* Make sure the next sector is free. */
  307. int next_sector = (fs->write.sector+1) % fs->flash->sector_count;
  308. _sector_get_status(fs, next_sector, &status);
  309. if (status != SECTOR_FREE) {
  310. /* Next sector must be freed. But first... */
  311. /* Move the read & cursor heads out of the way. */
  312. if (fs->read.sector == next_sector)
  313. _loc_advance_sector(fs, &fs->read);
  314. if (fs->cursor.sector == next_sector)
  315. _loc_advance_sector(fs, &fs->cursor);
  316. /* Free the next sector. */
  317. _sector_free(fs, next_sector);
  318. }
  319. /* Now we can make sure the current write sector is writable. */
  320. _sector_get_status(fs, fs->write.sector, &status);
  321. if (status == SECTOR_FREE) {
  322. /* Free sector. Mark as used. */
  323. _sector_set_status(fs, fs->write.sector, SECTOR_IN_USE);
  324. } else if (status != SECTOR_IN_USE) {
  325. printf("ringfs_append: corrupted filesystem\r\n");
  326. return -1;
  327. }
  328. /* Preallocate slot. */
  329. _slot_set_status(fs, &fs->write, SLOT_RESERVED);
  330. /* Write object. */
  331. fs->flash->program(fs->flash,
  332. _slot_address(fs, &fs->write) + sizeof(struct slot_header),
  333. object, fs->object_size);
  334. /* Commit write. */
  335. _slot_set_status(fs, &fs->write, SLOT_VALID);
  336. /* Advance the write head. */
  337. _loc_advance_slot(fs, &fs->write);
  338. return 0;
  339. }
  340. int ringfs_fetch(struct ringfs *fs, void *object)
  341. {
  342. /* Advance forward in search of a valid slot. */
  343. while (!_loc_equal(&fs->cursor, &fs->write)) {
  344. uint32_t status;
  345. _slot_get_status(fs, &fs->cursor, &status);
  346. printf("SLOT STATUS: %X\r\n", status);
  347. if (status == SLOT_VALID) {
  348. fs->flash->read(fs->flash,
  349. _slot_address(fs, &fs->cursor) + sizeof(struct slot_header),
  350. object, fs->object_size);
  351. _loc_advance_slot(fs, &fs->cursor);
  352. fs->cursor_position++;
  353. return 0;
  354. }
  355. _loc_advance_slot(fs, &fs->cursor);
  356. }
  357. return -1;
  358. }
  359. int ringfs_discard(struct ringfs *fs)
  360. {
  361. while (!_loc_equal(&fs->read, &fs->cursor)) {
  362. _slot_set_status(fs, &fs->read, SLOT_GARBAGE);
  363. _loc_advance_slot(fs, &fs->read);
  364. }
  365. fs->cursor_position = 0;
  366. return 0;
  367. }
  368. int ringfs_rewind(struct ringfs *fs)
  369. {
  370. fs->cursor = fs->read;
  371. fs->cursor_position = 0;
  372. return 0;
  373. }
  374. /**
  375. * @}
  376. */
  377. /* vim: set ts=4 sw=4 et: */