lfs.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597
  1. /*
  2. * The little filesystem
  3. *
  4. * Copyright (c) 2017 Christopher Haster
  5. * Distributed under the MIT license
  6. */
  7. #include "lfs.h"
  8. #include <string.h>
  9. #include <stdbool.h>
  10. static int lfs_diff(uint32_t a, uint32_t b) {
  11. return (int)(unsigned)(a - b);
  12. }
  13. static uint32_t lfs_crc(const uint8_t *data, lfs_size_t size, uint32_t crc) {
  14. static const uint32_t rtable[16] = {
  15. 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
  16. 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
  17. 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
  18. 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c,
  19. };
  20. for (lfs_size_t i = 0; i < size; i++) {
  21. crc = (crc >> 4) ^ rtable[(crc ^ (data[i] >> 0)) & 0xf];
  22. crc = (crc >> 4) ^ rtable[(crc ^ (data[i] >> 4)) & 0xf];
  23. }
  24. return crc;
  25. }
  26. static lfs_error_t lfs_bd_cmp(lfs_t *lfs,
  27. lfs_ino_t ino, lfs_off_t off, lfs_size_t size, const void *d) {
  28. const uint8_t *data = d;
  29. for (int i = 0; i < size; i++) {
  30. uint8_t c;
  31. int err = lfs->ops->read(lfs->bd, (void*)&c, ino, off + i, 1);
  32. if (err) {
  33. return err;
  34. }
  35. if (c != data[i]) {
  36. return false;
  37. }
  38. }
  39. return true;
  40. }
  41. static lfs_error_t lfs_alloc(lfs_t *lfs, lfs_ino_t *ino);
  42. static lfs_error_t lfs_free(lfs_t *lfs, lfs_ino_t ino);
  43. // Next index offset
  44. static lfs_off_t lfs_inext(lfs_t *lfs, lfs_off_t ioff) {
  45. ioff += 1;
  46. lfs_size_t wcount = lfs->info.erase_size/4;
  47. while (ioff % wcount == 0) {
  48. ioff += lfs_min(lfs_ctz(ioff/wcount + 1), wcount-1) + 1;
  49. }
  50. return ioff;
  51. }
  52. // Find index in index chain given its index offset
  53. static lfs_error_t lfs_ifind(lfs_t *lfs, lfs_ino_t head,
  54. lfs_size_t icount, lfs_off_t ioff, lfs_ino_t *ino) {
  55. lfs_size_t wcount = lfs->info.erase_size/4;
  56. lfs_off_t iitarget = ioff / wcount;
  57. lfs_off_t iicurrent = (icount-1) / wcount;
  58. while (iitarget != iicurrent) {
  59. lfs_size_t skip = lfs_min(
  60. lfs_min(lfs_ctz(iicurrent+1), wcount-1),
  61. lfs_npw2((iitarget ^ iicurrent)+1)-1);
  62. lfs_error_t err = lfs->ops->read(lfs->bd, (void*)&head,
  63. head, 4*skip, 4);
  64. if (err) {
  65. return err;
  66. }
  67. iicurrent -= 1 << skip;
  68. }
  69. return lfs->ops->read(lfs->bd, (void*)ino, head, 4*(ioff % wcount), 4);
  70. }
  71. // Append index to index chain, updates head and icount
  72. static lfs_error_t lfs_iappend(lfs_t *lfs, lfs_ino_t *headp,
  73. lfs_size_t *icountp, lfs_ino_t ino) {
  74. lfs_ino_t head = *headp;
  75. lfs_size_t ioff = *icountp - 1;
  76. lfs_size_t wcount = lfs->info.erase_size/4;
  77. ioff += 1;
  78. while (ioff % wcount == 0) {
  79. lfs_ino_t nhead;
  80. lfs_error_t err = lfs_alloc(lfs, &nhead);
  81. if (err) {
  82. return err;
  83. }
  84. lfs_off_t skips = lfs_min(lfs_ctz(ioff/wcount + 1), wcount-1) + 1;
  85. for (lfs_off_t i = 0; i < skips; i++) {
  86. err = lfs->ops->write(lfs->bd, (void*)&head, nhead, 4*i, 4);
  87. if (err) {
  88. return err;
  89. }
  90. if (head && i != skips-1) {
  91. err = lfs->ops->read(lfs->bd, (void*)&head, head, 4*i, 4);
  92. if (err) {
  93. return err;
  94. }
  95. }
  96. }
  97. ioff += skips;
  98. head = nhead;
  99. }
  100. lfs_error_t err = lfs->ops->write(lfs->bd, (void*)&ino,
  101. head, 4*(ioff % wcount), 4);
  102. if (err) {
  103. return err;
  104. }
  105. *headp = head;
  106. *icountp = ioff + 1;
  107. return 0;
  108. }
  109. // Memory managment
  110. static lfs_error_t lfs_alloc(lfs_t *lfs, lfs_ino_t *ino) {
  111. // TODO save slot for freeing?
  112. lfs_error_t err = lfs_ifind(lfs, lfs->free.d.head,
  113. lfs->free.d.icount, lfs->free.d.ioff, ino);
  114. if (err) {
  115. return err;
  116. }
  117. lfs->free.d.ioff = lfs_inext(lfs, lfs->free.d.ioff);
  118. return lfs->ops->erase(lfs->bd, *ino, 0, lfs->info.erase_size);
  119. }
  120. static lfs_error_t lfs_free(lfs_t *lfs, lfs_ino_t ino) {
  121. return lfs_iappend(lfs, &lfs->free.d.head, &lfs->free.d.icount, ino);
  122. }
  123. lfs_error_t lfs_check(lfs_t *lfs, lfs_ino_t block) {
  124. uint32_t crc = 0xffffffff;
  125. for (lfs_size_t i = 0; i < lfs->info.erase_size; i += 4) {
  126. uint32_t data;
  127. int err = lfs->ops->read(lfs->bd, (void*)&data, block, i, 4);
  128. if (err) {
  129. return err;
  130. }
  131. crc = lfs_crc((void*)&data, 4, crc);
  132. }
  133. return (crc != 0) ? LFS_ERROR_CORRUPT : LFS_ERROR_OK;
  134. }
  135. struct lfs_fetch_region {
  136. lfs_off_t off;
  137. lfs_size_t size;
  138. void *data;
  139. };
  140. lfs_error_t lfs_pair_fetch(lfs_t *lfs, lfs_ino_t pair[2],
  141. int count, const struct lfs_fetch_region *regions) {
  142. int checked = 0;
  143. int rev = 0;
  144. for (int i = 0; i < 2; i++) {
  145. uint32_t nrev;
  146. int err = lfs->ops->read(lfs->bd, (void*)&nrev,
  147. pair[0], 0, 4);
  148. if (err) {
  149. return err;
  150. }
  151. // TODO diff these
  152. if (checked > 0 && lfs_diff(nrev, rev) < 0) {
  153. continue;
  154. }
  155. err = lfs_check(lfs, pair[0]);
  156. if (err == LFS_ERROR_CORRUPT) {
  157. lfs_swap(&pair[0], &pair[1]);
  158. continue;
  159. } else if (err) {
  160. return err;
  161. }
  162. checked += 1;
  163. rev = nrev;
  164. lfs_swap(&pair[0], &pair[1]);
  165. }
  166. if (checked == 0) {
  167. return LFS_ERROR_CORRUPT;
  168. }
  169. for (int i = 0; i < count; i++) {
  170. int err = lfs->ops->read(lfs->bd, regions[i].data,
  171. pair[1], regions[i].off, regions[i].size);
  172. if (err) {
  173. return err;
  174. }
  175. }
  176. return 0;
  177. }
  178. struct lfs_commit_region {
  179. lfs_off_t off;
  180. lfs_size_t size;
  181. const void *data;
  182. };
  183. lfs_error_t lfs_pair_commit(lfs_t *lfs, lfs_ino_t pair[2],
  184. int count, const struct lfs_commit_region *regions) {
  185. uint32_t crc = 0xffffffff;
  186. int err = lfs->ops->erase(lfs->bd,
  187. pair[0], 0, lfs->info.erase_size);
  188. if (err) {
  189. return err;
  190. }
  191. lfs_off_t off = 0;
  192. while (off < lfs->info.erase_size - 4) {
  193. if (count > 0 && regions[0].off == off) {
  194. crc = lfs_crc(regions[0].data, regions[0].size, crc);
  195. int err = lfs->ops->write(lfs->bd, regions[0].data,
  196. pair[0], off, regions[0].size);
  197. if (err) {
  198. return err;
  199. }
  200. off += regions[0].size;
  201. count -= 1;
  202. regions += 1;
  203. } else {
  204. // TODO faster strides?
  205. uint8_t data;
  206. int err = lfs->ops->read(lfs->bd, (void*)&data,
  207. pair[1], off, sizeof(data));
  208. if (err) {
  209. return err;
  210. }
  211. crc = lfs_crc((void*)&data, sizeof(data), crc);
  212. err = lfs->ops->write(lfs->bd, (void*)&data,
  213. pair[0], off, sizeof(data));
  214. if (err) {
  215. return err;
  216. }
  217. off += sizeof(data);
  218. }
  219. }
  220. err = lfs->ops->write(lfs->bd, (void*)&crc,
  221. pair[0], lfs->info.erase_size-4, 4);
  222. if (err) {
  223. return err;
  224. }
  225. lfs_swap(&pair[0], &pair[1]);
  226. return 0;
  227. }
  228. lfs_error_t lfs_dir_make(lfs_t *lfs, lfs_dir_t *dir, lfs_ino_t parent[2]) {
  229. // Allocate pair of dir blocks
  230. for (int i = 0; i < 2; i++) {
  231. int err = lfs_alloc(lfs, &dir->pair[i]);
  232. if (err) {
  233. return err;
  234. }
  235. }
  236. // Rather than clobbering one of the blocks we just pretend
  237. // the revision may be valid
  238. int err = lfs->ops->read(lfs->bd, (void*)&dir->d.rev, dir->pair[1], 0, 4);
  239. if (err) {
  240. return err;
  241. }
  242. dir->d.rev += 1;
  243. // Other defaults
  244. dir->i = sizeof(struct lfs_disk_dir);
  245. dir->d.size = sizeof(struct lfs_disk_dir);
  246. dir->d.tail[0] = 0;
  247. dir->d.tail[1] = 0;
  248. // TODO sort this out
  249. dir->d.free = lfs->free.d;
  250. if (parent) {
  251. // Create '..' entry
  252. lfs_entry_t entry = {
  253. .d.type = LFS_TYPE_DIR,
  254. .d.len = sizeof(entry.d) + 2,
  255. .d.u.dir[0] = parent[0],
  256. .d.u.dir[1] = parent[1],
  257. };
  258. dir->d.size += entry.d.len;
  259. // Write out to memory
  260. return lfs_pair_commit(lfs, dir->pair,
  261. 3, (struct lfs_commit_region[3]){
  262. {0, sizeof(dir->d), &dir->d},
  263. {sizeof(dir->d), sizeof(entry.d), &entry.d},
  264. {sizeof(dir->d)+sizeof(entry.d), 2, ".."},
  265. });
  266. } else {
  267. return lfs_pair_commit(lfs, dir->pair,
  268. 1, (struct lfs_commit_region[1]){
  269. {0, sizeof(dir->d), &dir->d},
  270. });
  271. }
  272. }
  273. lfs_error_t lfs_dir_fetch(lfs_t *lfs, lfs_dir_t *dir, lfs_ino_t pair[2]) {
  274. dir->pair[0] = pair[0];
  275. dir->pair[1] = pair[1];
  276. dir->i = sizeof(dir->d);
  277. int err = lfs_pair_fetch(lfs, dir->pair,
  278. 1, (struct lfs_fetch_region[1]) {
  279. {0, sizeof(dir->d), &dir->d}
  280. });
  281. if (err == LFS_ERROR_CORRUPT) {
  282. LFS_ERROR("Corrupted dir at %d %d", pair[0], pair[1]);
  283. }
  284. return err;
  285. }
  286. lfs_error_t lfs_dir_next(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) {
  287. while (true) {
  288. // TODO iterate down list
  289. entry->dir[0] = dir->pair[0];
  290. entry->dir[1] = dir->pair[1];
  291. entry->off = dir->i;
  292. if (dir->d.size - dir->i < sizeof(entry->d)) {
  293. return LFS_ERROR_NO_ENTRY;
  294. }
  295. int err = lfs->ops->read(lfs->bd, (void*)&entry->d,
  296. dir->pair[1], dir->i, sizeof(entry->d));
  297. if (err) {
  298. return err;
  299. }
  300. dir->i += entry->d.len;
  301. // Skip any unknown entries
  302. if (entry->d.type == 1 || entry->d.type == 2) {
  303. return 0;
  304. }
  305. }
  306. }
  307. lfs_error_t lfs_dir_find(lfs_t *lfs, lfs_dir_t *dir,
  308. const char *path, lfs_entry_t *entry) {
  309. // TODO follow directories
  310. lfs_size_t pathlen = strcspn(path, "/");
  311. while (true) {
  312. int err = lfs_dir_next(lfs, dir, entry);
  313. if (err) {
  314. return err;
  315. }
  316. if (entry->d.len - sizeof(entry->d) != pathlen) {
  317. continue;
  318. }
  319. int ret = lfs_bd_cmp(lfs, entry->dir[1],
  320. entry->off + sizeof(entry->d), pathlen, path);
  321. if (ret < 0) {
  322. return ret;
  323. }
  324. // Found match
  325. if (ret == true) {
  326. return 0;
  327. }
  328. }
  329. }
  330. lfs_error_t lfs_dir_alloc(lfs_t *lfs, lfs_dir_t *dir,
  331. const char *path, lfs_entry_t *entry, uint16_t len) {
  332. int err = lfs_dir_find(lfs, dir, path, entry);
  333. if (err != LFS_ERROR_NO_ENTRY) {
  334. return err ? err : LFS_ERROR_EXISTS;
  335. }
  336. // Check if we fit
  337. if (dir->d.size + len > lfs->info.erase_size - 4) {
  338. return -1; // TODO make fit
  339. }
  340. return 0;
  341. }
  342. lfs_error_t lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path) {
  343. int err = lfs_dir_fetch(lfs, dir, lfs->cwd);
  344. if (err) {
  345. return err;
  346. }
  347. lfs_entry_t entry;
  348. err = lfs_dir_find(lfs, dir, path, &entry);
  349. if (err) {
  350. return err;
  351. } else if (entry.d.type != LFS_TYPE_DIR) {
  352. return LFS_ERROR_NOT_DIR;
  353. }
  354. return lfs_dir_fetch(lfs, dir, entry.d.u.dir);
  355. }
  356. lfs_error_t lfs_dir_close(lfs_t *lfs, lfs_dir_t *dir) {
  357. // Do nothing, dir is always synchronized
  358. return 0;
  359. }
  360. lfs_error_t lfs_mkdir(lfs_t *lfs, const char *path) {
  361. // Allocate entry for directory
  362. lfs_dir_t cwd;
  363. int err = lfs_dir_fetch(lfs, &cwd, lfs->cwd);
  364. if (err) {
  365. return err;
  366. }
  367. lfs_entry_t entry;
  368. err = lfs_dir_alloc(lfs, &cwd, path,
  369. &entry, sizeof(entry.d)+strlen(path));
  370. if (err) {
  371. return err;
  372. }
  373. // Build up new directory
  374. lfs_dir_t dir;
  375. err = lfs_dir_make(lfs, &dir, cwd.pair); // TODO correct parent?
  376. if (err) {
  377. return err;
  378. }
  379. entry.d.type = 2;
  380. entry.d.len = sizeof(entry.d) + strlen(path);
  381. entry.d.u.dir[0] = dir.pair[0];
  382. entry.d.u.dir[1] = dir.pair[1];
  383. cwd.d.rev += 1;
  384. cwd.d.size += entry.d.len;
  385. return lfs_pair_commit(lfs, entry.dir,
  386. 3, (struct lfs_commit_region[3]) {
  387. {0, sizeof(cwd.d), &cwd.d},
  388. {entry.off, sizeof(entry.d), &entry.d},
  389. {entry.off+sizeof(entry.d), entry.d.len - sizeof(entry.d), path}
  390. });
  391. }
  392. // Little filesystem operations
  393. lfs_error_t lfs_create(lfs_t *lfs, lfs_bd_t *bd, const struct lfs_bd_ops *ops) {
  394. lfs->bd = bd;
  395. lfs->ops = ops;
  396. lfs_error_t err = lfs->ops->info(lfs->bd, &lfs->info);
  397. if (err) {
  398. return err;
  399. }
  400. return 0;
  401. }
  402. lfs_error_t lfs_format(lfs_t *lfs) {
  403. struct lfs_bd_info info;
  404. lfs_error_t err = lfs->ops->info(lfs->bd, &info);
  405. if (err) {
  406. return err;
  407. }
  408. err = lfs->ops->erase(lfs->bd, 0, 0, 3*info.erase_size);
  409. if (err) {
  410. return err;
  411. }
  412. // TODO make sure that erase clobbered blocks
  413. { // Create free list
  414. lfs->free = (lfs_free_t){
  415. .d.head = 2,
  416. .d.ioff = 1,
  417. .d.icount = 1,
  418. .d.rev = 1,
  419. };
  420. lfs_size_t block_count = lfs->info.total_size / lfs->info.erase_size;
  421. for (lfs_ino_t i = 3; i < block_count; i++) {
  422. lfs_error_t err = lfs_free(lfs, i);
  423. if (err) {
  424. return err;
  425. }
  426. }
  427. }
  428. {
  429. // Write root directory
  430. lfs_dir_t root;
  431. int err = lfs_dir_make(lfs, &root, 0);
  432. if (err) {
  433. return err;
  434. }
  435. lfs->cwd[0] = root.pair[0];
  436. lfs->cwd[1] = root.pair[1];
  437. }
  438. {
  439. // Write superblocks
  440. lfs_superblock_t superblock = {
  441. .pair = {0, 1},
  442. .d.rev = 1,
  443. .d.size = sizeof(struct lfs_disk_superblock),
  444. .d.root = {lfs->cwd[0], lfs->cwd[1]},
  445. .d.magic = {"littlefs"},
  446. .d.block_size = info.erase_size,
  447. .d.block_count = info.total_size / info.erase_size,
  448. };
  449. for (int i = 0; i < 2; i++) {
  450. lfs_ino_t block = superblock.pair[0];
  451. int err = lfs_pair_commit(lfs, superblock.pair,
  452. 1, (struct lfs_commit_region[1]){
  453. {0, sizeof(superblock.d), &superblock.d}
  454. });
  455. err = lfs_check(lfs, block);
  456. if (err) {
  457. LFS_ERROR("Failed to write superblock at %d", block);
  458. return err;
  459. }
  460. }
  461. }
  462. return 0;
  463. }
  464. lfs_error_t lfs_mount(lfs_t *lfs) {
  465. struct lfs_bd_info info;
  466. lfs_error_t err = lfs->ops->info(lfs->bd, &info);
  467. if (err) {
  468. return err;
  469. }
  470. lfs_superblock_t superblock;
  471. err = lfs_pair_fetch(lfs,
  472. (lfs_ino_t[2]){0, 1},
  473. 1, (struct lfs_fetch_region[1]){
  474. {0, sizeof(superblock.d), &superblock.d}
  475. });
  476. if ((err == LFS_ERROR_CORRUPT ||
  477. memcmp(superblock.d.magic, "littlefs", 8) != 0)) {
  478. LFS_ERROR("Invalid superblock at %d %d\n", 0, 1);
  479. return LFS_ERROR_CORRUPT;
  480. }
  481. printf("superblock %d %d\n",
  482. superblock.d.block_size,
  483. superblock.d.block_count);
  484. lfs->cwd[0] = superblock.d.root[0];
  485. lfs->cwd[1] = superblock.d.root[1];
  486. return err;
  487. }