mirror of
				https://github.com/eledio-devices/thirdparty-littlefs.git
				synced 2025-10-31 08:42:40 +01:00 
			
		
		
		
	Combined superblock scan and fetch of xored-globals during mount
Conceptually these are two separate operations. However, they are both only needed during mount, both require iteration over the linked-list of metadata-pairs, and both are independent from each other. Combining these into one gives us a nice code savings. Additionally, this greatly simplifies the lookup of the root directory. Initially we used a flag to indicate which superblock was root, since we didn't want to fetch more pairs than we needed to. But since we're going to fetch all metadata-pairs anyways, we can just use the last superblock we find as the indicator of our root directory.
This commit is contained in:
		
							
								
								
									
										157
									
								
								lfs.c
									
									
									
									
									
								
							
							
						
						
									
										157
									
								
								lfs.c
									
									
									
									
									
								
							| @@ -3116,7 +3116,7 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) { | |||||||
|  |  | ||||||
|     lfs_superblock_tole32(&superblock); |     lfs_superblock_tole32(&superblock); | ||||||
|     err = lfs_dir_commit(lfs, &root, |     err = lfs_dir_commit(lfs, &root, | ||||||
|             LFS_MKATTR(LFS_TYPE_ROOT, 0, &superblock, sizeof(superblock), |             LFS_MKATTR(LFS_TYPE_SUPERBLOCK, 0, &superblock, sizeof(superblock), | ||||||
|             NULL)); |             NULL)); | ||||||
|     if (err) { |     if (err) { | ||||||
|         goto cleanup; |         goto cleanup; | ||||||
| @@ -3139,97 +3139,94 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { | |||||||
|         return err; |         return err; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // find root/superblock |     // scan directory blocks for superblock and any global updates | ||||||
|     lfs_mdir_t root; |  | ||||||
|     lfs_superblock_t superblock; |  | ||||||
|     lfs_stag_t tag = lfs_dir_findmatch(lfs, |  | ||||||
|             &root, (const lfs_block_t[2]){0, 1}, false, 0x7fc00000, |  | ||||||
|             LFS_MKTAG(LFS_TYPE_ROOT, 0, 8), |  | ||||||
|             lfs_dir_find_match, &(struct lfs_dir_find_match){ |  | ||||||
|                 lfs, "littlefs", 8}); |  | ||||||
|     if (tag < 0) { |  | ||||||
|         err = tag; |  | ||||||
|         goto cleanup; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     lfs_stag_t res = lfs_dir_get(lfs, &root, 0x7f800000, |  | ||||||
|             LFS_MKTAG(LFS_TYPE_SUPERBLOCK, 0, sizeof(superblock)), |  | ||||||
|             &superblock); |  | ||||||
|     if (res < 0) { |  | ||||||
|         err = res; |  | ||||||
|         goto cleanup; |  | ||||||
|     } |  | ||||||
|     lfs_superblock_fromle32(&superblock); |  | ||||||
|  |  | ||||||
|     lfs->root[0] = root.pair[0]; |  | ||||||
|     lfs->root[1] = root.pair[1]; |  | ||||||
|  |  | ||||||
|     // check version |  | ||||||
|     uint16_t major_version = (0xffff & (superblock.version >> 16)); |  | ||||||
|     uint16_t minor_version = (0xffff & (superblock.version >>  0)); |  | ||||||
|     if ((major_version != LFS_DISK_VERSION_MAJOR || |  | ||||||
|          minor_version > LFS_DISK_VERSION_MINOR)) { |  | ||||||
|         LFS_ERROR("Invalid version %"PRIu32".%"PRIu32, |  | ||||||
|                 major_version, minor_version); |  | ||||||
|         err = LFS_ERR_INVAL; |  | ||||||
|         goto cleanup; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // check superblock configuration |  | ||||||
|     if (superblock.attr_max) { |  | ||||||
|         if (superblock.attr_max > lfs->attr_max) { |  | ||||||
|             LFS_ERROR("Unsupported attr_max (%"PRIu32" > %"PRIu32")", |  | ||||||
|                     superblock.attr_max, lfs->attr_max); |  | ||||||
|             err = LFS_ERR_INVAL; |  | ||||||
|             goto cleanup; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         lfs->attr_max = superblock.attr_max; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if (superblock.name_max) { |  | ||||||
|         if (superblock.name_max > lfs->name_max) { |  | ||||||
|             LFS_ERROR("Unsupported name_max (%"PRIu32" > %"PRIu32")", |  | ||||||
|                     superblock.name_max, lfs->name_max); |  | ||||||
|             err = LFS_ERR_INVAL; |  | ||||||
|             goto cleanup; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         lfs->name_max = superblock.name_max; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if (superblock.inline_max) { |  | ||||||
|         if (superblock.inline_max > lfs->inline_max) { |  | ||||||
|             LFS_ERROR("Unsupported inline_max (%"PRIu32" > %"PRIu32")", |  | ||||||
|                     superblock.inline_max, lfs->inline_max); |  | ||||||
|             err = LFS_ERR_INVAL; |  | ||||||
|             goto cleanup; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         lfs->inline_max = superblock.inline_max; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // scan for any global updates |  | ||||||
|     lfs_mdir_t dir = {.tail = {0, 1}}; |     lfs_mdir_t dir = {.tail = {0, 1}}; | ||||||
|     while (!lfs_pair_isnull(dir.tail)) { |     while (!lfs_pair_isnull(dir.tail)) { | ||||||
|         res = lfs_dir_fetchmatch(lfs, &dir, dir.tail, 0x7c000000, |         // fetch next block in tail list | ||||||
|                 LFS_MKTAG(LFS_TYPE_GLOBALS, 0, 10),  NULL, NULL); |         lfs_stag_t res = lfs_dir_fetchmatch(lfs, &dir, dir.tail, 0x7fc00000, | ||||||
|  |                 LFS_MKTAG(LFS_TYPE_SUPERBLOCK, 0, 8), | ||||||
|  |                 lfs_dir_find_match, &(struct lfs_dir_find_match){ | ||||||
|  |                     lfs, "littlefs", 8}); | ||||||
|         if (res < 0) { |         if (res < 0) { | ||||||
|             err = LFS_ERR_INVAL; |             err = res; | ||||||
|             goto cleanup; |             goto cleanup; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         // has superblock? | ||||||
|         if (res) { |         if (res) { | ||||||
|             lfs_global_t locals; |             // update root | ||||||
|             res = lfs_dir_get(lfs, &dir, 0x7c000000, |             lfs->root[0] = dir.pair[0]; | ||||||
|                     LFS_MKTAG(LFS_TYPE_GLOBALS, 0, 10), &locals); |             lfs->root[1] = dir.pair[1]; | ||||||
|  |  | ||||||
|  |             // grab superblock | ||||||
|  |             lfs_superblock_t superblock; | ||||||
|  |             res = lfs_dir_get(lfs, &dir, 0x7f800000, | ||||||
|  |                     LFS_MKTAG(LFS_TYPE_SUPERBLOCK, 0, sizeof(superblock)), | ||||||
|  |                     &superblock); | ||||||
|             if (res < 0) { |             if (res < 0) { | ||||||
|                 err = res; |                 err = res; | ||||||
|                 goto cleanup; |                 goto cleanup; | ||||||
|             } |             } | ||||||
|             locals.l.deorphaned = (lfs_tag_type(res) & 1); |             lfs_superblock_fromle32(&superblock); | ||||||
|  |  | ||||||
|             // xor together indirect deletes |             // check version | ||||||
|  |             uint16_t major_version = (0xffff & (superblock.version >> 16)); | ||||||
|  |             uint16_t minor_version = (0xffff & (superblock.version >>  0)); | ||||||
|  |             if ((major_version != LFS_DISK_VERSION_MAJOR || | ||||||
|  |                  minor_version > LFS_DISK_VERSION_MINOR)) { | ||||||
|  |                 LFS_ERROR("Invalid version %"PRIu32".%"PRIu32, | ||||||
|  |                         major_version, minor_version); | ||||||
|  |                 err = LFS_ERR_INVAL; | ||||||
|  |                 goto cleanup; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // check superblock configuration | ||||||
|  |             if (superblock.attr_max) { | ||||||
|  |                 if (superblock.attr_max > lfs->attr_max) { | ||||||
|  |                     LFS_ERROR("Unsupported attr_max (%"PRIu32" > %"PRIu32")", | ||||||
|  |                             superblock.attr_max, lfs->attr_max); | ||||||
|  |                     err = LFS_ERR_INVAL; | ||||||
|  |                     goto cleanup; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 lfs->attr_max = superblock.attr_max; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (superblock.name_max) { | ||||||
|  |                 if (superblock.name_max > lfs->name_max) { | ||||||
|  |                     LFS_ERROR("Unsupported name_max (%"PRIu32" > %"PRIu32")", | ||||||
|  |                             superblock.name_max, lfs->name_max); | ||||||
|  |                     err = LFS_ERR_INVAL; | ||||||
|  |                     goto cleanup; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 lfs->name_max = superblock.name_max; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (superblock.inline_max) { | ||||||
|  |                 if (superblock.inline_max > lfs->inline_max) { | ||||||
|  |                     LFS_ERROR("Unsupported inline_max (%"PRIu32" > %"PRIu32")", | ||||||
|  |                             superblock.inline_max, lfs->inline_max); | ||||||
|  |                     err = LFS_ERR_INVAL; | ||||||
|  |                     goto cleanup; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 lfs->inline_max = superblock.inline_max; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // has globals? | ||||||
|  |         lfs_global_t locals; | ||||||
|  |         res = lfs_dir_get(lfs, &dir, 0x7c000000, | ||||||
|  |                 LFS_MKTAG(LFS_TYPE_GLOBALS, 0, 10), &locals); | ||||||
|  |         if (res < 0 && res != LFS_ERR_NOENT) { | ||||||
|  |             err = res; | ||||||
|  |             goto cleanup; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (res != LFS_ERR_NOENT) { | ||||||
|  |             locals.l.deorphaned = (lfs_tag_type(res) & 1); | ||||||
|  |             // xor together to find resulting globals | ||||||
|             lfs_global_xor(&lfs->locals, &locals); |             lfs_global_xor(&lfs->locals, &locals); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|   | |||||||
							
								
								
									
										8
									
								
								lfs.h
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								lfs.h
									
									
									
									
									
								
							| @@ -94,27 +94,25 @@ enum lfs_type { | |||||||
|  |  | ||||||
|     // internally used types |     // internally used types | ||||||
|     LFS_TYPE_USER           = 0x100, |     LFS_TYPE_USER           = 0x100, | ||||||
|     LFS_TYPE_SUPERBLOCK     = 0x001, |  | ||||||
|     LFS_TYPE_ROOT           = 0x000, |  | ||||||
|     LFS_TYPE_NAME           = 0x000, |     LFS_TYPE_NAME           = 0x000, | ||||||
|     LFS_TYPE_DELETE         = 0x020, |     LFS_TYPE_DELETE         = 0x020, | ||||||
|     LFS_TYPE_STRUCT         = 0x040, |     LFS_TYPE_STRUCT         = 0x040, | ||||||
|     LFS_TYPE_GLOBALS        = 0x0e0, |  | ||||||
|     LFS_TYPE_TAIL           = 0x080, |     LFS_TYPE_TAIL           = 0x080, | ||||||
|     LFS_TYPE_SOFTTAIL       = 0x080, |     LFS_TYPE_SOFTTAIL       = 0x080, | ||||||
|     LFS_TYPE_HARDTAIL       = 0x081, |     LFS_TYPE_HARDTAIL       = 0x081, | ||||||
|     LFS_TYPE_CRC            = 0x0a0, |     LFS_TYPE_CRC            = 0x0a0, | ||||||
|  |     LFS_TYPE_SUPERBLOCK     = 0x001, | ||||||
|  |     LFS_TYPE_GLOBALS        = 0x0e0, | ||||||
|  |  | ||||||
|     LFS_TYPE_DIRSTRUCT      = 0x040, |     LFS_TYPE_DIRSTRUCT      = 0x040, | ||||||
|     LFS_TYPE_INLINESTRUCT   = 0x041, |     LFS_TYPE_INLINESTRUCT   = 0x041, | ||||||
|     LFS_TYPE_CTZSTRUCT      = 0x042, |     LFS_TYPE_CTZSTRUCT      = 0x042, | ||||||
|  |  | ||||||
|     // internal chip sources |     // internal chip sources | ||||||
|     LFS_FROM_REGION         = 0x000, |     LFS_FROM_MEM            = 0x000, | ||||||
|     LFS_FROM_DISK           = 0x200, |     LFS_FROM_DISK           = 0x200, | ||||||
|     LFS_FROM_MOVE           = 0x0c1, |     LFS_FROM_MOVE           = 0x0c1, | ||||||
|     LFS_FROM_USERATTRS      = 0x0c2, |     LFS_FROM_USERATTRS      = 0x0c2, | ||||||
|     LFS_FROM_SUPERBLOCK     = 0x0c3, |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
| // File open flags | // File open flags | ||||||
|   | |||||||
| @@ -7,7 +7,6 @@ TYPES = { | |||||||
|     (0x1ff, 0x002): 'reg', |     (0x1ff, 0x002): 'reg', | ||||||
|     (0x1ff, 0x003): 'dir', |     (0x1ff, 0x003): 'dir', | ||||||
|     (0x1ff, 0x001): 'superblock', |     (0x1ff, 0x001): 'superblock', | ||||||
|     (0x1ff, 0x000): 'root', |  | ||||||
|     (0x1ff, 0x020): 'delete', |     (0x1ff, 0x020): 'delete', | ||||||
|     (0x1f0, 0x0e0): 'globals', |     (0x1f0, 0x0e0): 'globals', | ||||||
|     (0x1ff, 0x080): 'tail soft', |     (0x1ff, 0x080): 'tail soft', | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user