@@ -377,6 +377,25 @@ static void lfs_ctz_tole32(struct lfs_ctz *ctz) {
377
377
ctz -> size = lfs_tole32 (ctz -> size );
378
378
}
379
379
380
+ static inline void lfs_superblock_fromle32 (lfs_superblock_t * superblock ) {
381
+ superblock -> version = lfs_fromle32 (superblock -> version );
382
+ superblock -> block_size = lfs_fromle32 (superblock -> block_size );
383
+ superblock -> block_count = lfs_fromle32 (superblock -> block_count );
384
+ superblock -> inline_max = lfs_fromle32 (superblock -> inline_max );
385
+ superblock -> attr_max = lfs_fromle32 (superblock -> attr_max );
386
+ superblock -> name_max = lfs_fromle32 (superblock -> name_max );
387
+ }
388
+
389
+ static inline void lfs_superblock_tole32 (lfs_superblock_t * superblock ) {
390
+ superblock -> version = lfs_tole32 (superblock -> version );
391
+ superblock -> block_size = lfs_tole32 (superblock -> block_size );
392
+ superblock -> block_count = lfs_tole32 (superblock -> block_count );
393
+ superblock -> inline_max = lfs_tole32 (superblock -> inline_max );
394
+ superblock -> attr_max = lfs_tole32 (superblock -> attr_max );
395
+ superblock -> name_max = lfs_tole32 (superblock -> name_max );
396
+ }
397
+
398
+
380
399
381
400
/// Entry tag operations ///
382
401
#define LFS_MKTAG (type , id , size ) \
@@ -524,15 +543,15 @@ static int lfs_commit_move(lfs_t *lfs, struct lfs_commit *commit,
524
543
525
544
static int lfs_commit_attr (lfs_t * lfs , struct lfs_commit * commit ,
526
545
uint32_t tag , const void * buffer ) {
527
- if (lfs_tag_type (tag ) == LFS_FROM_ATTRS ) {
528
- // special case for custom attributes
529
- return lfs_commit_attrs (lfs , commit ,
530
- lfs_tag_id (tag ), buffer );
531
- } else if (lfs_tag_type (tag ) == LFS_FROM_MOVE ) {
546
+ if (lfs_tag_subtype (tag ) == LFS_FROM_MOVE ) {
532
547
// special case for moves
533
548
return lfs_commit_move (lfs , commit ,
534
549
lfs_tag_size (tag ), lfs_tag_id (tag ),
535
550
buffer , NULL );
551
+ } else if (lfs_tag_subtype (tag ) == LFS_FROM_ATTRS ) {
552
+ // special case for custom attributes
553
+ return lfs_commit_attrs (lfs , commit ,
554
+ lfs_tag_id (tag ), buffer );
536
555
}
537
556
538
557
// check if we fit
@@ -628,7 +647,8 @@ static int lfs_commit_move(lfs_t *lfs, struct lfs_commit *commit,
628
647
tag |= 0x80000000 ;
629
648
}
630
649
631
- if (lfs_tag_type (tag ) == LFS_TYPE_DELETE && lfs_tag_id (tag ) <= fromid ) {
650
+ if (lfs_tag_type (tag ) == LFS_TYPE_DELETE &&
651
+ lfs_tag_id (tag ) <= fromid ) {
632
652
// something was deleted, we need to move around it
633
653
fromid += 1 ;
634
654
} else if (lfs_tag_id (tag ) != fromid ) {
@@ -667,8 +687,8 @@ static int lfs_commit_globals(lfs_t *lfs, struct lfs_commit *commit,
667
687
668
688
lfs_global_xor (locals , & lfs -> locals );
669
689
int err = lfs_commit_attr (lfs , commit ,
670
- LFS_MKTAG (LFS_TYPE_GLOBALS + locals -> s .deorphaned ,
671
- 0x3ff , sizeof ( lfs_global_t )), locals );
690
+ LFS_MKTAG (LFS_TYPE_GLOBALS + locals -> s .deorphaned , 0x3ff , 10 ),
691
+ locals );
672
692
lfs_global_xor (locals , & lfs -> locals );
673
693
return err ;
674
694
}
@@ -726,7 +746,7 @@ static int lfs_commit_crc(lfs_t *lfs, struct lfs_commit *commit) {
726
746
727
747
// internal dir operations
728
748
static int lfs_dir_alloc (lfs_t * lfs , lfs_mdir_t * dir ) {
729
- // allocate pair of dir blocks (backwards, so we write to block 1 first)
749
+ // allocate pair of dir blocks (backwards, so we write block 1 first)
730
750
for (int i = 0 ; i < 2 ; i ++ ) {
731
751
int err = lfs_alloc (lfs , & dir -> pair [(i + 1 )%2 ]);
732
752
if (err ) {
@@ -756,10 +776,9 @@ static int lfs_dir_alloc(lfs_t *lfs, lfs_mdir_t *dir) {
756
776
return 0 ;
757
777
}
758
778
759
- static int32_t lfs_dir_find (lfs_t * lfs ,
779
+ static int32_t lfs_dir_fetchmatch (lfs_t * lfs ,
760
780
lfs_mdir_t * dir , const lfs_block_t pair [2 ],
761
- uint32_t findmask , uint32_t findtag ,
762
- const void * findbuffer ) {
781
+ uint32_t findmask , uint32_t findtag , const void * findbuffer ) {
763
782
dir -> pair [0 ] = pair [0 ];
764
783
dir -> pair [1 ] = pair [1 ];
765
784
int32_t foundtag = LFS_ERR_NOENT ;
@@ -887,7 +906,7 @@ static int32_t lfs_dir_find(lfs_t *lfs,
887
906
} else if (lfs_tag_subtype (tag ) == LFS_TYPE_GLOBALS ) {
888
907
templocals .s .deorphaned = (lfs_tag_type (tag ) & 1 );
889
908
err = lfs_bd_read (lfs , dir -> pair [0 ], off + sizeof (tag ),
890
- & templocals , sizeof ( templocals ) );
909
+ & templocals , 10 );
891
910
if (err ) {
892
911
if (err == LFS_ERR_CORRUPT ) {
893
912
dir -> erased = false;
@@ -906,7 +925,7 @@ static int32_t lfs_dir_find(lfs_t *lfs,
906
925
}
907
926
} else if ((tag & findmask ) == (findtag & findmask )) {
908
927
int res = lfs_bd_cmp (lfs , dir -> pair [0 ], off + sizeof (tag ),
909
- findbuffer , lfs_tag_size (tag ));
928
+ findbuffer , lfs_tag_size (findtag ));
910
929
if (res < 0 ) {
911
930
if (res == LFS_ERR_CORRUPT ) {
912
931
dir -> erased = false;
@@ -953,14 +972,32 @@ static int32_t lfs_dir_find(lfs_t *lfs,
953
972
954
973
static int lfs_dir_fetch (lfs_t * lfs ,
955
974
lfs_mdir_t * dir , const lfs_block_t pair [2 ]) {
956
- int32_t res = lfs_dir_find (lfs , dir , pair , 0xffffffff , 0xffffffff , NULL );
975
+ int32_t res = lfs_dir_fetchmatch (lfs , dir , pair ,
976
+ 0xffffffff , 0xffffffff , NULL );
957
977
if (res < 0 && res != LFS_ERR_NOENT ) {
958
978
return res ;
959
979
}
960
980
961
981
return 0 ;
962
982
}
963
983
984
+ static int32_t lfs_dir_find (lfs_t * lfs ,
985
+ lfs_mdir_t * dir , const lfs_block_t pair [2 ], bool fs ,
986
+ uint32_t findmask , uint32_t findtag , const void * findbuffer ) {
987
+ dir -> split = true;
988
+ dir -> tail [0 ] = pair [0 ];
989
+ dir -> tail [1 ] = pair [1 ];
990
+ while ((dir -> split || fs ) && !lfs_pair_isnull (dir -> tail )) {
991
+ int32_t tag = lfs_dir_fetchmatch (lfs , dir , dir -> tail ,
992
+ findmask , findtag , findbuffer );
993
+ if (tag != LFS_ERR_NOENT ) {
994
+ return tag ;
995
+ }
996
+ }
997
+
998
+ return LFS_ERR_NOENT ;
999
+ }
1000
+
964
1001
static int32_t lfs_dir_get (lfs_t * lfs , lfs_mdir_t * dir ,
965
1002
uint32_t getmask , uint32_t gettag , void * buffer ) {
966
1003
int32_t getdiff = 0 ;
@@ -979,6 +1016,8 @@ static int lfs_dir_compact(lfs_t *lfs,
979
1016
lfs_mdir_t * source , uint16_t begin , uint16_t end ) {
980
1017
// save some state in case block is bad
981
1018
const lfs_block_t oldpair [2 ] = {dir -> pair [1 ], dir -> pair [0 ]};
1019
+ int16_t ack ;
1020
+ bool expanding = false;
982
1021
bool relocated = false;
983
1022
984
1023
// There's nothing special about our global delta, so feed it back
@@ -989,9 +1028,25 @@ static int lfs_dir_compact(lfs_t *lfs,
989
1028
// increment revision count
990
1029
dir -> rev += 1 ;
991
1030
1031
+ if (lfs_pair_cmp (dir -> pair , (const lfs_block_t [2 ]){0 , 1 }) == 0 &&
1032
+ dir -> rev % 16 == 0 ) {
1033
+ // we're writing too much to the superblock, should we expand?
1034
+ lfs_ssize_t res = lfs_fs_size (lfs );
1035
+ if (res < 0 ) {
1036
+ return res ;
1037
+ }
1038
+
1039
+ // do we have enough space to expand?
1040
+ if (res < lfs -> cfg -> block_count ) {
1041
+ expanding = (lfs_pair_cmp (dir -> pair , lfs -> root ) != 0 );
1042
+ ack = 0 ;
1043
+ goto split ;
1044
+ }
1045
+ }
1046
+
992
1047
while (true) {
993
1048
// last complete id
994
- int16_t ack = -1 ;
1049
+ ack = -1 ;
995
1050
dir -> count = end - begin ;
996
1051
997
1052
if (true) {
@@ -1111,7 +1166,7 @@ static int lfs_dir_compact(lfs_t *lfs,
1111
1166
tail .tail [0 ] = dir -> tail [0 ];
1112
1167
tail .tail [1 ] = dir -> tail [1 ];
1113
1168
1114
- err = lfs_dir_compact (lfs , & tail , attrs , dir , ack + 1 , end );
1169
+ err = lfs_dir_compact (lfs , & tail , attrs , dir , ack + 1 - expanding , end );
1115
1170
if (err ) {
1116
1171
return err ;
1117
1172
}
@@ -1390,25 +1445,10 @@ static int32_t lfs_dir_lookup(lfs_t *lfs, lfs_mdir_t *dir, const char **path) {
1390
1445
}
1391
1446
1392
1447
// find entry matching name
1393
- while (true) {
1394
- tag = lfs_dir_find (lfs , dir , pair , 0x7c000fff ,
1395
- LFS_MKTAG (LFS_TYPE_NAME , 0 , namelen ), name );
1396
- if (tag < 0 && tag != LFS_ERR_NOENT ) {
1397
- return tag ;
1398
- }
1399
-
1400
- if (tag != LFS_ERR_NOENT ) {
1401
- // found it
1402
- break ;
1403
- }
1404
-
1405
- if (!dir -> split ) {
1406
- // couldn't find it
1407
- return LFS_ERR_NOENT ;
1408
- }
1409
-
1410
- pair [0 ] = dir -> tail [0 ];
1411
- pair [1 ] = dir -> tail [1 ];
1448
+ tag = lfs_dir_find (lfs , dir , pair , false, 0x7c000fff ,
1449
+ LFS_MKTAG (LFS_TYPE_NAME , 0 , namelen ), name );
1450
+ if (tag < 0 ) {
1451
+ return tag ;
1412
1452
}
1413
1453
1414
1454
// to next name
@@ -2721,24 +2761,6 @@ int lfs_setattr(lfs_t *lfs, const char *path,
2721
2761
2722
2762
2723
2763
/// Filesystem operations ///
2724
- static inline void lfs_superblockfromle32 (lfs_superblock_t * superblock ) {
2725
- superblock -> version = lfs_fromle32 (superblock -> version );
2726
- superblock -> block_size = lfs_fromle32 (superblock -> block_size );
2727
- superblock -> block_count = lfs_fromle32 (superblock -> block_count );
2728
- superblock -> inline_max = lfs_fromle32 (superblock -> inline_max );
2729
- superblock -> attr_max = lfs_fromle32 (superblock -> attr_max );
2730
- superblock -> name_max = lfs_fromle32 (superblock -> name_max );
2731
- }
2732
-
2733
- static inline void lfs_superblocktole32 (lfs_superblock_t * superblock ) {
2734
- superblock -> version = lfs_tole32 (superblock -> version );
2735
- superblock -> block_size = lfs_tole32 (superblock -> block_size );
2736
- superblock -> block_count = lfs_tole32 (superblock -> block_count );
2737
- superblock -> inline_max = lfs_tole32 (superblock -> inline_max );
2738
- superblock -> attr_max = lfs_tole32 (superblock -> attr_max );
2739
- superblock -> name_max = lfs_tole32 (superblock -> name_max );
2740
- }
2741
-
2742
2764
static int lfs_init (lfs_t * lfs , const struct lfs_config * cfg ) {
2743
2765
lfs -> cfg = cfg ;
2744
2766
int err = 0 ;
@@ -2859,30 +2881,13 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) {
2859
2881
lfs -> free .i = 0 ;
2860
2882
lfs_alloc_ack (lfs );
2861
2883
2862
- // create superblock dir
2863
- lfs_mdir_t dir ;
2864
- err = lfs_dir_alloc (lfs , & dir );
2865
- if (err ) {
2866
- goto cleanup ;
2867
- }
2868
-
2869
- // write root directory
2884
+ // create root dir
2870
2885
lfs_mdir_t root ;
2871
2886
err = lfs_dir_alloc (lfs , & root );
2872
2887
if (err ) {
2873
2888
goto cleanup ;
2874
2889
}
2875
2890
2876
- err = lfs_dir_commit (lfs , & root , NULL );
2877
- if (err ) {
2878
- goto cleanup ;
2879
- }
2880
-
2881
- lfs -> root [0 ] = root .pair [0 ];
2882
- lfs -> root [1 ] = root .pair [1 ];
2883
- dir .tail [0 ] = lfs -> root [0 ];
2884
- dir .tail [1 ] = lfs -> root [1 ];
2885
-
2886
2891
// write one superblock
2887
2892
lfs_superblock_t superblock = {
2888
2893
.magic = {"littlefs" },
@@ -2895,20 +2900,17 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) {
2895
2900
.inline_max = lfs -> inline_max ,
2896
2901
};
2897
2902
2898
- lfs_superblocktole32 (& superblock );
2899
- lfs_pair_tole32 (lfs -> root );
2900
- err = lfs_dir_commit (lfs , & dir ,
2903
+ lfs_superblock_tole32 (& superblock );
2904
+ err = lfs_dir_commit (lfs , & root ,
2901
2905
LFS_MKATTR (LFS_TYPE_SUPERBLOCK , 0 , & superblock , sizeof (superblock ),
2902
- LFS_MKATTR (LFS_TYPE_DIRSTRUCT , 0 , lfs -> root , sizeof ( lfs -> root ) ,
2906
+ LFS_MKATTR (LFS_TYPE_ROOT , 1 , NULL , 0 ,
2903
2907
NULL )));
2904
- lfs_pair_fromle32 (lfs -> root );
2905
- lfs_superblockfromle32 (& superblock );
2906
2908
if (err ) {
2907
2909
goto cleanup ;
2908
2910
}
2909
2911
2910
2912
// sanity check that fetch works
2911
- err = lfs_dir_fetch (lfs , & dir , (const lfs_block_t [2 ]){0 , 1 });
2913
+ err = lfs_dir_fetch (lfs , & root , (const lfs_block_t [2 ]){0 , 1 });
2912
2914
if (err ) {
2913
2915
goto cleanup ;
2914
2916
}
@@ -2931,27 +2933,34 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
2931
2933
lfs_alloc_ack (lfs );
2932
2934
2933
2935
// load superblock
2934
- lfs_mdir_t superdir ;
2935
- err = lfs_dir_fetch (lfs , & superdir , (const lfs_block_t [2 ]){0 , 1 });
2936
+ lfs_mdir_t root ;
2937
+ err = lfs_dir_fetch (lfs , & root , (const lfs_block_t [2 ]){0 , 1 });
2936
2938
if (err ) {
2937
- goto cleanup ;
2939
+ return err ;
2938
2940
}
2939
2941
2940
2942
lfs_superblock_t superblock ;
2941
- int32_t res = lfs_dir_get (lfs , & superdir , 0x7ffff000 ,
2943
+ int32_t res = lfs_dir_get (lfs , & root , 0x7fc00000 ,
2942
2944
LFS_MKTAG (LFS_TYPE_SUPERBLOCK , 0 , sizeof (superblock )),
2943
2945
& superblock );
2944
2946
if (res < 0 ) {
2945
2947
err = res ;
2946
2948
goto cleanup ;
2947
2949
}
2948
- lfs_superblockfromle32 (& superblock );
2950
+ lfs_superblock_fromle32 (& superblock );
2949
2951
2950
- if (memcmp (superblock .magic , "littlefs" , 8 ) != 0 ) {
2951
- LFS_ERROR ("Invalid superblock \"%.8s\"" , superblock .magic );
2952
- return LFS_ERR_INVAL ;
2952
+ // find root
2953
+ int32_t tag = lfs_dir_find (lfs ,
2954
+ & root , (const lfs_block_t [2 ]){0 , 1 }, false, 0x7fc00000 ,
2955
+ LFS_MKTAG (LFS_TYPE_ROOT , 0 , 0 ), NULL );
2956
+ if (tag < 0 ) {
2957
+ return tag ;
2953
2958
}
2954
2959
2960
+ lfs -> root [0 ] = root .pair [0 ];
2961
+ lfs -> root [1 ] = root .pair [1 ];
2962
+
2963
+ // check version
2955
2964
uint16_t major_version = (0xffff & (superblock .version >> 16 ));
2956
2965
uint16_t minor_version = (0xffff & (superblock .version >> 0 ));
2957
2966
if ((major_version != LFS_DISK_VERSION_MAJOR ||
@@ -2962,15 +2971,6 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
2962
2971
goto cleanup ;
2963
2972
}
2964
2973
2965
- res = lfs_dir_get (lfs , & superdir , 0x7ffff000 ,
2966
- LFS_MKTAG (LFS_TYPE_DIRSTRUCT , 0 , sizeof (lfs -> root )),
2967
- & lfs -> root );
2968
- if (res < 0 ) {
2969
- err = res ;
2970
- goto cleanup ;
2971
- }
2972
- lfs_pair_fromle32 (lfs -> root );
2973
-
2974
2974
// check superblock configuration
2975
2975
if (superblock .attr_max ) {
2976
2976
if (superblock .attr_max > lfs -> attr_max ) {
@@ -3145,16 +3145,11 @@ static int32_t lfs_fs_parent(lfs_t *lfs, const lfs_block_t pair[2],
3145
3145
lfs_block_t child [2 ] = {pair [0 ], pair [1 ]};
3146
3146
lfs_pair_tole32 (child );
3147
3147
for (int i = 0 ; i < 2 ; i ++ ) {
3148
- // iterate over all directory directory entries
3149
- parent -> tail [0 ] = 0 ;
3150
- parent -> tail [1 ] = 1 ;
3151
- while (!lfs_pair_isnull (parent -> tail )) {
3152
- int32_t tag = lfs_dir_find (lfs , parent , parent -> tail , 0x7fc00fff ,
3153
- LFS_MKTAG (LFS_TYPE_DIRSTRUCT , 0 , sizeof (child )),
3154
- child );
3155
- if (tag != LFS_ERR_NOENT ) {
3156
- return tag ;
3157
- }
3148
+ int32_t tag = lfs_dir_find (lfs , parent ,
3149
+ (const lfs_block_t [2 ]){0 , 1 }, true, 0x7fc00fff ,
3150
+ LFS_MKTAG (LFS_TYPE_DIRSTRUCT , 0 , sizeof (child )), child );
3151
+ if (tag != LFS_ERR_NOENT ) {
3152
+ return tag ;
3158
3153
}
3159
3154
3160
3155
lfs_pair_swap (child );
@@ -3190,6 +3185,7 @@ static int lfs_fs_relocate(lfs_t *lfs,
3190
3185
3191
3186
if (tag != LFS_ERR_NOENT ) {
3192
3187
// update disk, this creates a desync
3188
+ lfs_global_deorphaned (lfs , false);
3193
3189
lfs_pair_tole32 (newpair );
3194
3190
int err = lfs_dir_commit (lfs , & parent ,
3195
3191
& (lfs_mattr_t ){.tag = tag , .buffer = newpair });
0 commit comments