A node from dir_mkfile has no links from the start but was never put on
the orphan list: after a crash while it was open, e2fsck found an inode
in use without links and freed it as an error. Add it to the list
before its first update, as ext4 does for O_TMPFILE.
dir_link left a file on the orphan list when it gave it a link, so the
list held a linked file, which recovery would treat as an unfinished
truncation. Take it off.
---
libdiskfs/dir-link.c | 4 ++++
libdiskfs/node-create.c | 6 ++++++
2 files changed, 10 insertions(+)
diff --git a/libdiskfs/dir-link.c b/libdiskfs/dir-link.c
index 29567e7a6..0b09c83df 100644
--- a/libdiskfs/dir-link.c
+++ b/libdiskfs/dir-link.c
@@ -110,6 +110,10 @@ try_link (struct protid *dircred,
}
np->dn_stat.st_nlink++;
np->dn_set_ctime = 1;
+ /* A file with no links (dir_mkfile's, or one unlinked while open) is
+ on the orphan list, which recovery would free it from. */
+ if (np->dn_stat.st_nlink == 1)
+ diskfs_orphan_del (np);
diskfs_node_update (np, diskfs_synchronous);
/* Attach it */
diff --git a/libdiskfs/node-create.c b/libdiskfs/node-create.c
index 56d548f75..2d58a6e23 100644
--- a/libdiskfs/node-create.c
+++ b/libdiskfs/node-create.c
@@ -132,6 +132,12 @@ diskfs_create_node (struct node *dir,
if (S_ISDIR (mode))
err = diskfs_init_dir (np, dir, cred);
+ /* With no name the node has no links from the start (dir_mkfile).
+ Put it on the orphan list, so that after a crash before its last
+ close, recovery frees it rather than e2fsck finding it in use. */
+ if (!err && !name)
+ diskfs_orphan_add (np);
+
diskfs_node_update (np, diskfs_synchronous);
if (err)
--
2.56.0