1[cases.test_orphans_normal] 2in = "lfs.c" 3if = 'PROG_SIZE <= 0x3fe' # only works with one crc per commit 4code = ''' 5 lfs_t lfs; 6 lfs_format(&lfs, cfg) => 0; 7 lfs_mount(&lfs, cfg) => 0; 8 lfs_mkdir(&lfs, "parent") => 0; 9 lfs_mkdir(&lfs, "parent/orphan") => 0; 10 lfs_mkdir(&lfs, "parent/child") => 0; 11 lfs_remove(&lfs, "parent/orphan") => 0; 12 lfs_unmount(&lfs) => 0; 13 14 // corrupt the child's most recent commit, this should be the update 15 // to the linked-list entry, which should orphan the orphan. Note this 16 // makes a lot of assumptions about the remove operation. 17 lfs_mount(&lfs, cfg) => 0; 18 lfs_dir_t dir; 19 lfs_dir_open(&lfs, &dir, "parent/child") => 0; 20 lfs_block_t block = dir.m.pair[0]; 21 lfs_dir_close(&lfs, &dir) => 0; 22 lfs_unmount(&lfs) => 0; 23 uint8_t buffer[BLOCK_SIZE]; 24 cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0; 25 int off = BLOCK_SIZE-1; 26 while (off >= 0 && buffer[off] == ERASE_VALUE) { 27 off -= 1; 28 } 29 memset(&buffer[off-3], BLOCK_SIZE, 3); 30 cfg->erase(cfg, block) => 0; 31 cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0; 32 cfg->sync(cfg) => 0; 33 34 lfs_mount(&lfs, cfg) => 0; 35 struct lfs_info info; 36 lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT; 37 lfs_stat(&lfs, "parent/child", &info) => 0; 38 lfs_fs_size(&lfs) => 8; 39 lfs_unmount(&lfs) => 0; 40 41 lfs_mount(&lfs, cfg) => 0; 42 lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT; 43 lfs_stat(&lfs, "parent/child", &info) => 0; 44 lfs_fs_size(&lfs) => 8; 45 // this mkdir should both create a dir and deorphan, so size 46 // should be unchanged 47 lfs_mkdir(&lfs, "parent/otherchild") => 0; 48 lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT; 49 lfs_stat(&lfs, "parent/child", &info) => 0; 50 lfs_stat(&lfs, "parent/otherchild", &info) => 0; 51 lfs_fs_size(&lfs) => 8; 52 lfs_unmount(&lfs) => 0; 53 54 lfs_mount(&lfs, cfg) => 0; 55 lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT; 56 lfs_stat(&lfs, "parent/child", &info) => 0; 57 lfs_stat(&lfs, "parent/otherchild", &info) => 0; 58 lfs_fs_size(&lfs) => 8; 59 lfs_unmount(&lfs) => 0; 60''' 61 62# test that we only run deorphan once per power-cycle 63[cases.test_orphans_no_orphans] 64in = 'lfs.c' 65code = ''' 66 lfs_t lfs; 67 lfs_format(&lfs, cfg) => 0; 68 69 lfs_mount(&lfs, cfg) => 0; 70 // mark the filesystem as having orphans 71 lfs_fs_preporphans(&lfs, +1) => 0; 72 lfs_mdir_t mdir; 73 lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; 74 lfs_dir_commit(&lfs, &mdir, NULL, 0) => 0; 75 76 // we should have orphans at this state 77 assert(lfs_gstate_hasorphans(&lfs.gstate)); 78 lfs_unmount(&lfs) => 0; 79 80 // mount 81 lfs_mount(&lfs, cfg) => 0; 82 // we should detect orphans 83 assert(lfs_gstate_hasorphans(&lfs.gstate)); 84 // force consistency 85 lfs_fs_forceconsistency(&lfs) => 0; 86 // we should no longer have orphans 87 assert(!lfs_gstate_hasorphans(&lfs.gstate)); 88 89 lfs_unmount(&lfs) => 0; 90''' 91 92[cases.test_orphans_one_orphan] 93in = 'lfs.c' 94code = ''' 95 lfs_t lfs; 96 lfs_format(&lfs, cfg) => 0; 97 98 lfs_mount(&lfs, cfg) => 0; 99 // create an orphan 100 lfs_mdir_t orphan; 101 lfs_alloc_ack(&lfs); 102 lfs_dir_alloc(&lfs, &orphan) => 0; 103 lfs_dir_commit(&lfs, &orphan, NULL, 0) => 0; 104 105 // append our orphan and mark the filesystem as having orphans 106 lfs_fs_preporphans(&lfs, +1) => 0; 107 lfs_mdir_t mdir; 108 lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; 109 lfs_pair_tole32(orphan.pair); 110 lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS( 111 {LFS_MKTAG(LFS_TYPE_SOFTTAIL, 0x3ff, 8), orphan.pair})) => 0; 112 113 // we should have orphans at this state 114 assert(lfs_gstate_hasorphans(&lfs.gstate)); 115 lfs_unmount(&lfs) => 0; 116 117 // mount 118 lfs_mount(&lfs, cfg) => 0; 119 // we should detect orphans 120 assert(lfs_gstate_hasorphans(&lfs.gstate)); 121 // force consistency 122 lfs_fs_forceconsistency(&lfs) => 0; 123 // we should no longer have orphans 124 assert(!lfs_gstate_hasorphans(&lfs.gstate)); 125 126 lfs_unmount(&lfs) => 0; 127''' 128 129# test that we can persist gstate with lfs_fs_mkconsistent 130[cases.test_orphans_mkconsistent_no_orphans] 131in = 'lfs.c' 132code = ''' 133 lfs_t lfs; 134 lfs_format(&lfs, cfg) => 0; 135 136 lfs_mount(&lfs, cfg) => 0; 137 // mark the filesystem as having orphans 138 lfs_fs_preporphans(&lfs, +1) => 0; 139 lfs_mdir_t mdir; 140 lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; 141 lfs_dir_commit(&lfs, &mdir, NULL, 0) => 0; 142 143 // we should have orphans at this state 144 assert(lfs_gstate_hasorphans(&lfs.gstate)); 145 lfs_unmount(&lfs) => 0; 146 147 // mount 148 lfs_mount(&lfs, cfg) => 0; 149 // we should detect orphans 150 assert(lfs_gstate_hasorphans(&lfs.gstate)); 151 // force consistency 152 lfs_fs_mkconsistent(&lfs) => 0; 153 // we should no longer have orphans 154 assert(!lfs_gstate_hasorphans(&lfs.gstate)); 155 156 // remount 157 lfs_unmount(&lfs) => 0; 158 lfs_mount(&lfs, cfg) => 0; 159 // we should still have no orphans 160 assert(!lfs_gstate_hasorphans(&lfs.gstate)); 161 lfs_unmount(&lfs) => 0; 162''' 163 164[cases.test_orphans_mkconsistent_one_orphan] 165in = 'lfs.c' 166code = ''' 167 lfs_t lfs; 168 lfs_format(&lfs, cfg) => 0; 169 170 lfs_mount(&lfs, cfg) => 0; 171 // create an orphan 172 lfs_mdir_t orphan; 173 lfs_alloc_ack(&lfs); 174 lfs_dir_alloc(&lfs, &orphan) => 0; 175 lfs_dir_commit(&lfs, &orphan, NULL, 0) => 0; 176 177 // append our orphan and mark the filesystem as having orphans 178 lfs_fs_preporphans(&lfs, +1) => 0; 179 lfs_mdir_t mdir; 180 lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; 181 lfs_pair_tole32(orphan.pair); 182 lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS( 183 {LFS_MKTAG(LFS_TYPE_SOFTTAIL, 0x3ff, 8), orphan.pair})) => 0; 184 185 // we should have orphans at this state 186 assert(lfs_gstate_hasorphans(&lfs.gstate)); 187 lfs_unmount(&lfs) => 0; 188 189 // mount 190 lfs_mount(&lfs, cfg) => 0; 191 // we should detect orphans 192 assert(lfs_gstate_hasorphans(&lfs.gstate)); 193 // force consistency 194 lfs_fs_mkconsistent(&lfs) => 0; 195 // we should no longer have orphans 196 assert(!lfs_gstate_hasorphans(&lfs.gstate)); 197 198 // remount 199 lfs_unmount(&lfs) => 0; 200 lfs_mount(&lfs, cfg) => 0; 201 // we should still have no orphans 202 assert(!lfs_gstate_hasorphans(&lfs.gstate)); 203 lfs_unmount(&lfs) => 0; 204''' 205 206# reentrant testing for orphans, basically just spam mkdir/remove 207[cases.test_orphans_reentrant] 208reentrant = true 209# TODO fix this case, caused by non-DAG trees 210if = '!(DEPTH == 3 && CACHE_SIZE != 64)' 211defines = [ 212 {FILES=6, DEPTH=1, CYCLES=20}, 213 {FILES=26, DEPTH=1, CYCLES=20}, 214 {FILES=3, DEPTH=3, CYCLES=20}, 215] 216code = ''' 217 lfs_t lfs; 218 int err = lfs_mount(&lfs, cfg); 219 if (err) { 220 lfs_format(&lfs, cfg) => 0; 221 lfs_mount(&lfs, cfg) => 0; 222 } 223 224 uint32_t prng = 1; 225 const char alpha[] = "abcdefghijklmnopqrstuvwxyz"; 226 for (unsigned i = 0; i < CYCLES; i++) { 227 // create random path 228 char full_path[256]; 229 for (unsigned d = 0; d < DEPTH; d++) { 230 sprintf(&full_path[2*d], "/%c", alpha[TEST_PRNG(&prng) % FILES]); 231 } 232 233 // if it does not exist, we create it, else we destroy 234 struct lfs_info info; 235 int res = lfs_stat(&lfs, full_path, &info); 236 if (res == LFS_ERR_NOENT) { 237 // create each directory in turn, ignore if dir already exists 238 for (unsigned d = 0; d < DEPTH; d++) { 239 char path[1024]; 240 strcpy(path, full_path); 241 path[2*d+2] = '\0'; 242 err = lfs_mkdir(&lfs, path); 243 assert(!err || err == LFS_ERR_EXIST); 244 } 245 246 for (unsigned d = 0; d < DEPTH; d++) { 247 char path[1024]; 248 strcpy(path, full_path); 249 path[2*d+2] = '\0'; 250 lfs_stat(&lfs, path, &info) => 0; 251 assert(strcmp(info.name, &path[2*d+1]) == 0); 252 assert(info.type == LFS_TYPE_DIR); 253 } 254 } else { 255 // is valid dir? 256 assert(strcmp(info.name, &full_path[2*(DEPTH-1)+1]) == 0); 257 assert(info.type == LFS_TYPE_DIR); 258 259 // try to delete path in reverse order, ignore if dir is not empty 260 for (int d = DEPTH-1; d >= 0; d--) { 261 char path[1024]; 262 strcpy(path, full_path); 263 path[2*d+2] = '\0'; 264 err = lfs_remove(&lfs, path); 265 assert(!err || err == LFS_ERR_NOTEMPTY); 266 } 267 268 lfs_stat(&lfs, full_path, &info) => LFS_ERR_NOENT; 269 } 270 } 271 lfs_unmount(&lfs) => 0; 272''' 273 274