Skip to content

Commit 2ff32d2

Browse files
committed
Fixed bug where globals were poisoning move commits
The issue lies in the reuse of the id field for globals. Before globals, the only tags with a non-null (0x3ff) id field were names, structs, and other file-specific metadata. But globals are also using this field for the indirect delete, since otherwise the globals structure would be very unaligned (74-bits long). To make matters worse, the id field for globals contains the delta used to reconstruct the globals at mount time. Which means the id field could take on very absurd values and break the dir fetch logic if we're not careful. Solution is to use the scope portion of the type field where necessary, although unforunately this does add some code cost.
1 parent b46fcac commit 2ff32d2

File tree

3 files changed

+56
-12
lines changed

3 files changed

+56
-12
lines changed

lfs.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,13 @@ static int lfs_commit_movescan(lfs_t *lfs, void *p, lfs_mattr_t attr) {
664664
return 0;
665665
}
666666

667+
// TODO AHHHH, scopes, what about user scope above?
668+
if (lfs_tag_scope(attr.tag) == LFS_SCOPE_FS ||
669+
lfs_tag_scope(attr.tag) == LFS_SCOPE_DIR) {
670+
// ignore non-matching ids
671+
return 0;
672+
}
673+
667674
if (lfs_tag_id(attr.tag) != move->id.from) {
668675
// ignore non-matching ids
669676
return 0;
@@ -1023,6 +1030,9 @@ static int lfs_dir_compact(lfs_t *lfs, lfs_mdir_t *dir, lfs_mattrlist_t *list,
10231030

10241031
// There's nothing special about our global delta, so feed it back
10251032
// into the global global delta
1033+
// TODO IMMENSE HMM globals get bleed into from above, need to be fixed after commits due to potential moves
1034+
lfs_globals_t gtemp = dir->globals; // TODO hmm, why did we have different variables then?
1035+
10261036
lfs->diff = lfs_globals_xor(&lfs->diff, &dir->globals);
10271037
dir->globals = (lfs_globals_t){0};
10281038

@@ -1196,6 +1206,8 @@ static int lfs_dir_compact(lfs_t *lfs, lfs_mdir_t *dir, lfs_mattrlist_t *list,
11961206
lfs->diff = (lfs_globals_t){0};
11971207
}
11981208

1209+
lfs->globals = lfs_globals_xor(&lfs->globals, &gtemp); // TODO hmm, why did we have different variables then?
1210+
11991211
return 0;
12001212
}
12011213

@@ -1244,6 +1256,8 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir, lfs_mattrlist_t *list) {
12441256
// successful commit, lets update dir
12451257
dir->off = commit.off;
12461258
dir->etag = commit.ptag;
1259+
// // TODO hm
1260+
// dir->globals = lfs_globals_xor(&dir->globals, &lfs->diff);
12471261
lfs->globals = lfs_globals_xor(&lfs->globals, &lfs->diff);
12481262
lfs->diff = (lfs_globals_t){0};
12491263
break;
@@ -2954,6 +2968,10 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
29542968
return res;
29552969
}
29562970

2971+
// TODO test for global state stealing?
2972+
// steal global state
2973+
lfs->globals = lfs_globals_xor(&lfs->globals, &prevdir.globals);
2974+
29572975
LFS_ASSERT(res); // must have pred
29582976
newcwd.tail[0] = prevdir.tail[0];
29592977
newcwd.tail[1] = prevdir.tail[1];

lfs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ enum lfs_type {
129129
// internal sources
130130
LFS_FROM_REGION = 0x000,
131131
LFS_FROM_DISK = 0x200,
132-
LFS_FROM_MOVE = 0x0ff,
132+
LFS_FROM_MOVE = 0x03f,
133133
};
134134

135135
// File open flags

tests/test_move.sh

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ tests/test.py << TEST
109109
TEST
110110

