Hello, Seems like this somehow didn't make it all the way to the mailing list so i am reposting it hoping it will this time! ... and re-attaching the patch explicitly.
Its a cleanup, one liner that squashes a reproducible freeze under specific conditions (disk full, and create node fails) Thanks, Milos On Mon, Oct 5, 2026 at 9:16 PM Milos Nikic <[email protected]> wrote: > diskfs_alloc_node returns the new node locked and with a hard > reference. When diskfs_create_node then fails before entering the node > in the directory, for instance because diskfs_init_dir finds no free > block for a new directory, the error path cleared the mode and link > count and returned without releasing the node! The node stayed locked > for good, and its inode stayed allocated on disk until e2fsck freed it. > > The next diskfs_node_iterate then waits for that lock forever. Without > a journal this stops the periodic sync until reboot silently. > With a journal the periodic sync holds a handle while it waits, so the > commit > cannot drain and every new RPC blocks behind it. > Running mkdir on a full filesystem is enough to trigger it. > > Release the node with diskfs_nput. As it is unlinked, diskfs_drop_node > truncates it and frees its inode. Keep the file type in st_mode rather > than clearing it, since diskfs_drop_node passes the mode to > diskfs_free_node, and ext2fs uses it to undo the used directories count > that ext2_alloc_inode took for a directory. > --- > libdiskfs/node-create.c | 7 ++++++- > 1 file changed, 6 insertions(+), 1 deletion(-) > > diff --git a/libdiskfs/node-create.c b/libdiskfs/node-create.c > index 28d2c6e34..56d548f75 100644 > --- a/libdiskfs/node-create.c > +++ b/libdiskfs/node-create.c > @@ -137,11 +137,16 @@ diskfs_create_node (struct node *dir, > if (err) > { > change_err: > - np->dn_stat.st_mode = 0; > + /* Hand the inode back: dropping the last reference to an unlinked > + node truncates and frees it. Keep the file type so that > + diskfs_free_node undoes what diskfs_alloc_node accounted for it, > + such as the count of used directories. */ > + np->dn_stat.st_mode = mode & S_IFMT; > np->dn_stat.st_nlink = 0; > if (name) > diskfs_drop_dirstat (dir, ds); > *newnode = NULL; > + diskfs_nput (np); > return err; > } > > -- > 2.56.0 > >
From 8184b0a8dc24cf60aef5ff45d469ba297f6a5c2d Mon Sep 17 00:00:00 2001 From: Milos Nikic <[email protected]> Date: Mon, 5 Oct 2026 20:51:51 -0700 Subject: [PATCH] libdiskfs: Release the new node when diskfs_create_node fails diskfs_alloc_node returns the new node locked and with a hard reference. When diskfs_create_node then fails before entering the node in the directory, for instance because diskfs_init_dir finds no free block for a new directory, the error path cleared the mode and link count and returned without releasing the node! The node stayed locked for good, and its inode stayed allocated on disk until e2fsck freed it. The next diskfs_node_iterate then waits for that lock forever. Without a journal this stops the periodic sync until reboot silently. With a journal the periodic sync holds a handle while it waits, so the commit cannot drain and every new RPC blocks behind it. Running mkdir on a full filesystem is enough to trigger it. Release the node with diskfs_nput. As it is unlinked, diskfs_drop_node truncates it and frees its inode. Keep the file type in st_mode rather than clearing it, since diskfs_drop_node passes the mode to diskfs_free_node, and ext2fs uses it to undo the used directories count that ext2_alloc_inode took for a directory. --- libdiskfs/node-create.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libdiskfs/node-create.c b/libdiskfs/node-create.c index 28d2c6e34..56d548f75 100644 --- a/libdiskfs/node-create.c +++ b/libdiskfs/node-create.c @@ -137,11 +137,16 @@ diskfs_create_node (struct node *dir, if (err) { change_err: - np->dn_stat.st_mode = 0; + /* Hand the inode back: dropping the last reference to an unlinked + node truncates and frees it. Keep the file type so that + diskfs_free_node undoes what diskfs_alloc_node accounted for it, + such as the count of used directories. */ + np->dn_stat.st_mode = mode & S_IFMT; np->dn_stat.st_nlink = 0; if (name) diskfs_drop_dirstat (dir, ds); *newnode = NULL; + diskfs_nput (np); return err; } -- 2.56.0
