lib_ringfs.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588
  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 <inttypes.h>
  15. #include <stdbool.h>
  16. #include <stddef.h>
  17. #include "lib_ringfs.h"
  18. /**
  19. * @defgroup sector
  20. * @{
  21. */
  22. #if 0
  23. enum sector_status {
  24. SECTOR_ERASED = 0xFFFFFFFF, /**< Default state after NOR flash erase. */
  25. SECTOR_FREE = 0xFFFFFF00, /**< Sector erased. */
  26. SECTOR_IN_USE = 0xFFFF0000, /**< Sector contains valid data. */
  27. SECTOR_ERASING = 0xFF000000, /**< Sector should be erased. */
  28. SECTOR_FORMATTING = 0x00000000, /**< The entire partition is being formatted. */
  29. };
  30. #else
  31. #define SECTOR_ERASED 0xFFFFFFFF /**< Default state after NOR flash erase. */
  32. #define SECTOR_FREE 0xFFFFFF00 /**< Sector erased. */
  33. #define SECTOR_IN_USE 0xFFFF0000 /**< Sector contains valid data. */
  34. #define SECTOR_ERASING 0xFF000000 /**< Sector should be erased. */
  35. #define SECTOR_FORMATTING 0x00000000 /**< The entire partition is being formatted. */
  36. #endif
  37. struct sector_header {
  38. uint32_t status;
  39. uint32_t version;
  40. };
  41. static int _sector_address(struct ringfs *fs, int sector_offset)
  42. {
  43. return (fs->flash->sector_offset + sector_offset) * fs->flash->sector_size;
  44. }
  45. static int _sector_get_status(struct ringfs *fs, int sector, uint32_t *status)
  46. {
  47. return fs->flash->read(fs->flash,
  48. _sector_address(fs, sector) + offsetof(struct sector_header, status),
  49. status, sizeof(*status));
  50. }
  51. static int _sector_set_status(struct ringfs *fs, int sector, uint32_t status)
  52. {
  53. return fs->flash->program(fs->flash,
  54. _sector_address(fs, sector) + offsetof(struct sector_header, status),
  55. &status, sizeof(status));
  56. }
  57. static int _sector_free(struct ringfs *fs, int sector)
  58. {
  59. int sector_addr = _sector_address(fs, sector);
  60. _sector_set_status(fs, sector, SECTOR_ERASING);
  61. fs->flash->sector_erase(fs->flash, sector_addr);
  62. fs->flash->program(fs->flash,
  63. sector_addr + offsetof(struct sector_header, version),
  64. &fs->version, sizeof(fs->version));
  65. _sector_set_status(fs, sector, SECTOR_FREE);
  66. return 0;
  67. }
  68. /**
  69. * @}
  70. * @defgroup slot
  71. * @{
  72. */
  73. #if 0
  74. enum slot_status {
  75. SLOT_ERASED = 0xFFFFFFFF, /**< Default state after NOR flash erase. */
  76. SLOT_RESERVED = 0xFFFFFF00, /**< Write started but not yet committed. */
  77. SLOT_VALID = 0xFFFF0000, /**< Write committed, slot contains valid data. */
  78. SLOT_GARBAGE = 0xFF000000, /**< Slot contents discarded and no longer valid. */
  79. };
  80. #else
  81. #define SLOT_ERASED 0xFFFFFFFF /**< Default state after NOR flash erase. */
  82. #define SLOT_RESERVED 0xFFFFFF00 /**< Write started but not yet committed. */
  83. #define SLOT_VALID 0xFFFF0000 /**< Write committed, slot contains valid data. */
  84. #define SLOT_GARBAGE 0xFF000000 /**< Slot contents discarded and no longer valid. */
  85. #endif
  86. struct slot_header {
  87. uint32_t status;
  88. };
  89. static int _slot_address(struct ringfs *fs, struct ringfs_loc *loc)
  90. {
  91. return _sector_address(fs, loc->sector) +
  92. sizeof(struct sector_header) +
  93. (sizeof(struct slot_header) + fs->object_size) * loc->slot;
  94. }
  95. static int _slot_get_status(struct ringfs *fs, struct ringfs_loc *loc, uint32_t *status)
  96. {
  97. return fs->flash->read(fs->flash,
  98. _slot_address(fs, loc) + offsetof(struct slot_header, status),
  99. status, sizeof(*status));
  100. }
  101. static int _slot_set_status(struct ringfs *fs, struct ringfs_loc *loc, uint32_t status)
  102. {
  103. return fs->flash->program(fs->flash,
  104. _slot_address(fs, loc) + offsetof(struct slot_header, status),
  105. &status, sizeof(status));
  106. }
  107. /**
  108. * @}
  109. * @defgroup loc
  110. * @{
  111. */
  112. static bool _loc_equal(struct ringfs_loc *a, struct ringfs_loc *b)
  113. {
  114. return (a->sector == b->sector) && (a->slot == b->slot);
  115. }
  116. /** Advance a location to the beginning of the next sector. */
  117. static void _loc_advance_sector(struct ringfs *fs, struct ringfs_loc *loc)
  118. {
  119. loc->slot = 0;
  120. loc->sector++;
  121. if (loc->sector >= fs->flash->sector_count)
  122. loc->sector = 0;
  123. }
  124. /** Advance a location to the next slot, advancing the sector too if needed. */
  125. static void _loc_advance_slot(struct ringfs *fs, struct ringfs_loc *loc)
  126. {
  127. loc->slot++;
  128. if (loc->slot >= fs->slots_per_sector)
  129. _loc_advance_sector(fs, loc);
  130. }
  131. /** Back a location to the ending of the pre sector. */
  132. static void _loc_back_sector(struct ringfs *fs, struct ringfs_loc *loc)
  133. {
  134. loc->slot = fs->slots_per_sector - 1;
  135. loc->sector--;
  136. if (loc->sector < 0)
  137. loc->sector = fs->flash->sector_count - 1;
  138. }
  139. /** Back a location to the next slot, backing the sector too if needed. */
  140. static void _loc_back_slot(struct ringfs *fs, struct ringfs_loc *loc)
  141. {
  142. loc->slot--;
  143. if (loc->slot < 0)
  144. _loc_back_sector(fs, loc);
  145. }
  146. /**
  147. * @}
  148. */
  149. /* And here we go. */
  150. int ringfs_init(struct ringfs *fs, struct ringfs_flash_partition *flash, uint32_t version, int object_size)
  151. {
  152. /* Copy arguments to instance. */
  153. fs->flash = flash;
  154. fs->version = version;
  155. fs->object_size = object_size;
  156. /* Precalculate commonly used values. */
  157. fs->slots_per_sector = (fs->flash->sector_size - sizeof(struct sector_header)) /
  158. (sizeof(struct slot_header) + fs->object_size);
  159. return 0;
  160. }
  161. int ringfs_format(struct ringfs *fs)
  162. {
  163. /* Mark all sectors to prevent half-erased filesystems. */
  164. for (int sector=0; sector<fs->flash->sector_count; sector++)
  165. _sector_set_status(fs, sector, SECTOR_FORMATTING);
  166. /* Erase, update version, mark as free. */
  167. for (int sector=0; sector<fs->flash->sector_count; sector++)
  168. _sector_free(fs, sector);
  169. /* Start reading & writing at the first sector. */
  170. fs->read.sector = 0;
  171. fs->read.slot = 0;
  172. fs->write.sector = 0;
  173. fs->write.slot = 0;
  174. fs->cursor.sector = 0;
  175. fs->cursor.slot = 0;
  176. return 0;
  177. }
  178. int ringfs_scan(struct ringfs *fs)
  179. {
  180. uint32_t previous_sector_status = SECTOR_FREE;
  181. /* The read sector is the first IN_USE sector *after* a FREE sector
  182. * (or the first one). */
  183. int read_sector = 0;
  184. /* The write sector is the last IN_USE sector *before* a FREE sector
  185. * (or the last one). */
  186. int write_sector = fs->flash->sector_count - 1;
  187. /* There must be at least one FREE sector available at all times. */
  188. bool free_seen = false;
  189. /* If there's no IN_USE sector, we start at the first one. */
  190. bool used_seen = false;
  191. /* Iterate over sectors. */
  192. for (int sector=0; sector<fs->flash->sector_count; sector++) {
  193. int addr = _sector_address(fs, sector);
  194. /* Read sector header. */
  195. struct sector_header header;
  196. fs->flash->read(fs->flash, addr, &header, sizeof(header));
  197. /* Detect partially-formatted partitions. */
  198. if (header.status == SECTOR_FORMATTING) {
  199. printf("ringfs_scan: partially formatted partition\r\n");
  200. return -1;
  201. }
  202. /* Detect and fix partially erased sectors. */
  203. if (header.status == SECTOR_ERASING || header.status == SECTOR_ERASED) {
  204. _sector_free(fs, addr);
  205. header.status = SECTOR_FREE;
  206. }
  207. /* Detect corrupted sectors. */
  208. if (header.status != SECTOR_FREE && header.status != SECTOR_IN_USE) {
  209. printf("ringfs_scan: corrupted sector %d\r\n", sector);
  210. return -1;
  211. }
  212. /* Detect obsolete versions. We can't do this earlier because the version
  213. * could have been invalid due to a partial erase. */
  214. if (header.version != fs->version) {
  215. printf("ringfs_scan: incompatible version 0x%08"PRIx32"\r\n", header.version);
  216. return -1;
  217. }
  218. /* Record the presence of a FREE sector. */
  219. if (header.status == SECTOR_FREE)
  220. free_seen = true;
  221. /* Record the presence of a IN_USE sector. */
  222. if (header.status == SECTOR_IN_USE)
  223. used_seen = true;
  224. /* Update read & write sectors according to the above rules. */
  225. if (header.status == SECTOR_IN_USE && previous_sector_status == SECTOR_FREE)
  226. read_sector = sector;
  227. if (header.status == SECTOR_FREE && previous_sector_status == SECTOR_IN_USE)
  228. write_sector = sector-1;
  229. previous_sector_status = header.status;
  230. }
  231. /* Detect the lack of a FREE sector. */
  232. if (!free_seen) {
  233. printf("ringfs_scan: invariant violated: no FREE sector found\r\n");
  234. return -1;
  235. }
  236. /* Start writing at the first sector if the filesystem is empty. */
  237. if (!used_seen) {
  238. write_sector = 0;
  239. }
  240. /* Scan the write sector and skip all occupied slots at the beginning. */
  241. fs->write.sector = write_sector;
  242. fs->write.slot = 0;
  243. while (fs->write.sector == write_sector) {
  244. uint32_t status;
  245. _slot_get_status(fs, &fs->write, &status);
  246. if (status == SLOT_ERASED)
  247. break;
  248. _loc_advance_slot(fs, &fs->write);
  249. }
  250. /* If the sector was full, we're at the beginning of a FREE sector now. */
  251. /* Position the read head at the start of the first IN_USE sector, then skip
  252. * over garbage/invalid slots until something of value is found or we reach
  253. * the write head which means there's no data. */
  254. fs->read.sector = read_sector;
  255. fs->read.slot = 0;
  256. while (!_loc_equal(&fs->read, &fs->write)) {
  257. uint32_t status;
  258. _slot_get_status(fs, &fs->read, &status);
  259. if (status == SLOT_VALID)
  260. break;
  261. _loc_advance_slot(fs, &fs->read);
  262. }
  263. /* Move the read cursor to the read head position. */
  264. fs->cursor = fs->read;
  265. return 0;
  266. }
  267. int ringfs_capacity(struct ringfs *fs)
  268. {
  269. return fs->slots_per_sector * (fs->flash->sector_count - 1);
  270. }
  271. int ringfs_count_estimate(struct ringfs *fs)
  272. {
  273. int sector_diff = (fs->write.sector - fs->read.sector + fs->flash->sector_count) %
  274. fs->flash->sector_count;
  275. return sector_diff * fs->slots_per_sector + fs->write.slot - fs->read.slot;
  276. }
  277. int ringfs_count_exact(struct ringfs *fs)
  278. {
  279. int count = 0;
  280. /* Use a temporary loc for iteration. */
  281. struct ringfs_loc loc = fs->read;
  282. while (!_loc_equal(&loc, &fs->write)) {
  283. uint32_t status;
  284. _slot_get_status(fs, &loc, &status);
  285. if (status == SLOT_VALID)
  286. count++;
  287. _loc_advance_slot(fs, &loc);
  288. }
  289. return count;
  290. }
  291. int ringfs_append(struct ringfs *fs, const void *object)
  292. {
  293. uint32_t status;
  294. /*
  295. * There are three sectors involved in appending a value:
  296. * - the sector where the append happens: it has to be writable
  297. * - the next sector: it must be free (invariant)
  298. * - the next-next sector: read & cursor heads are moved there if needed
  299. */
  300. /* Make sure the next sector is free. */
  301. int next_sector = (fs->write.sector+1) % fs->flash->sector_count;
  302. _sector_get_status(fs, next_sector, &status);
  303. if (status != SECTOR_FREE) {
  304. /* Next sector must be freed. But first... */
  305. /* Move the read & cursor heads out of the way. */
  306. if (fs->read.sector == next_sector)
  307. _loc_advance_sector(fs, &fs->read);
  308. if (fs->cursor.sector == next_sector)
  309. _loc_advance_sector(fs, &fs->cursor);
  310. /* Free the next sector. */
  311. _sector_free(fs, next_sector);
  312. }
  313. /* Now we can make sure the current write sector is writable. */
  314. _sector_get_status(fs, fs->write.sector, &status);
  315. if (status == SECTOR_FREE) {
  316. /* Free sector. Mark as used. */
  317. _sector_set_status(fs, fs->write.sector, SECTOR_IN_USE);
  318. } else if (status != SECTOR_IN_USE) {
  319. printf("ringfs_append: corrupted filesystem\r\n");
  320. return -1;
  321. }
  322. /* Preallocate slot. */
  323. _slot_set_status(fs, &fs->write, SLOT_RESERVED);
  324. /* Write object. */
  325. fs->flash->program(fs->flash,
  326. _slot_address(fs, &fs->write) + sizeof(struct slot_header),
  327. object, fs->object_size);
  328. /* Commit write. */
  329. _slot_set_status(fs, &fs->write, SLOT_VALID);
  330. /* Advance the write head. */
  331. _loc_advance_slot(fs, &fs->write);
  332. return 0;
  333. }
  334. int ringfs_fetch(struct ringfs *fs, void *object)
  335. {
  336. /* Advance forward in search of a valid slot. */
  337. while (!_loc_equal(&fs->cursor, &fs->write)) {
  338. uint32_t status;
  339. _slot_get_status(fs, &fs->cursor, &status);
  340. if (status == SLOT_VALID) {
  341. fs->flash->read(fs->flash,
  342. _slot_address(fs, &fs->cursor) + sizeof(struct slot_header),
  343. object, fs->object_size);
  344. _loc_advance_slot(fs, &fs->cursor);
  345. return 0;
  346. }
  347. _loc_advance_slot(fs, &fs->cursor);
  348. }
  349. return -1;
  350. }
  351. int ringfs_pop(struct ringfs *fs, void *object)
  352. {
  353. fs->cursor = fs->write;
  354. /* Advance forward in search of a valid slot. */
  355. /*向前搜索有效的数据单元*/
  356. return ringfs_del(fs, object);
  357. }
  358. int ringfs_del(struct ringfs *fs, void *object)
  359. {
  360. /* Advance forward in search of a valid slot. */
  361. while (!_loc_equal(&fs->cursor, &fs->read)) {
  362. uint32_t status;
  363. _loc_back_slot(fs, &fs->cursor);
  364. _slot_get_status(fs, &fs->cursor, &status);
  365. if (status == SLOT_VALID) {
  366. fs->flash->read(fs->flash,
  367. _slot_address(fs, &fs->cursor) + sizeof(struct slot_header),
  368. object, fs->object_size);
  369. _slot_set_status(fs, &fs->cursor, SLOT_GARBAGE);
  370. //boly modify 20221124
  371. //_loc_back_slot(fs, &fs->cursor);
  372. //end boly
  373. return 0;
  374. }
  375. }
  376. ringfs_check(fs);
  377. return -1;
  378. }
  379. int ringfs_discard(struct ringfs *fs)
  380. {
  381. while (!_loc_equal(&fs->read, &fs->cursor)) {
  382. _slot_set_status(fs, &fs->read, SLOT_GARBAGE);
  383. _loc_advance_slot(fs, &fs->read);
  384. }
  385. return 0;
  386. }
  387. int ringfs_item_discard(struct ringfs *fs)
  388. {
  389. _slot_set_status(fs, &fs->read, SLOT_GARBAGE);
  390. _loc_advance_slot(fs, &fs->read);
  391. return 0;
  392. }
  393. int ringfs_end(struct ringfs *fs)
  394. {
  395. fs->cursor = fs->write;
  396. return 0;
  397. }
  398. int ringfs_rewind(struct ringfs *fs)
  399. {
  400. fs->cursor = fs->read;
  401. return 0;
  402. }
  403. int ringfs_check(struct ringfs *fs)
  404. {
  405. uint32_t status;
  406. if(_loc_equal(&fs->write, &fs->read)) //检查读写位置是否一致
  407. {
  408. return -1;
  409. }
  410. _slot_get_status(fs, &fs->read, &status);
  411. if (status != SLOT_GARBAGE) //检查读取位置是否可用
  412. {
  413. return -1;
  414. }
  415. if(_loc_equal(&fs->read, &fs->cursor) )//检查当前位置与读取位置是否一致
  416. {
  417. _loc_advance_slot(fs, &fs->read);
  418. fs->cursor = fs->read;
  419. }
  420. else
  421. {
  422. _loc_advance_slot(fs, &fs->read);
  423. }
  424. return 0;
  425. }
  426. void ringfs_dump(FILE *stream, struct ringfs *fs)
  427. {
  428. const char *description;
  429. fprintf(stream, "RingFS read: {%d,%d} cursor: {%d,%d} write: {%d,%d}\n",
  430. fs->read.sector, fs->read.slot,
  431. fs->cursor.sector, fs->cursor.slot,
  432. fs->write.sector, fs->write.slot);
  433. for (int sector=0; sector<fs->flash->sector_count; sector++) {
  434. int addr = _sector_address(fs, sector);
  435. /* Read sector header. */
  436. struct sector_header header;
  437. fs->flash->read(fs->flash, addr, &header, sizeof(header));
  438. switch (header.status) {
  439. case SECTOR_ERASED: description = "ERASED"; break;
  440. case SECTOR_FREE: description = "FREE"; break;
  441. case SECTOR_IN_USE: description = "IN_USE"; break;
  442. case SECTOR_ERASING: description = "ERASING"; break;
  443. case SECTOR_FORMATTING: description = "FORMATTING"; break;
  444. default: description = "UNKNOWN"; break;
  445. }
  446. fprintf(stream, "[%04d] [v=0x%08"PRIx32"] [%-10s] ",
  447. sector, header.version, description);
  448. for (int slot=0; slot<fs->slots_per_sector; slot++) {
  449. struct ringfs_loc loc = { sector, slot };
  450. uint32_t status;
  451. _slot_get_status(fs, &loc, &status);
  452. switch (status) {
  453. case SLOT_ERASED: description = "E"; break;
  454. case SLOT_RESERVED: description = "R"; break;
  455. case SLOT_VALID: description = "V"; break;
  456. case SLOT_GARBAGE: description = "G"; break;
  457. default: description = "?"; break;
  458. }
  459. fprintf(stream, "%s", description);
  460. }
  461. fprintf(stream, "\n");
  462. }
  463. fflush(stream);
  464. }
  465. void ringfs_assert_failed(int8_t* func, int8_t* file, uint32_t line)
  466. {
  467. // User can add his own implementation to report the file name and line number,
  468. // ex: printf(“Wrong parameters value: file %s on line %d\r\n”, file, line) /
  469. // Infinite loop */
  470. while (1){
  471. };
  472. };
  473. /**
  474. * @}
  475. */
  476. /* vim: set ts=4 sw=4 et: */