111111
echo "--- Move file after corrupt ---"
112-
tests/test.py -s << TEST
112+
tests/test.py << TEST
113113
lfs_mount(&lfs, &cfg) => 0;
114114
lfs_rename(&lfs, "c/hello", "d/hello") => 0;
115115
lfs_unmount(&lfs) => 0;
@@ -166,7 +166,7 @@ tests/test.py << TEST
166166
lfs_rename(&lfs, "b/hi", "c/hi") => 0;
167167
lfs_unmount(&lfs) => 0;
168168
TEST
169-
rm -v blocks/7
169+
truncate -s-11 blocks/7
170170
tests/test.py << TEST
171171
lfs_mount(&lfs, &cfg) => 0;
172172
lfs_dir_open(&lfs, &dir[0], "b") => 0;
@@ -182,8 +182,6 @@ tests/test.py << TEST
182182
lfs_dir_read(&lfs, &dir[0], &info) => 1;
183183
strcmp(info.name, "..") => 0;
184184
lfs_dir_read(&lfs, &dir[0], &info) => 1;
185-
strcmp(info.name, "hello") => 0;
186-
lfs_dir_read(&lfs, &dir[0], &info) => 1;
187185
strcmp(info.name, "hi") => 0;
188186
lfs_dir_read(&lfs, &dir[0], &info) => 0;
189187
lfs_unmount(&lfs) => 0;
@@ -195,8 +193,8 @@ tests/test.py << TEST
195193
lfs_rename(&lfs, "c/hi", "d/hi") => 0;
196194
lfs_unmount(&lfs) => 0;
197195
TEST
198-
rm -v blocks/9
199-
rm -v blocks/a
196+
truncate -s-11 blocks/9
197+
truncate -s-11 blocks/b
200198
tests/test.py << TEST
201199
lfs_mount(&lfs, &cfg) => 0;
202200
lfs_dir_open(&lfs, &dir[0], "c") => 0;
@@ -205,16 +203,44 @@ tests/test.py << TEST
205203
lfs_dir_read(&lfs, &dir[0], &info) => 1;
206204
strcmp(info.name, "..") => 0;
207205
lfs_dir_read(&lfs, &dir[0], &info) => 1;
206+
strcmp(info.name, "hi") => 0;
207+
lfs_dir_read(&lfs, &dir[0], &info) => 0;
208+
lfs_dir_close(&lfs, &dir[0]) => 0;
209+
lfs_dir_open(&lfs, &dir[0], "d") => 0;
210+
lfs_dir_read(&lfs, &dir[0], &info) => 1;
211+
strcmp(info.name, ".") => 0;
212+
lfs_dir_read(&lfs, &dir[0], &info) => 1;
213+
strcmp(info.name, "..") => 0;
214+
lfs_dir_read(&lfs, &dir[0], &info) => 1;
208215
strcmp(info.name, "hello") => 0;
216+
lfs_dir_read(&lfs, &dir[0], &info) => 0;
217+
lfs_unmount(&lfs) => 0;
218+
TEST
219+
220+
echo "--- Move dir after corrupt ---"
221+
tests/test.py << TEST
222+
lfs_mount(&lfs, &cfg) => 0;
223+
lfs_rename(&lfs, "c/hi", "d/hi") => 0;
224+
lfs_unmount(&lfs) => 0;
225+
TEST
226+
tests/test.py << TEST
227+
lfs_mount(&lfs, &cfg) => 0;
228+
lfs_dir_open(&lfs, &dir[0], "c") => 0;
209229
lfs_dir_read(&lfs, &dir[0], &info) => 1;
210-
strcmp(info.name, "hi") => 0;
230+
strcmp(info.name, ".") => 0;
231+
lfs_dir_read(&lfs, &dir[0], &info) => 1;
232+
strcmp(info.name, "..") => 0;
211233
lfs_dir_read(&lfs, &dir[0], &info) => 0;
212234
lfs_dir_close(&lfs, &dir[0]) => 0;
213235
lfs_dir_open(&lfs, &dir[0], "d") => 0;
214236
lfs_dir_read(&lfs, &dir[0], &info) => 1;
215237
strcmp(info.name, ".") => 0;
216238
lfs_dir_read(&lfs, &dir[0], &info) => 1;
217239
strcmp(info.name, "..") => 0;
240+
lfs_dir_read(&lfs, &dir[0], &info) => 1;
241+
strcmp(info.name, "hello") => 0;
242+
lfs_dir_read(&lfs, &dir[0], &info) => 1;
243+
strcmp(info.name, "hi") => 0;
218244
lfs_dir_read(&lfs, &dir[0], &info) => 0;
219245
lfs_unmount(&lfs) => 0;
220246
TEST
@@ -225,9 +251,9 @@ tests/test.py << TEST
225251
226252
lfs_dir_open(&lfs, &dir[0], "a/hi") => LFS_ERR_NOENT;
227253
lfs_dir_open(&lfs, &dir[0], "b/hi") => LFS_ERR_NOENT;
228-
lfs_dir_open(&lfs, &dir[0], "d/hi") => LFS_ERR_NOENT;
254+
lfs_dir_open(&lfs, &dir[0], "c/hi") => LFS_ERR_NOENT;
229255
230-
lfs_dir_open(&lfs, &dir[0], "c/hi") => 0;
256+
lfs_dir_open(&lfs, &dir[0], "d/hi") => 0;
231257
lfs_dir_read(&lfs, &dir[0], &info) => 1;
232258
strcmp(info.name, ".") => 0;
233259
lfs_dir_read(&lfs, &dir[0], &info) => 1;
@@ -243,9 +269,9 @@ tests/test.py << TEST
243269
244270
lfs_dir_open(&lfs, &dir[0], "a/hello") => LFS_ERR_NOENT;
245271
lfs_dir_open(&lfs, &dir[0], "b/hello") => LFS_ERR_NOENT;
246-
lfs_dir_open(&lfs, &dir[0], "d/hello") => LFS_ERR_NOENT;
272+
lfs_dir_open(&lfs, &dir[0], "c/hello") => LFS_ERR_NOENT;
247273
248-
lfs_file_open(&lfs, &file[0], "c/hello", LFS_O_RDONLY) => 0;
274+
lfs_file_open(&lfs, &file[0], "d/hello", LFS_O_RDONLY) => 0;
249275
lfs_file_read(&lfs, &file[0], buffer, 5) => 5;
250276
memcmp(buffer, "hola\n", 5) => 0;
251277
lfs_file_read(&lfs, &file[0], buffer, 8) => 8;

0 commit comments

Comments
 (0)