mirror of
				https://github.com/eledio-devices/thirdparty-littlefs.git
				synced 2025-10-31 16:14:16 +01:00 
			
		
		
		
	Fixed issue with directories falling out of date after block relocation
This is caused by dir->head not being updated when dir->m.pair may be. This causes the two to fall out of sync and later dir rewinds to fail. This bug stems all the way back from the first commits of littlefs, so it's surprising it has avoided detection for this long. Perhaps because lfs_dir_rewind is not used often.
This commit is contained in:
		
							
								
								
									
										1
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								Makefile
									
									
									
									
									
								
							| @@ -55,6 +55,7 @@ test: \ | |||||||
| 	test_attrs \ | 	test_attrs \ | ||||||
| 	test_move \ | 	test_move \ | ||||||
| 	test_orphan \ | 	test_orphan \ | ||||||
|  | 	test_relocations \ | ||||||
| 	test_corrupt | 	test_corrupt | ||||||
| 	@rm test.c | 	@rm test.c | ||||||
| test_%: tests/test_%.sh | test_%: tests/test_%.sh | ||||||
|   | |||||||
							
								
								
									
										8
									
								
								lfs.c
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								lfs.c
									
									
									
									
									
								
							| @@ -2103,8 +2103,6 @@ int lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir) { | |||||||
|         return err; |         return err; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     dir->m.pair[0] = dir->head[0]; |  | ||||||
|     dir->m.pair[1] = dir->head[1]; |  | ||||||
|     dir->id = 0; |     dir->id = 0; | ||||||
|     dir->pos = 0; |     dir->pos = 0; | ||||||
|     LFS_TRACE("lfs_dir_rewind -> %d", 0); |     LFS_TRACE("lfs_dir_rewind -> %d", 0); | ||||||
| @@ -3887,6 +3885,12 @@ static int lfs_fs_relocate(lfs_t *lfs, | |||||||
|             d->m.pair[0] = newpair[0]; |             d->m.pair[0] = newpair[0]; | ||||||
|             d->m.pair[1] = newpair[1]; |             d->m.pair[1] = newpair[1]; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         if (d->type == LFS_TYPE_DIR && | ||||||
|  |                 lfs_pair_cmp(oldpair, ((lfs_dir_t*)d)->head) == 0) { | ||||||
|  |             ((lfs_dir_t*)d)->head[0] = newpair[0]; | ||||||
|  |             ((lfs_dir_t*)d)->head[1] = newpair[1]; | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // find parent |     // find parent | ||||||
|   | |||||||
							
								
								
									
										88
									
								
								tests/test_relocations.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										88
									
								
								tests/test_relocations.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,88 @@ | |||||||
|  | #!/bin/bash | ||||||
|  | set -eu | ||||||
|  | export TEST_FILE=$0 | ||||||
|  | trap 'export TEST_LINE=$LINENO' DEBUG | ||||||
|  |  | ||||||
|  | ITERATIONS=20 | ||||||
|  | COUNT=10 | ||||||
|  |  | ||||||
|  | echo "=== Relocation tests ===" | ||||||
|  | rm -rf blocks | ||||||
|  | scripts/test.py << TEST | ||||||
|  |     lfs_format(&lfs, &cfg) => 0; | ||||||
|  |     // fill up filesystem so only ~16 blocks are left | ||||||
|  |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|  |     lfs_file_open(&lfs, &file, "padding", LFS_O_CREAT | LFS_O_WRONLY) => 0; | ||||||
|  |     memset(buffer, 0, 512); | ||||||
|  |     while (LFS_BLOCK_COUNT - lfs_fs_size(&lfs) > 16) { | ||||||
|  |         lfs_file_write(&lfs, &file, buffer, 512) => 512; | ||||||
|  |     } | ||||||
|  |     lfs_file_close(&lfs, &file) => 0; | ||||||
|  |     // make a child dir to use in bounded space | ||||||
|  |     lfs_mkdir(&lfs, "child") => 0; | ||||||
|  |     lfs_unmount(&lfs) => 0; | ||||||
|  | TEST | ||||||
|  |  | ||||||
|  | echo "--- Outdated head test ---" | ||||||
|  | scripts/test.py << TEST | ||||||
|  |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|  |     for (int j = 0; j < $ITERATIONS; j++) { | ||||||
|  |         for (int i = 0; i < $COUNT; i++) { | ||||||
|  |             sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); | ||||||
|  |             lfs_file_open(&lfs, &file, path, LFS_O_CREAT | LFS_O_WRONLY) => 0; | ||||||
|  |             lfs_file_close(&lfs, &file) => 0; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         lfs_dir_open(&lfs, &dir, "child") => 0; | ||||||
|  |         lfs_dir_read(&lfs, &dir, &info) => 1; | ||||||
|  |         lfs_dir_read(&lfs, &dir, &info) => 1; | ||||||
|  |         for (int i = 0; i < $COUNT; i++) { | ||||||
|  |             sprintf(path, "test%03d_loooooooooooooooooong_name", i); | ||||||
|  |             lfs_dir_read(&lfs, &dir, &info) => 1; | ||||||
|  |             strcmp(info.name, path) => 0; | ||||||
|  |             info.size => 0; | ||||||
|  |  | ||||||
|  |             sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); | ||||||
|  |             lfs_file_open(&lfs, &file, path, LFS_O_WRONLY) => 0; | ||||||
|  |             lfs_file_write(&lfs, &file, "hi", 2) => 2; | ||||||
|  |             lfs_file_close(&lfs, &file) => 0; | ||||||
|  |         } | ||||||
|  |         lfs_dir_read(&lfs, &dir, &info) => 0; | ||||||
|  |  | ||||||
|  |         lfs_dir_rewind(&lfs, &dir) => 0; | ||||||
|  |         lfs_dir_read(&lfs, &dir, &info) => 1; | ||||||
|  |         lfs_dir_read(&lfs, &dir, &info) => 1; | ||||||
|  |         for (int i = 0; i < $COUNT; i++) { | ||||||
|  |             sprintf(path, "test%03d_loooooooooooooooooong_name", i); | ||||||
|  |             lfs_dir_read(&lfs, &dir, &info) => 1; | ||||||
|  |             strcmp(info.name, path) => 0; | ||||||
|  |             info.size => 2; | ||||||
|  |  | ||||||
|  |             sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); | ||||||
|  |             lfs_file_open(&lfs, &file, path, LFS_O_WRONLY) => 0; | ||||||
|  |             lfs_file_write(&lfs, &file, "hi", 2) => 2; | ||||||
|  |             lfs_file_close(&lfs, &file) => 0; | ||||||
|  |         } | ||||||
|  |         lfs_dir_read(&lfs, &dir, &info) => 0; | ||||||
|  |  | ||||||
|  |         lfs_dir_rewind(&lfs, &dir) => 0; | ||||||
|  |         lfs_dir_read(&lfs, &dir, &info) => 1; | ||||||
|  |         lfs_dir_read(&lfs, &dir, &info) => 1; | ||||||
|  |         for (int i = 0; i < $COUNT; i++) { | ||||||
|  |             sprintf(path, "test%03d_loooooooooooooooooong_name", i); | ||||||
|  |             lfs_dir_read(&lfs, &dir, &info) => 1; | ||||||
|  |             strcmp(info.name, path) => 0; | ||||||
|  |             info.size => 2; | ||||||
|  |         } | ||||||
|  |         lfs_dir_read(&lfs, &dir, &info) => 0; | ||||||
|  |         lfs_dir_close(&lfs, &dir) => 0; | ||||||
|  |  | ||||||
|  |         for (int i = 0; i < $COUNT; i++) { | ||||||
|  |             sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); | ||||||
|  |             lfs_remove(&lfs, path) => 0; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     lfs_unmount(&lfs) => 0; | ||||||
|  | TEST | ||||||
|  |  | ||||||
|  | scripts/results.py | ||||||
		Reference in New Issue
	
	Block a user