littlefs_fs.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746
  1. /*
  2. * Copyright (c) 2019 Bolt Innovation Management, LLC
  3. * Copyright (c) 2019 Peter Bigot Consulting, LLC
  4. *
  5. * SPDX-License-Identifier: Apache-2.0
  6. */
  7. #include <stdio.h>
  8. #include <string.h>
  9. #include <kernel.h>
  10. #include <device.h>
  11. #include <errno.h>
  12. #include <init.h>
  13. #include <fs/fs.h>
  14. #include <fs/fs_sys.h>
  15. #define LFS_LOG_REGISTER
  16. #include <lfs_util.h>
  17. #include <lfs.h>
  18. #include <fs/littlefs.h>
  19. #include <drivers/flash.h>
  20. #include <partition/partition.h>
  21. #include <board_cfg.h>
  22. #include "fs_impl.h"
  23. struct lfs_file_data {
  24. struct lfs_file file;
  25. struct lfs_file_config config;
  26. void *cache_block;
  27. };
  28. #define LFS_FILEP(fp) (&((struct lfs_file_data *)(fp->filep))->file)
  29. /* Global memory pool for open files and dirs */
  30. static K_MEM_SLAB_DEFINE(file_data_pool, sizeof(struct lfs_file_data),
  31. CONFIG_FS_LITTLEFS_NUM_FILES, 4);
  32. static K_MEM_SLAB_DEFINE(lfs_dir_pool, sizeof(struct lfs_dir),
  33. CONFIG_FS_LITTLEFS_NUM_DIRS, 4);
  34. /* Inferred overhead, in bytes, for each k_heap_aligned allocation for
  35. * the filecache heap. This relates to the CHUNK_UNIT parameter in
  36. * the heap implementation, but that value is not visible outside the
  37. * kernel.
  38. */
  39. #define FC_HEAP_PER_ALLOC_OVERHEAD 24U
  40. #if (CONFIG_FS_LITTLEFS_FC_HEAP_SIZE - 0) <= 0
  41. /* Auto-generate heap size from cache size and number of files */
  42. #undef CONFIG_FS_LITTLEFS_FC_HEAP_SIZE
  43. #define CONFIG_FS_LITTLEFS_FC_HEAP_SIZE \
  44. ((CONFIG_FS_LITTLEFS_CACHE_SIZE + FC_HEAP_PER_ALLOC_OVERHEAD) * \
  45. CONFIG_FS_LITTLEFS_NUM_FILES)
  46. #endif /* CONFIG_FS_LITTLEFS_FC_HEAP_SIZE */
  47. static K_HEAP_DEFINE(file_cache_heap, CONFIG_FS_LITTLEFS_FC_HEAP_SIZE);
  48. static inline void *fc_allocate(size_t size)
  49. {
  50. void *ret = NULL;
  51. ret = k_heap_alloc(&file_cache_heap, size, K_NO_WAIT);
  52. return ret;
  53. }
  54. static inline void fc_release(void *buf)
  55. {
  56. k_heap_free(&file_cache_heap, buf);
  57. }
  58. static inline void fs_lock(struct fs_littlefs *fs)
  59. {
  60. k_mutex_lock(&fs->mutex, K_FOREVER);
  61. }
  62. static inline void fs_unlock(struct fs_littlefs *fs)
  63. {
  64. k_mutex_unlock(&fs->mutex);
  65. }
  66. static int lfs_to_errno(int error)
  67. {
  68. if (error >= 0) {
  69. return error;
  70. }
  71. switch (error) {
  72. default:
  73. case LFS_ERR_IO: /* Error during device operation */
  74. return -EIO;
  75. case LFS_ERR_CORRUPT: /* Corrupted */
  76. return -EFAULT;
  77. case LFS_ERR_NOENT: /* No directory entry */
  78. return -ENOENT;
  79. case LFS_ERR_EXIST: /* Entry already exists */
  80. return -EEXIST;
  81. case LFS_ERR_NOTDIR: /* Entry is not a dir */
  82. return -ENOTDIR;
  83. case LFS_ERR_ISDIR: /* Entry is a dir */
  84. return -EISDIR;
  85. case LFS_ERR_NOTEMPTY: /* Dir is not empty */
  86. return -ENOTEMPTY;
  87. case LFS_ERR_BADF: /* Bad file number */
  88. return -EBADF;
  89. case LFS_ERR_FBIG: /* File too large */
  90. return -EFBIG;
  91. case LFS_ERR_INVAL: /* Invalid parameter */
  92. return -EINVAL;
  93. case LFS_ERR_NOSPC: /* No space left on device */
  94. return -ENOSPC;
  95. case LFS_ERR_NOMEM: /* No more memory available */
  96. return -ENOMEM;
  97. }
  98. }
  99. static int errno_to_lfs(int error)
  100. {
  101. if (error >= 0) {
  102. return LFS_ERR_OK;
  103. }
  104. switch (error) {
  105. default:
  106. case -EIO: /* Error during device operation */
  107. return LFS_ERR_IO;
  108. case -EFAULT: /* Corrupted */
  109. return LFS_ERR_CORRUPT;
  110. case -ENOENT: /* No directory entry */
  111. return LFS_ERR_NOENT;
  112. case -EEXIST: /* Entry already exists */
  113. return LFS_ERR_EXIST;
  114. case -ENOTDIR: /* Entry is not a dir */
  115. return LFS_ERR_NOTDIR;
  116. case -EISDIR: /* Entry is a dir */
  117. return LFS_ERR_ISDIR;
  118. case -ENOTEMPTY: /* Dir is not empty */
  119. return LFS_ERR_NOTEMPTY;
  120. case -EBADF: /* Bad file number */
  121. return LFS_ERR_BADF;
  122. case -EFBIG: /* File too large */
  123. return LFS_ERR_FBIG;
  124. case -EINVAL: /* Invalid parameter */
  125. return LFS_ERR_INVAL;
  126. case -ENOSPC: /* No space left on device */
  127. return LFS_ERR_NOSPC;
  128. case -ENOMEM: /* No more memory available */
  129. return LFS_ERR_NOMEM;
  130. }
  131. }
  132. static int lfs_api_read(const struct lfs_config *c, lfs_block_t block,
  133. lfs_off_t off, void *buffer, lfs_size_t size)
  134. {
  135. const struct lfs_dev *lfs_dev = c->context;
  136. size_t offset = lfs_dev->offset + block * c->block_size + off;
  137. int rc = flash_read(lfs_dev->dev, offset, buffer, size);
  138. return errno_to_lfs(rc);
  139. }
  140. static int lfs_api_prog(const struct lfs_config *c, lfs_block_t block,
  141. lfs_off_t off, const void *buffer, lfs_size_t size)
  142. {
  143. const struct lfs_dev *lfs_dev = c->context;
  144. uint64_t offset = lfs_dev->offset + block * c->block_size + off;
  145. int rc = flash_write(lfs_dev->dev, offset, buffer, size);
  146. return errno_to_lfs(rc);
  147. }
  148. static int lfs_api_erase(const struct lfs_config *c, lfs_block_t block)
  149. {
  150. const struct lfs_dev *lfs_dev = c->context;
  151. size_t offset = lfs_dev->offset + block * c->block_size;
  152. int rc = flash_erase(lfs_dev->dev, offset, c->block_size);
  153. return errno_to_lfs(rc);
  154. }
  155. static int lfs_api_sync(const struct lfs_config *c)
  156. {
  157. return LFS_ERR_OK;
  158. }
  159. static void release_file_data(struct fs_file_t *fp)
  160. {
  161. struct lfs_file_data *fdp = fp->filep;
  162. if (fdp->config.buffer) {
  163. fc_release(fdp->cache_block);
  164. }
  165. k_mem_slab_free(&file_data_pool, &fp->filep);
  166. fp->filep = NULL;
  167. }
  168. static int lfs_flags_from_zephyr(unsigned int zflags)
  169. {
  170. int flags = (zflags & FS_O_CREATE) ? LFS_O_CREAT : 0;
  171. /* LFS_O_READONLY and LFS_O_WRONLY can be selected at the same time,
  172. * this is not a mistake, together they create RDWR access.
  173. */
  174. flags |= (zflags & FS_O_READ) ? LFS_O_RDONLY : 0;
  175. flags |= (zflags & FS_O_WRITE) ? LFS_O_WRONLY : 0;
  176. flags |= (zflags & FS_O_APPEND) ? LFS_O_APPEND : 0;
  177. return flags;
  178. }
  179. static int littlefs_open(struct fs_file_t *fp, const char *path,
  180. fs_mode_t zflags)
  181. {
  182. struct fs_littlefs *fs = fp->mp->fs_data;
  183. struct lfs *lfs = &fs->lfs;
  184. int flags = lfs_flags_from_zephyr(zflags);
  185. int ret = k_mem_slab_alloc(&file_data_pool, &fp->filep, K_NO_WAIT);
  186. if (ret != 0) {
  187. return ret;
  188. }
  189. struct lfs_file_data *fdp = fp->filep;
  190. memset(fdp, 0, sizeof(*fdp));
  191. fdp->cache_block = fc_allocate(lfs->cfg->cache_size);
  192. if (fdp->cache_block == NULL) {
  193. ret = -ENOMEM;
  194. goto out;
  195. }
  196. fdp->config.buffer = fdp->cache_block;
  197. path = fs_impl_strip_prefix(path, fp->mp);
  198. fs_lock(fs);
  199. ret = lfs_file_opencfg(&fs->lfs, &fdp->file,
  200. path, flags, &fdp->config);
  201. fs_unlock(fs);
  202. out:
  203. if (ret < 0) {
  204. release_file_data(fp);
  205. }
  206. return lfs_to_errno(ret);
  207. }
  208. static int littlefs_close(struct fs_file_t *fp)
  209. {
  210. struct fs_littlefs *fs = fp->mp->fs_data;
  211. fs_lock(fs);
  212. int ret = lfs_file_close(&fs->lfs, LFS_FILEP(fp));
  213. fs_unlock(fs);
  214. release_file_data(fp);
  215. return lfs_to_errno(ret);
  216. }
  217. static int littlefs_unlink(struct fs_mount_t *mountp, const char *path)
  218. {
  219. struct fs_littlefs *fs = mountp->fs_data;
  220. path = fs_impl_strip_prefix(path, mountp);
  221. fs_lock(fs);
  222. int ret = lfs_remove(&fs->lfs, path);
  223. fs_unlock(fs);
  224. return lfs_to_errno(ret);
  225. }
  226. static int littlefs_rename(struct fs_mount_t *mountp, const char *from,
  227. const char *to)
  228. {
  229. struct fs_littlefs *fs = mountp->fs_data;
  230. from = fs_impl_strip_prefix(from, mountp);
  231. to = fs_impl_strip_prefix(to, mountp);
  232. fs_lock(fs);
  233. int ret = lfs_rename(&fs->lfs, from, to);
  234. fs_unlock(fs);
  235. return lfs_to_errno(ret);
  236. }
  237. static ssize_t littlefs_read(struct fs_file_t *fp, void *ptr, size_t len)
  238. {
  239. struct fs_littlefs *fs = fp->mp->fs_data;
  240. fs_lock(fs);
  241. ssize_t ret = lfs_file_read(&fs->lfs, LFS_FILEP(fp), ptr, len);
  242. fs_unlock(fs);
  243. return lfs_to_errno(ret);
  244. }
  245. static ssize_t littlefs_write(struct fs_file_t *fp, const void *ptr, size_t len)
  246. {
  247. struct fs_littlefs *fs = fp->mp->fs_data;
  248. fs_lock(fs);
  249. ssize_t ret = lfs_file_write(&fs->lfs, LFS_FILEP(fp), ptr, len);
  250. fs_unlock(fs);
  251. return lfs_to_errno(ret);
  252. }
  253. BUILD_ASSERT((FS_SEEK_SET == LFS_SEEK_SET)
  254. && (FS_SEEK_CUR == LFS_SEEK_CUR)
  255. && (FS_SEEK_END == LFS_SEEK_END));
  256. static int littlefs_seek(struct fs_file_t *fp, off_t off, int whence)
  257. {
  258. struct fs_littlefs *fs = fp->mp->fs_data;
  259. fs_lock(fs);
  260. off_t ret = lfs_file_seek(&fs->lfs, LFS_FILEP(fp), off, whence);
  261. fs_unlock(fs);
  262. if (ret >= 0) {
  263. ret = 0;
  264. }
  265. return lfs_to_errno(ret);
  266. }
  267. static off_t littlefs_tell(struct fs_file_t *fp)
  268. {
  269. struct fs_littlefs *fs = fp->mp->fs_data;
  270. fs_lock(fs);
  271. off_t ret = lfs_file_tell(&fs->lfs, LFS_FILEP(fp));
  272. fs_unlock(fs);
  273. return ret;
  274. }
  275. static int littlefs_truncate(struct fs_file_t *fp, off_t length)
  276. {
  277. struct fs_littlefs *fs = fp->mp->fs_data;
  278. fs_lock(fs);
  279. int ret = lfs_file_truncate(&fs->lfs, LFS_FILEP(fp), length);
  280. fs_unlock(fs);
  281. return lfs_to_errno(ret);
  282. }
  283. static int littlefs_sync(struct fs_file_t *fp)
  284. {
  285. struct fs_littlefs *fs = fp->mp->fs_data;
  286. fs_lock(fs);
  287. int ret = lfs_file_sync(&fs->lfs, LFS_FILEP(fp));
  288. fs_unlock(fs);
  289. return lfs_to_errno(ret);
  290. }
  291. static int littlefs_mkdir(struct fs_mount_t *mountp, const char *path)
  292. {
  293. struct fs_littlefs *fs = mountp->fs_data;
  294. path = fs_impl_strip_prefix(path, mountp);
  295. fs_lock(fs);
  296. int ret = lfs_mkdir(&fs->lfs, path);
  297. fs_unlock(fs);
  298. return lfs_to_errno(ret);
  299. }
  300. static int littlefs_opendir(struct fs_dir_t *dp, const char *path)
  301. {
  302. struct fs_littlefs *fs = dp->mp->fs_data;
  303. if (k_mem_slab_alloc(&lfs_dir_pool, &dp->dirp, K_NO_WAIT) != 0) {
  304. return -ENOMEM;
  305. }
  306. memset(dp->dirp, 0, sizeof(struct lfs_dir));
  307. path = fs_impl_strip_prefix(path, dp->mp);
  308. fs_lock(fs);
  309. int ret = lfs_dir_open(&fs->lfs, dp->dirp, path);
  310. fs_unlock(fs);
  311. if (ret < 0) {
  312. k_mem_slab_free(&lfs_dir_pool, &dp->dirp);
  313. }
  314. return lfs_to_errno(ret);
  315. }
  316. static void info_to_dirent(const struct lfs_info *info, struct fs_dirent *entry)
  317. {
  318. entry->type = ((info->type == LFS_TYPE_DIR) ?
  319. FS_DIR_ENTRY_DIR : FS_DIR_ENTRY_FILE);
  320. entry->size = info->size;
  321. strncpy(entry->name, info->name, sizeof(entry->name));
  322. entry->name[sizeof(entry->name) - 1] = '\0';
  323. }
  324. static int littlefs_readdir(struct fs_dir_t *dp, struct fs_dirent *entry)
  325. {
  326. struct fs_littlefs *fs = dp->mp->fs_data;
  327. fs_lock(fs);
  328. struct lfs_info info;
  329. int ret = lfs_dir_read(&fs->lfs, dp->dirp, &info);
  330. fs_unlock(fs);
  331. if (ret > 0) {
  332. info_to_dirent(&info, entry);
  333. ret = 0;
  334. } else if (ret == 0) {
  335. entry->name[0] = 0;
  336. }
  337. return lfs_to_errno(ret);
  338. }
  339. static int littlefs_closedir(struct fs_dir_t *dp)
  340. {
  341. struct fs_littlefs *fs = dp->mp->fs_data;
  342. fs_lock(fs);
  343. int ret = lfs_dir_close(&fs->lfs, dp->dirp);
  344. fs_unlock(fs);
  345. k_mem_slab_free(&lfs_dir_pool, &dp->dirp);
  346. return lfs_to_errno(ret);
  347. }
  348. static int littlefs_stat(struct fs_mount_t *mountp,
  349. const char *path, struct fs_dirent *entry)
  350. {
  351. struct fs_littlefs *fs = mountp->fs_data;
  352. path = fs_impl_strip_prefix(path, mountp);
  353. fs_lock(fs);
  354. struct lfs_info info;
  355. int ret = lfs_stat(&fs->lfs, path, &info);
  356. fs_unlock(fs);
  357. if (ret >= 0) {
  358. info_to_dirent(&info, entry);
  359. ret = 0;
  360. }
  361. return lfs_to_errno(ret);
  362. }
  363. static int littlefs_statvfs(struct fs_mount_t *mountp,
  364. const char *path, struct fs_statvfs *stat)
  365. {
  366. struct fs_littlefs *fs = mountp->fs_data;
  367. struct lfs *lfs = &fs->lfs;
  368. stat->f_bsize = lfs->cfg->prog_size;
  369. stat->f_frsize = lfs->cfg->block_size;
  370. stat->f_blocks = lfs->cfg->block_count;
  371. path = fs_impl_strip_prefix(path, mountp);
  372. fs_lock(fs);
  373. ssize_t ret = lfs_fs_size(lfs);
  374. fs_unlock(fs);
  375. if (ret >= 0) {
  376. stat->f_bfree = stat->f_blocks - ret;
  377. ret = 0;
  378. }
  379. return lfs_to_errno(ret);
  380. }
  381. static int lfs_get_dev(struct lfs_dev *lfs_dev, uint32_t file_id)
  382. {
  383. const struct partition_entry *parti;
  384. const struct device *dev = NULL;
  385. for(int i = 0; i < STORAGE_ID_MAX; i++){
  386. parti = partition_get_stf_part(i, file_id);
  387. if (parti) {
  388. dev = partition_get_storage_dev(parti);
  389. printk("disk type: %d file_id %d dev %p\n", i, file_id,dev);
  390. break;
  391. }
  392. }
  393. if (!dev || !parti || !lfs_dev) {
  394. printk("disk: dev error %p parti %p lfs_dev %p\n", dev, parti, lfs_dev);
  395. return -ENODEV;
  396. }
  397. lfs_dev->offset = parti->offset;
  398. lfs_dev->size = parti->size;
  399. lfs_dev->dev = (struct device *)dev;
  400. return 0;
  401. }
  402. static int littlefs_mount(struct fs_mount_t *mountp)
  403. {
  404. int ret;
  405. struct fs_littlefs *fs = mountp->fs_data;
  406. struct lfs_dev *lfs_dev = &fs->lfs_dev;
  407. uint32_t file_id = (uint32_t)mountp->storage_dev;
  408. LOG_INF("LittleFS version %u.%u, disk version %u.%u",
  409. LFS_VERSION_MAJOR, LFS_VERSION_MINOR,
  410. LFS_DISK_VERSION_MAJOR, LFS_DISK_VERSION_MINOR);
  411. if (lfs_dev->dev) {
  412. return -EBUSY;
  413. }
  414. /* Create and take mutex. */
  415. k_mutex_init(&fs->mutex);
  416. fs_lock(fs);
  417. /* Open device */
  418. ret = lfs_get_dev(lfs_dev, file_id);
  419. if (ret) {
  420. return -ENODEV;
  421. }
  422. LOG_DBG("FS disk %u at 0x%x for %u bytes",
  423. file_id, (uint32_t)lfs_dev->offset,
  424. (uint32_t)lfs_dev->size);
  425. BUILD_ASSERT(CONFIG_FS_LITTLEFS_READ_SIZE > 0);
  426. BUILD_ASSERT(CONFIG_FS_LITTLEFS_PROG_SIZE > 0);
  427. BUILD_ASSERT(CONFIG_FS_LITTLEFS_CACHE_SIZE > 0);
  428. BUILD_ASSERT(CONFIG_FS_LITTLEFS_LOOKAHEAD_SIZE > 0);
  429. BUILD_ASSERT((CONFIG_FS_LITTLEFS_LOOKAHEAD_SIZE % 8) == 0);
  430. BUILD_ASSERT((CONFIG_FS_LITTLEFS_CACHE_SIZE
  431. % CONFIG_FS_LITTLEFS_READ_SIZE) == 0);
  432. BUILD_ASSERT((CONFIG_FS_LITTLEFS_CACHE_SIZE
  433. % CONFIG_FS_LITTLEFS_PROG_SIZE) == 0);
  434. struct lfs_config *lcp = &fs->cfg;
  435. lfs_size_t read_size = lcp->read_size;
  436. if (read_size == 0) {
  437. read_size = CONFIG_FS_LITTLEFS_READ_SIZE;
  438. }
  439. lfs_size_t prog_size = lcp->prog_size;
  440. if (prog_size == 0) {
  441. prog_size = CONFIG_FS_LITTLEFS_PROG_SIZE;
  442. }
  443. /* Yes, you can override block size. */
  444. lfs_size_t block_size = lcp->block_size;
  445. if (block_size == 0) {
  446. block_size = CONFIG_FS_LITTLEFS_BLOCK_SIZE;
  447. }
  448. if (block_size == 0) {
  449. __ASSERT_NO_MSG(block_size != 0);
  450. ret = -EINVAL;
  451. goto out;
  452. }
  453. int32_t block_cycles = lcp->block_cycles;
  454. if (block_cycles == 0) {
  455. block_cycles = CONFIG_FS_LITTLEFS_BLOCK_CYCLES;
  456. }
  457. if (block_cycles <= 0) {
  458. /* Disable leveling (littlefs v2.1+ semantics) */
  459. block_cycles = -1;
  460. }
  461. lfs_size_t cache_size = lcp->cache_size;
  462. if (cache_size == 0) {
  463. cache_size = CONFIG_FS_LITTLEFS_CACHE_SIZE;
  464. }
  465. lfs_size_t lookahead_size = lcp->lookahead_size;
  466. if (lookahead_size == 0) {
  467. lookahead_size = CONFIG_FS_LITTLEFS_LOOKAHEAD_SIZE;
  468. }
  469. /* No, you don't get to override this. */
  470. lfs_size_t block_count = lfs_dev->size / block_size;
  471. LOG_INF("FS at %s:0x%x is %u 0x%x-byte blocks with %u cycle",
  472. log_strdup(lfs_dev->dev->name), (uint32_t)lfs_dev->offset,
  473. block_count, block_size, block_cycles);
  474. LOG_INF("sizes: rd %u ; pr %u ; ca %u ; la %u",
  475. read_size, prog_size, cache_size, lookahead_size);
  476. __ASSERT_NO_MSG(prog_size != 0);
  477. __ASSERT_NO_MSG(read_size != 0);
  478. __ASSERT_NO_MSG(cache_size != 0);
  479. __ASSERT_NO_MSG(block_size != 0);
  480. __ASSERT((lfs_dev->size % block_size) == 0,
  481. "partition size must be multiple of block size");
  482. __ASSERT((block_size % prog_size) == 0,
  483. "erase size must be multiple of write size");
  484. __ASSERT((block_size % cache_size) == 0,
  485. "cache size incompatible with block size");
  486. /* Set the validated/defaulted values. */
  487. lcp->context = (void *)lfs_dev;
  488. lcp->read = lfs_api_read;
  489. lcp->prog = lfs_api_prog;
  490. lcp->erase = lfs_api_erase;
  491. lcp->sync = lfs_api_sync;
  492. lcp->read_size = read_size;
  493. lcp->prog_size = prog_size;
  494. lcp->block_size = block_size;
  495. lcp->block_count = block_count;
  496. lcp->block_cycles = block_cycles;
  497. lcp->cache_size = cache_size;
  498. lcp->lookahead_size = lookahead_size;
  499. /* Mount it, formatting if needed. */
  500. ret = lfs_mount(&fs->lfs, &fs->cfg);
  501. if (ret < 0 &&
  502. (mountp->flags & FS_MOUNT_FLAG_NO_FORMAT) == 0) {
  503. LOG_WRN("can't mount (LFS %d); formatting", ret);
  504. if ((mountp->flags & FS_MOUNT_FLAG_READ_ONLY) == 0) {
  505. ret = lfs_format(&fs->lfs, &fs->cfg);
  506. if (ret < 0) {
  507. LOG_ERR("format failed (LFS %d)", ret);
  508. ret = lfs_to_errno(ret);
  509. goto out;
  510. }
  511. } else {
  512. LOG_ERR("can not format read-only system");
  513. ret = -EROFS;
  514. goto out;
  515. }
  516. ret = lfs_mount(&fs->lfs, &fs->cfg);
  517. if (ret < 0) {
  518. LOG_ERR("remount after format failed (LFS %d)", ret);
  519. ret = lfs_to_errno(ret);
  520. goto out;
  521. }
  522. }
  523. LOG_INF("%s mounted", log_strdup(mountp->mnt_point));
  524. out:
  525. if (ret < 0) {
  526. lfs_dev->dev = NULL;
  527. }
  528. fs_unlock(fs);
  529. return ret;
  530. }
  531. static int littlefs_unmount(struct fs_mount_t *mountp)
  532. {
  533. struct fs_littlefs *fs = mountp->fs_data;
  534. struct lfs_dev *lfs_dev = &fs->lfs_dev;
  535. fs_lock(fs);
  536. lfs_unmount(&fs->lfs);
  537. lfs_dev->dev = NULL;
  538. fs_unlock(fs);
  539. LOG_INF("%s unmounted", log_strdup(mountp->mnt_point));
  540. return 0;
  541. }
  542. /* File system interface */
  543. static const struct fs_file_system_t littlefs_fs = {
  544. .open = littlefs_open,
  545. .close = littlefs_close,
  546. .read = littlefs_read,
  547. .write = littlefs_write,
  548. .lseek = littlefs_seek,
  549. .tell = littlefs_tell,
  550. .truncate = littlefs_truncate,
  551. .sync = littlefs_sync,
  552. .opendir = littlefs_opendir,
  553. .readdir = littlefs_readdir,
  554. .closedir = littlefs_closedir,
  555. .mount = littlefs_mount,
  556. .unmount = littlefs_unmount,
  557. .unlink = littlefs_unlink,
  558. .rename = littlefs_rename,
  559. .mkdir = littlefs_mkdir,
  560. .stat = littlefs_stat,
  561. .statvfs = littlefs_statvfs,
  562. };
  563. static int littlefs_init(const struct device *dev)
  564. {
  565. ARG_UNUSED(dev);
  566. return fs_register(FS_LITTLEFS, &littlefs_fs);
  567. }
  568. SYS_INIT(littlefs_init, POST_KERNEL, 99);