mirror of
				https://github.com/eledio-devices/thirdparty-littlefs.git
				synced 2025-10-31 00:32:38 +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); | ||||
|     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)); | ||||
|     if (err) { | ||||
|         goto cleanup; | ||||
| @@ -3139,97 +3139,94 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { | ||||
|         return err; | ||||
|     } | ||||
|  | ||||
|     // find root/superblock | ||||
|     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 | ||||
|     // scan directory blocks for superblock and any global updates | ||||
|     lfs_mdir_t dir = {.tail = {0, 1}}; | ||||
|     while (!lfs_pair_isnull(dir.tail)) { | ||||
|         res = lfs_dir_fetchmatch(lfs, &dir, dir.tail, 0x7c000000, | ||||
|                 LFS_MKTAG(LFS_TYPE_GLOBALS, 0, 10),  NULL, NULL); | ||||
|         // fetch next block in tail list | ||||
|         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) { | ||||
|             err = LFS_ERR_INVAL; | ||||
|             err = res; | ||||
|             goto cleanup; | ||||
|         } | ||||
|  | ||||
|         // has superblock? | ||||
|         if (res) { | ||||
|             lfs_global_t locals; | ||||
|             res = lfs_dir_get(lfs, &dir, 0x7c000000, | ||||
|                     LFS_MKTAG(LFS_TYPE_GLOBALS, 0, 10), &locals); | ||||
|             // update root | ||||
|             lfs->root[0] = dir.pair[0]; | ||||
|             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) { | ||||
|                 err = res; | ||||
|                 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); | ||||
|         } | ||||
|     } | ||||
|   | ||||
							
								
								
									
										8
									
								
								lfs.h
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								lfs.h
									
									
									
									
									
								
							| @@ -94,27 +94,25 @@ enum lfs_type { | ||||
|  | ||||
|     // internally used types | ||||
|     LFS_TYPE_USER           = 0x100, | ||||
|     LFS_TYPE_SUPERBLOCK     = 0x001, | ||||
|     LFS_TYPE_ROOT           = 0x000, | ||||
|     LFS_TYPE_NAME           = 0x000, | ||||
|     LFS_TYPE_DELETE         = 0x020, | ||||
|     LFS_TYPE_STRUCT         = 0x040, | ||||
|     LFS_TYPE_GLOBALS        = 0x0e0, | ||||
|     LFS_TYPE_TAIL           = 0x080, | ||||
|     LFS_TYPE_SOFTTAIL       = 0x080, | ||||
|     LFS_TYPE_HARDTAIL       = 0x081, | ||||
|     LFS_TYPE_CRC            = 0x0a0, | ||||
|     LFS_TYPE_SUPERBLOCK     = 0x001, | ||||
|     LFS_TYPE_GLOBALS        = 0x0e0, | ||||
|  | ||||
|     LFS_TYPE_DIRSTRUCT      = 0x040, | ||||
|     LFS_TYPE_INLINESTRUCT   = 0x041, | ||||
|     LFS_TYPE_CTZSTRUCT      = 0x042, | ||||
|  | ||||
|     // internal chip sources | ||||
|     LFS_FROM_REGION         = 0x000, | ||||
|     LFS_FROM_MEM            = 0x000, | ||||
|     LFS_FROM_DISK           = 0x200, | ||||
|     LFS_FROM_MOVE           = 0x0c1, | ||||
|     LFS_FROM_USERATTRS      = 0x0c2, | ||||
|     LFS_FROM_SUPERBLOCK     = 0x0c3, | ||||
| }; | ||||
|  | ||||
| // File open flags | ||||
|   | ||||
| @@ -7,7 +7,6 @@ TYPES = { | ||||
|     (0x1ff, 0x002): 'reg', | ||||
|     (0x1ff, 0x003): 'dir', | ||||
|     (0x1ff, 0x001): 'superblock', | ||||
|     (0x1ff, 0x000): 'root', | ||||
|     (0x1ff, 0x020): 'delete', | ||||
|     (0x1f0, 0x0e0): 'globals', | ||||
|     (0x1ff, 0x080): 'tail soft', | ||||
|   | ||||
		Reference in New Issue
	
	Block a user