瀏覽代碼

Switched back to simple deorphan-step on directory remove

Originally I tried to reuse the indirect delete to accomplish truely
atomic directory removes, however this fell apart when it came to
implementing directory removes as a side-effect of renames.

A single indirect-delete simply can't handle renames with removes as
a side effects. When copying an entry to its destination, we need to
atomically delete both the old entry, and the source of our copy. We
can't delete both with only a single indirect-delete. It is possible to
accomplish this with two indirect-deletes, but this is such an uncommon
case that it's really not worth supporting efficiently due to how
expensive globals are.

I also dropped indirect-deletes for normal directory removes. I may add
it back later, but at the moment it's extra code cost for that's not
traveled very often.

As a result, restructured the indirect delete handling to be a bit more
generic, now with a multipurpose lfs_globals_t struct instead of the
delete specific lfs_entry_t struct.

Also worked on integrating xored-globals, now with several primitive
global operations to manage fetching/updating globals on disk.
Christopher Haster 7 年之前
父節點
當前提交
cebf7aa0fe
共有 3 個文件被更改,包括 322 次插入95 次删除
  1. 278 84
      lfs.c
  2. 15 8
      lfs.h
  3. 29 3
      tests/test_move.sh

+ 278 - 84
lfs.c

@@ -267,6 +267,8 @@ static int lfs_parent(lfs_t *lfs, const lfs_block_t dir[2],
 static int lfs_moved(lfs_t *lfs, lfs_mdir_t *fromdir, uint16_t fromid);
 static int lfs_relocate(lfs_t *lfs,
         const lfs_block_t oldpair[2], const lfs_block_t newpair[2]);
+int lfs_scan(lfs_t *lfs);
+int lfs_fixmove(lfs_t *lfs);
 int lfs_deorphan(lfs_t *lfs);
 
 
@@ -458,6 +460,22 @@ static inline lfs_size_t lfs_tag_size(lfs_tag_t tag) {
     return tag & 0x00000fff;
 }
 
+// operations on globals
+static lfs_globals_t lfs_globals_xor(
+        const lfs_globals_t *a, const lfs_globals_t *b) {
+    lfs_globals_t res;
+    res.move.pair[0] = a->move.pair[0] ^ b->move.pair[0];
+    res.move.pair[1] = a->move.pair[1] ^ b->move.pair[1];
+    res.move.id = a->move.id ^ b->move.id;
+    return res;
+}
+
+static bool lfs_globals_iszero(const lfs_globals_t *a) {
+    return (a->move.pair[0] == 0 && a->move.pair[1] == 0 && a->move.id == 0);
+}
+
+
+// commit logic
 struct lfs_commit {
     lfs_block_t block;
     lfs_off_t off;
@@ -701,6 +719,23 @@ static int lfs_commit_move(lfs_t *lfs, struct lfs_commit *commit,
     return 0;
 }
 
+static int lfs_commit_globals(lfs_t *lfs, struct lfs_commit *commit,
+        const lfs_globals_t *source, const lfs_globals_t *diff) {
+    lfs_globals_t res = lfs_globals_xor(source, diff);
+
+    if (!lfs_globals_iszero(&res)) {
+        int err = lfs_commit_commit(lfs, commit, (lfs_mattr_t){
+                lfs_mktag(LFS_TYPE_IDELETE,
+                    res.move.id, sizeof(res.move.pair)),
+                    .u.buffer=res.move.pair});
+        if (err) {
+            return err;
+        }
+    }
+
+    return 0;
+}
+
 static int lfs_dir_alloc(lfs_t *lfs, lfs_mdir_t *dir,
         bool split, const lfs_block_t tail[2]) {
     // allocate pair of dir blocks (backwards, so we write to block 1 first)
@@ -727,7 +762,7 @@ static int lfs_dir_alloc(lfs_t *lfs, lfs_mdir_t *dir,
     dir->tail[1] = tail[1];
     dir->erased = false;
     dir->split = split;
-    dir->idelete = (lfs_entry_t){{0, 0}, 0};
+    dir->globals = (lfs_globals_t){0};
 
     // don't write out yet, let caller take care of that
     return 0;
@@ -764,7 +799,7 @@ static int lfs_dir_fetchwith(lfs_t *lfs,
         dir->tail[1] = 0xffffffff;
         dir->count = 0;
         dir->split = false;
-        dir->idelete = (lfs_entry_t){{0, 0}, 0};
+        dir->globals = (lfs_globals_t){0};
         dir->moveid = -1;
 
         dir->rev = lfs_tole32(rev[0]);
@@ -786,9 +821,12 @@ static int lfs_dir_fetchwith(lfs_t *lfs,
 
             // next commit not yet programmed
             if (lfs_tag_type(ptag) == LFS_TYPE_CRC && !lfs_tag_valid(tag)) {
-                if (lfs_paircmp(dir->pair, lfs->idelete.pair) == 0 && cb) {
+                // synthetic move
+                if (lfs_paircmp(dir->pair, lfs->globals.move.pair) == 0
+                        && cb) {
                     int err = cb(lfs, data, (lfs_mattr_t){
-                            lfs_mktag(LFS_STRUCT_DELETE, lfs->idelete.id, 0)});
+                            lfs_mktag(LFS_STRUCT_DELETE,
+                                lfs->globals.move.id, 0)});
                     if (err) {
                         return err;
                     }
@@ -818,12 +856,13 @@ static int lfs_dir_fetchwith(lfs_t *lfs,
                         // try other block
                         break;
                     } else {
+                        // snythetic move
                         // TODO combine with above?
-                        if (lfs_paircmp(dir->pair, lfs->idelete.pair) == 0
+                        if (lfs_paircmp(dir->pair, lfs->globals.move.pair) == 0
                                 && cb) {
                             int err = cb(lfs, data, (lfs_mattr_t){
                                     lfs_mktag(LFS_STRUCT_DELETE,
-                                        lfs->idelete.id, 0)});
+                                        lfs->globals.move.id, 0)});
                             if (err) {
                                 return err;
                             }
@@ -855,8 +894,10 @@ static int lfs_dir_fetchwith(lfs_t *lfs,
                         return err;
                     }
                 } else if (lfs_tag_type(tag) == LFS_TYPE_IDELETE) {
+                    temp.globals.move.id = lfs_tag_id(tag);
                     err = lfs_bd_read(lfs, temp.pair[0], off+sizeof(tag),
-                            &temp.idelete, sizeof(temp.idelete));
+                            &temp.globals.move.pair,
+                            sizeof(temp.globals.move.pair));
                     if (err) {
                         return err;
                     }
@@ -864,7 +905,7 @@ static int lfs_dir_fetchwith(lfs_t *lfs,
                     // TODO handle moves correctly?
                     temp.moveid = lfs_tag_id(tag);
                 } else {
-                    if (lfs_tag_id(tag) < 0x3ff &&
+                    if (lfs_tag_scope(tag) <= LFS_SCOPE_ENTRY &&
                             lfs_tag_id(tag) >= temp.count) {
                         temp.count = lfs_tag_id(tag)+1;
                     }
@@ -918,9 +959,10 @@ static int lfs_dir_traverse(lfs_t *lfs, lfs_mdir_t *dir,
     lfs_off_t off = dir->off;
     lfs_tag_t tag = dir->etag;
 
-    if (lfs_paircmp(dir->pair, lfs->idelete.pair) == 0) {
+    // synthetic move
+    if (lfs_paircmp(dir->pair, lfs->globals.move.pair) == 0) {
         int err = cb(lfs, data, (lfs_mattr_t){
-                lfs_mktag(LFS_STRUCT_DELETE, lfs->idelete.id, 0)});
+                lfs_mktag(LFS_STRUCT_DELETE, lfs->globals.move.id, 0)});
         if (err) {
             return err;
         }
@@ -1031,29 +1073,29 @@ static int lfs_dir_compact(lfs_t *lfs, lfs_mdir_t *dir, lfs_mattrlist_t *list,
                 ack = id;
             }
 
+            // reopen the reserved space at the end
+            // TODO can I just commit these first?
             commit.end = lfs->cfg->block_size - 2*sizeof(uint32_t);
-            if (!lfs_pairisnull(dir->tail)) {
-                // TODO le32
-                err = lfs_commit_commit(lfs, &commit, (lfs_mattr_t){
-                        lfs_mktag(LFS_STRUCT_TAIL + dir->split*0x8,
-                            0x3ff, sizeof(dir->tail)),
-                        .u.buffer=dir->tail});
+
+            if (!relocated) {
+                err = lfs_commit_globals(lfs, &commit,
+                        &dir->globals, &lfs->diff);
                 if (err) {
-                    if (err == LFS_ERR_CORRUPT) {
+                    if (err == LFS_ERR_NOSPC) {
+                        goto split;
+                    } else if (err == LFS_ERR_CORRUPT) {
                         goto relocate;
                     }
                     return err;
                 }
             }
 
-            if (!(dir->idelete.pair[0] == 0 &&
-                  dir->idelete.pair[0] == 0 &&
-                  dir->idelete.id == 0)) {
+            if (!lfs_pairisnull(dir->tail)) {
                 // TODO le32
                 err = lfs_commit_commit(lfs, &commit, (lfs_mattr_t){
-                        lfs_mktag(LFS_TYPE_IDELETE,
-                            0x3ff, sizeof(dir->idelete)),
-                        .u.buffer=&dir->idelete});
+                        lfs_mktag(LFS_STRUCT_TAIL + dir->split*0x8,
+                            0x3ff, sizeof(dir->tail)),
+                        .u.buffer=dir->tail});
                 if (err) {
                     if (err == LFS_ERR_CORRUPT) {
                         goto relocate;
@@ -1131,6 +1173,9 @@ relocate:
         if (err) {
             return err;
         }
+    } else {
+        lfs->globals = lfs_globals_xor(&lfs->globals, &lfs->diff);
+        lfs->diff = (lfs_globals_t){0};
     }
 
     return 0;
@@ -1162,6 +1207,16 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir, lfs_mattrlist_t *list) {
             return err;
         }
 
+        if (!lfs_globals_iszero(&lfs->diff)) {
+            err = lfs_commit_globals(lfs, &commit, &dir->globals, &lfs->diff);
+            if (err) {
+                if (err == LFS_ERR_NOSPC || err == LFS_ERR_CORRUPT) {
+                    goto compact;
+                }
+                return err;
+            }
+        }
+
         err = lfs_commit_crc(lfs, &commit);
         if (err) {
             if (err == LFS_ERR_NOSPC || err == LFS_ERR_CORRUPT) {
@@ -1173,6 +1228,8 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir, lfs_mattrlist_t *list) {
         // successful commit, lets update dir
         dir->off = commit.off;
         dir->etag = commit.ptag;
+        lfs->globals = lfs_globals_xor(&lfs->globals, &lfs->diff);
+        lfs->diff = (lfs_globals_t){0};
         break;
 
 compact:
@@ -1212,9 +1269,13 @@ static int lfs_dir_delete(lfs_t *lfs, lfs_mdir_t *dir, uint16_t id) {
         }
 
         if (res && pdir.split) {
+            // steal tail, and global state
             pdir.split = dir->split;
             pdir.tail[0] = dir->tail[0];
             pdir.tail[1] = dir->tail[1];
+            lfs->diff = dir->globals;
+            lfs->globals = lfs_globals_xor(&lfs->globals, &dir->globals);
+
             int err = lfs_dir_commit(lfs, &pdir, &(lfs_mattrlist_t){
                     {lfs_mktag(LFS_STRUCT_TAIL + pdir.split*0x8,
                         0x3ff, sizeof(pdir.tail)),
@@ -2661,17 +2722,50 @@ int lfs_remove(lfs_t *lfs, const char *path) {
         return err;
     }
 
+    lfs_mdir_t dir;
     if (lfs_tag_subtype(attr.tag) == LFS_TYPE_DIR) {
-        lfs_mdir_t dir;
         // must be empty before removal
         err = lfs_dir_fetch(lfs, &dir, attr.u.pair);
         if (err) {
             return err;
         }
 
+        // TODO lfs_dir_empty?
         if (dir.count > 0 || dir.split) {
             return LFS_ERR_NOTEMPTY;
         }
+//
+//        // unlink from tail chain and create move to fix
+//        lfs->diff.move.pair[0] = cwd.pair[0] ^ lfs->globals.move.pair[0];
+//        lfs->diff.move.pair[1] = cwd.pair[1] ^ lfs->globals.move.pair[1];
+//        lfs->diff.move.id      = id          ^ lfs->globals.move.id;
+//
+//        // xor over our child's global state
+//        lfs->diff = lfs_globals_xor(&lfs->diff, &dir.globals);
+//        lfs->globals = lfs_globals_xor(&lfs->globals, &dir.globals);
+//
+//        // find pred and remove
+//        // TODO handle dropped block?
+//        lfs_mdir_t pred;
+//        int res = lfs_pred(lfs, dir.pair, &pred);
+//        if (res < 0) {
+//            return res;
+//        }
+//
+//        LFS_ASSERT(res); // must have pred
+//        pred.tail[0] = dir.tail[0];
+//        pred.tail[1] = dir.tail[1];
+//        err = lfs_dir_commit(lfs, &pred, &(lfs_mattrlist_t){
+//                {lfs_mktag(LFS_TYPE_SOFTTAIL, 0x3ff, sizeof(pred.tail)),
+//                    .u.buffer=pred.tail}});
+//        if (err) {
+//            return err;
+//        }
+//
+//        // mark global state to clear move entry
+//        lfs->diff.move.pair[0] = 0xffffffff ^ lfs->globals.move.pair[0];
+//        lfs->diff.move.pair[1] = 0xffffffff ^ lfs->globals.move.pair[1];
+//        lfs->diff.move.id      = 0x3ff      ^ lfs->globals.move.id;
     }
 
     // delete the entry
@@ -2680,31 +2774,28 @@ int lfs_remove(lfs_t *lfs, const char *path) {
         return err;
     }
 
-    // if we were a directory, find pred, replace tail
-    // TODO can this just deorphan?
-    if (lfs_tag_subtype(attr.tag) == LFS_TYPE_DIR) {
-        err = lfs_deorphan(lfs);
-        if (err) {
-            return err;
-        }
-    }
-
+//    // if we were a directory, fix the move we just created
 //    if (lfs_tag_subtype(attr.tag) == LFS_TYPE_DIR) {
-//        int res = lfs_pred(lfs, dir.pair, &cwd);
-//        if (res < 0) {
-//            return res;
-//        }
-//
-//        LFS_ASSERT(res); // must have pred
-//        cwd.tail[0] = dir.tail[0];
-//        cwd.tail[1] = dir.tail[1];
-//
-//        err = lfs_dir_commit(lfs, &cwd, NULL, 0);
+//        err = lfs_deorphan(lfs);
 //        if (err) {
 //            return err;
 //        }
 //    }
 
+    if (lfs_tag_subtype(attr.tag) == LFS_TYPE_DIR) {
+        int res = lfs_pred(lfs, dir.pair, &cwd);
+        if (res < 0) {
+            return res;
+        }
+
+        LFS_ASSERT(res); // must have pred
+        cwd.tail[0] = dir.tail[0];
+        cwd.tail[1] = dir.tail[1];
+        err = lfs_dir_commit(lfs, &cwd, &(lfs_mattrlist_t){
+                {lfs_mktag(LFS_TYPE_SOFTTAIL, 0x3ff, sizeof(cwd.tail)),
+                    .u.buffer=cwd.tail}});
+    }
+
     return 0;
 }
 
@@ -2741,8 +2832,10 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
     }
 
     bool prevexists = (err != LFS_ERR_NOENT);
-    bool samepair = (lfs_paircmp(oldcwd.pair, newcwd.pair) == 0);
+    //bool samepair = (lfs_paircmp(oldcwd.pair, newcwd.pair) == 0);
+
     lfs_mattr_t prevattr;
+    lfs_mdir_t prevdir;
     if (prevexists) {
         // get prev entry, check that we have same type
         err = lfs_dir_getentry(lfs, &newcwd, 0x703ff000,
@@ -2756,7 +2849,6 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
         }
 
         if (lfs_tag_subtype(prevattr.tag) == LFS_TYPE_DIR) {
-            lfs_mdir_t prevdir;
             // must be empty before removal
             err = lfs_dir_fetch(lfs, &prevdir, prevattr.u.pair);
             if (err) {
@@ -2781,19 +2873,24 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
         }
     }
 
-    // mark as moving
-    //printf("RENAME MOVE %d %d %d\n", oldcwd.pair[0], oldcwd.pair[1], oldid);
-    err = lfs_dir_commit(lfs, &oldcwd, &(lfs_mattrlist_t){
-            {lfs_mktag(LFS_STRUCT_MOVE, oldid, 0)}});
-    if (err) {
-        return err;
-    }
-
-    if (samepair) {
-        // update pair if newcwd == oldcwd
-        newcwd = oldcwd;
-    }
+    // create move to fix later
+    lfs->diff.move.pair[0] = oldcwd.pair[0] ^ lfs->globals.move.pair[0];
+    lfs->diff.move.pair[1] = oldcwd.pair[1] ^ lfs->globals.move.pair[1];
+    lfs->diff.move.id      = oldid          ^ lfs->globals.move.id;
 
+//    // mark as moving
+//    //printf("RENAME MOVE %d %d %d\n", oldcwd.pair[0], oldcwd.pair[1], oldid);
+//    err = lfs_dir_commit(lfs, &oldcwd, &(lfs_mattrlist_t){
+//            {lfs_mktag(LFS_STRUCT_MOVE, oldid, 0)}});
+//    if (err) {
+//        return err;
+//    }
+//
+//    if (samepair) {
+//        // update pair if newcwd == oldcwd
+//        newcwd = oldcwd;
+//    }
+//
 // TODO check that all complaints are fixed
 //    // move to new location
 //    // TODO NAME?????
@@ -2813,6 +2910,7 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
 //        return err;
 //    }
 
+    // move over all attributes
     err = lfs_dir_commit(lfs, &newcwd, &(lfs_mattrlist_t){
             {lfs_mktag(LFS_STRUCT_NAME | lfs_tag_subtype(oldattr.tag),
                 newid, strlen(newpath)),
@@ -2823,28 +2921,53 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
         return err;
     }
 
-    if (samepair) {
-        // update pair if newcwd == oldcwd
-        oldcwd = newcwd;
-    }
-
-    // remove old entry
-    //printf("RENAME DELETE %d %d %d\n", oldcwd.pair[0], oldcwd.pair[1], oldid);
-    err = lfs_dir_delete(lfs, &oldcwd, oldid);
+    // clean up after ourselves
+    err = lfs_fixmove(lfs);
     if (err) {
         return err;
     }
 
-    // if we were a directory, find pred, replace tail
-    // TODO can this just deorphan?
     if (prevexists && lfs_tag_subtype(prevattr.tag) == LFS_TYPE_DIR) {
-        err = lfs_deorphan(lfs);
-        if (err) {
-            return err;
+        int res = lfs_pred(lfs, prevdir.pair, &newcwd);
+        if (res < 0) {
+            return res;
         }
+
+        LFS_ASSERT(res); // must have pred
+        newcwd.tail[0] = prevdir.tail[0];
+        newcwd.tail[1] = prevdir.tail[1];
+        err = lfs_dir_commit(lfs, &newcwd, &(lfs_mattrlist_t){
+                {lfs_mktag(LFS_TYPE_SOFTTAIL, 0x3ff, sizeof(newcwd.tail)),
+                    .u.buffer=newcwd.tail}});
     }
 
     return 0;
+    
+
+//    if (samepair) {
+//        // update pair if newcwd == oldcwd
+//        oldcwd = newcwd;
+//    }
+//
+//    err = fix
+//
+//    // remove old entry
+//    //printf("RENAME DELETE %d %d %d\n", oldcwd.pair[0], oldcwd.pair[1], oldid);
+//    err = lfs_dir_delete(lfs, &oldcwd, oldid);
+//    if (err) {
+//        return err;
+//    }
+//
+//    // if we were a directory, find pred, replace tail
+//    // TODO can this just deorphan?
+//    if (prevexists && lfs_tag_subtype(prevattr.tag) == LFS_TYPE_DIR) {
+//        err = lfs_deorphan(lfs);
+//        if (err) {
+//            return err;
+//        }
+//    }
+//
+    return 0;
 }
 
 //int lfs_getattrs(lfs_t *lfs, const char *path,
@@ -2954,7 +3077,17 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
     lfs->files = NULL;
     lfs->dirs = NULL;
     lfs->deorphaned = false;
-    lfs->idelete = (lfs_entry_t){{0xffffffff, 0xffffffff}, 0xffff};
+    lfs->globals.move.pair[0] = 0xffffffff;
+    lfs->globals.move.pair[1] = 0xffffffff;
+    lfs->globals.move.id = 0x3ff;
+    lfs->diff = (lfs_globals_t){0};
+
+    // scan for any global updates
+    // TODO rm me? need to grab any inits
+    int err = lfs_scan(lfs);
+    if (err) {
+        return err;
+    }
 
     return 0;
 }
@@ -3122,6 +3255,11 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
     lfs->root[0] = superblock.root[0];
     lfs->root[1] = superblock.root[1];
 
+    err = lfs_scan(lfs);
+    if (err) {
+        return err;
+    }
+
     return 0;
 }
 
@@ -3601,15 +3739,80 @@ static int lfs_relocate(lfs_t *lfs,
     return 0;
 }
 
+int lfs_scan(lfs_t *lfs) {
+    if (lfs_pairisnull(lfs->root)) { // TODO rm me
+        return 0;
+    }
+
+    lfs_mdir_t dir = {.tail = {0, 1}};
+    lfs_globals_t globals = {{{0xffffffff, 0xffffffff}, 0x3ff}};
+
+    // iterate over all directory directory entries
+    while (!lfs_pairisnull(dir.tail)) {
+        int err = lfs_dir_fetch(lfs, &dir, dir.tail);
+        if (err) {
+            return err;
+        }
+
+        // xor together indirect deletes
+        globals = lfs_globals_xor(&globals, &dir.globals);
+    }
+
+    // update littlefs with globals
+    lfs->globals = globals;
+    lfs->diff = (lfs_globals_t){0};
+    if (!lfs_pairisnull(lfs->globals.move.pair)) {
+        LFS_DEBUG("Found move %d %d %d",
+                lfs->globals.move.pair[0],
+                lfs->globals.move.pair[1],
+                lfs->globals.move.id);
+    }
+
+    return 0;
+}
+
+int lfs_fixmove(lfs_t *lfs) {
+    LFS_DEBUG("Fixing move %d %d %d", // TODO move to just deorphan
+            lfs->globals.move.pair[0],
+            lfs->globals.move.pair[1],
+            lfs->globals.move.id);
+
+    // mark global state to clear move entry
+    lfs->diff.move.pair[0] = 0xffffffff ^ lfs->globals.move.pair[0];
+    lfs->diff.move.pair[1] = 0xffffffff ^ lfs->globals.move.pair[1];
+    lfs->diff.move.id      = 0x3ff      ^ lfs->globals.move.id;
+
+    // fetch and delete the moved entry
+    lfs_mdir_t movedir;
+    int err = lfs_dir_fetch(lfs, &movedir, lfs->globals.move.pair);
+    if (err) {
+        return err;
+    }
+
+    err = lfs_dir_delete(lfs, &movedir, lfs->globals.move.id);
+    if (err) {
+        return err;
+    }
+
+    return 0;
+}
+
 int lfs_deorphan(lfs_t *lfs) {
     lfs->deorphaned = true;
-    if (lfs_pairisnull(lfs->root)) {
+    if (lfs_pairisnull(lfs->root)) { // TODO rm me?
         return 0;
     }
 
+    // Fix bad moves
+    if (!lfs_pairisnull(lfs->globals.move.pair)) {
+        int err = lfs_fixmove(lfs);
+        if (err) {
+            return err;
+        }
+    }
+
     lfs_mdir_t pdir = {.split = true};
     lfs_mdir_t dir = {.tail = {0, 1}};
-    lfs_entry_t idelete = {{0xffffffff, 0xffffffff}, 0xffff};
 
     // iterate over all directory directory entries
     while (!lfs_pairisnull(dir.tail)) {
@@ -3618,11 +3821,6 @@ int lfs_deorphan(lfs_t *lfs) {
             return err;
         }
 
-        // xor together indirect deletes
-        idelete.pair[0] ^= dir.idelete.pair[0];
-        idelete.pair[1] ^= dir.idelete.pair[1];
-        idelete.id      ^= dir.idelete.id;
-
         // check head blocks for orphans
         if (!pdir.split) {
             // check if we have a parent
@@ -3671,7 +3869,7 @@ int lfs_deorphan(lfs_t *lfs) {
         }
 
         // check entries for moves
-        if (dir.moveid >= 0) {
+        //if (dir.moveid >= 0) {
 // TODO moves and stuff
                     // TODO need to load entry to find it
 //                    // found moved entry
@@ -3698,15 +3896,11 @@ int lfs_deorphan(lfs_t *lfs) {
 //                            return err;
 //                        }
 //                    }
-        }
+        //}
 
         memcpy(&pdir, &dir, sizeof(pdir));
     }
 
-    // update littlefs with current move
-    // TODO do this here? needs to be before reads also
-    lfs->idelete = idelete;
-
     return 0;
 }
 /*

+ 15 - 8
lfs.h

@@ -129,7 +129,7 @@ enum lfs_type {
     // internal sources
     LFS_FROM_REGION     = 0x000,
     LFS_FROM_DISK       = 0x200,
-    LFS_FROM_MOVE       = 0x004,
+    LFS_FROM_MOVE       = 0x0ff,
 };
 
 // File open flags
@@ -296,10 +296,17 @@ typedef struct lfs_mattrlist {
     struct lfs_mattrlist *next;
 } lfs_mattrlist_t;
 
-typedef struct lfs_entry {
-    lfs_block_t pair[2];
-    uint16_t id;
-} lfs_entry_t;
+//typedef struct lfs_entry {
+//    lfs_block_t pair[2];
+//    uint16_t id;
+//} lfs_entry_t;
+
+typedef struct lfs_globals {
+    struct lfs_move {
+        lfs_block_t pair[2];
+        uint16_t id;
+    } move;
+} lfs_globals_t;
 
 typedef struct lfs_mdir {
     lfs_block_t pair[2];
@@ -310,7 +317,7 @@ typedef struct lfs_mdir {
     uint16_t count;
     bool erased;
     bool split;
-    lfs_entry_t idelete;
+    lfs_globals_t globals;
     bool stop_at_commit; // TODO hmmm
     uint16_t moveid; // TODO rm me
 } lfs_mdir_t;
@@ -380,8 +387,8 @@ typedef struct lfs {
 
     lfs_free_t free;
     bool deorphaned;
-    lfs_entry_t idelete;
-    lfs_entry_t diff;
+    lfs_globals_t globals;
+    lfs_globals_t diff;
 
     lfs_size_t inline_size;
     lfs_size_t attrs_size;

+ 29 - 3
tests/test_move.sh

@@ -59,7 +59,7 @@ tests/test.py << TEST
     lfs_rename(&lfs, "b/hello", "c/hello") => 0;
     lfs_unmount(&lfs) => 0;
 TEST
-truncate -s-7 blocks/6
+truncate -s-11 blocks/6
 tests/test.py << TEST
     lfs_mount(&lfs, &cfg) => 0;
     lfs_dir_open(&lfs, &dir[0], "b") => 0;
@@ -86,8 +86,8 @@ tests/test.py << TEST
     lfs_rename(&lfs, "c/hello", "d/hello") => 0;
     lfs_unmount(&lfs) => 0;
 TEST
-truncate -s-7 blocks/8
-truncate -s-7 blocks/a
+truncate -s-11 blocks/8
+truncate -s-11 blocks/a
 tests/test.py << TEST
     lfs_mount(&lfs, &cfg) => 0;
     lfs_dir_open(&lfs, &dir[0], "c") => 0;
@@ -108,6 +108,32 @@ tests/test.py << TEST
     lfs_unmount(&lfs) => 0;
 TEST
 
+echo "--- Move file after corrupt ---"
+tests/test.py -s << TEST
+    lfs_mount(&lfs, &cfg) => 0;
+    lfs_rename(&lfs, "c/hello", "d/hello") => 0;
+    lfs_unmount(&lfs) => 0;
+TEST
+tests/test.py << TEST
+    lfs_mount(&lfs, &cfg) => 0;
+    lfs_dir_open(&lfs, &dir[0], "c") => 0;
+    lfs_dir_read(&lfs, &dir[0], &info) => 1;
+    strcmp(info.name, ".") => 0;
+    lfs_dir_read(&lfs, &dir[0], &info) => 1;
+    strcmp(info.name, "..") => 0;
+    lfs_dir_read(&lfs, &dir[0], &info) => 0;
+    lfs_dir_close(&lfs, &dir[0]) => 0;
+    lfs_dir_open(&lfs, &dir[0], "d") => 0;
+    lfs_dir_read(&lfs, &dir[0], &info) => 1;
+    strcmp(info.name, ".") => 0;
+    lfs_dir_read(&lfs, &dir[0], &info) => 1;
+    strcmp(info.name, "..") => 0;
+    lfs_dir_read(&lfs, &dir[0], &info) => 1;
+    strcmp(info.name, "hello") => 0;
+    lfs_dir_read(&lfs, &dir[0], &info) => 0;
+    lfs_unmount(&lfs) => 0;
+TEST
+
 echo "--- Move dir ---"
 tests/test.py << TEST
     lfs_mount(&lfs, &cfg) => 0;