Applied, thanks!

Milos Nikic, le mar. 06 oct. 2026 20:56:39 -0700, a ecrit:
> 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 <[1][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
> 
> 
> 
> References:
> 
> [1] mailto:[email protected]

> 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
> 


-- 
Samuel
<y> le y est un animal discret se logeant facilement dans un terminal
*** c has changed the topic on channel #ens-mim to ne pas jeter de cacahuetes 
aux ys, svp
 -+- #ens-mim - n'oubliez pas le guide -+-

Reply via email to