mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 0/3] ntfs: fix mount failure cleanup and free-count setup
@ 2026-05-20 17:01 DaeMyung Kang
  2026-05-20 17:01 ` [PATCH 1/3] ntfs: free volume-wide resources on fill_super failure DaeMyung Kang
                   ` (5 more replies)
  0 siblings, 6 replies; 23+ messages in thread
From: DaeMyung Kang @ 2026-05-20 17:01 UTC (permalink / raw)
  To: Namjae Jeon; +Cc: Hyunchul Lee, linux-fsdevel, linux-kernel, DaeMyung Kang

Hi Namjae,

This small series is based on current ntfs-next commit d8756162c6ca
("ntfs: remove unsupported quota handling").

The previous quota_ino reference leak fix is intentionally dropped
because that commit removes load_and_init_quota(), the $Quota/$Q state,
and the quota out-of-date marker path.

The remaining fixes cover mount failure cleanup, a free-cluster precalc
OOM path that can otherwise leave waiters blocked forever, and the
$UpCase default-table alias check.  The free-cluster patch also clears
the per-bitmap-page free counters on the conservative zero-free-count
path so later allocation heuristics stay conservative after the known
flag is published.

Testing:
- For patch 1, I built a DEBUG_KMEMLEAK/DEBUG_FS kernel and injected an
  ntfs_fill_super() failure immediately after load_system_files().  Before
  the fix, kmemleak reported the leaked volume label allocated from
  ntfs_ucstonls(); after the fix, the same failure path produced no
  kmemleak report.
- For patch 2, I used QEMU with a debug injection that forces the initial
  precalc readahead-state allocation to fail.  Before the fix, statfs
  remained blocked in D state in ntfs_statfs(); after the fix, the waiter
  woke up and statfs returned with the conservative zero free-cluster
  count.

DaeMyung Kang (3):
  ntfs: free volume-wide resources on fill_super failure
  ntfs: wake free-cluster waiters when precalc allocation fails
  ntfs: only alias volume $UpCase to default on exact match

 super.c | 34 ++++++++++++++++++++++------------
 1 file changed, 22 insertions(+), 12 deletions(-)


base-commit: d8756162c6cab1ad4478539d33da6cab413af1ee
-- 
2.43.0

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 1/3] ntfs: free volume-wide resources on fill_super failure
  2026-05-20 17:01 [PATCH 0/3] ntfs: fix mount failure cleanup and free-count setup DaeMyung Kang
@ 2026-05-20 17:01 ` DaeMyung Kang
  2026-05-21  1:03   ` Hyunchul Lee
  2026-05-20 17:01 ` [PATCH 2/3] ntfs: wake free-cluster waiters when precalc allocation fails DaeMyung Kang
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 23+ messages in thread
From: DaeMyung Kang @ 2026-05-20 17:01 UTC (permalink / raw)
  To: Namjae Jeon; +Cc: Hyunchul Lee, linux-fsdevel, linux-kernel, DaeMyung Kang

ntfs_fill_super()'s err_out_now path frees only the volume struct via
kfree(vol), leaving several vol-owned allocations behind on mount
failure.

vol->nls_map is loaded by ntfs_init_fs_context() via load_nls_default()
or replaced by an explicit nls= option in ntfs_parse_param().
vol->volume_label is allocated by load_system_files() once the $Volume
name attribute has been parsed.  vol->lcn_empty_bits_per_page is
allocated before load_system_files() and was freed only from the upper
error label.

Move these per-volume frees to err_out_now so every failure path
releases them exactly once.

Signed-off-by: DaeMyung Kang <charsyam@gmail.com>
---
 super.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/super.c b/super.c
index f93f0f8bcc45..6cf09bbe017d 100644
--- a/super.c
+++ b/super.c
@@ -2638,8 +2638,6 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
 	}
 	/* Error exit code path. */
 unl_upcase_iput_tmp_ino_err_out_now:
-	if (vol->lcn_empty_bits_per_page)
-		kvfree(vol->lcn_empty_bits_per_page);
 	/*
 	 * Decrease the number of upcase users and destroy the global default
 	 * upcase table if necessary.
@@ -2659,6 +2657,9 @@ iput_tmp_ino_err_out_now:
 	/* Errors at this stage are irrelevant. */
 err_out_now:
 	sb->s_fs_info = NULL;
+	kvfree(vol->lcn_empty_bits_per_page);
+	kfree(vol->volume_label);
+	unload_nls(vol->nls_map);
 	kfree(vol);
 	ntfs_debug("Failed, returning -EINVAL.");
 	lockdep_on();
-- 
2.43.0


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 2/3] ntfs: wake free-cluster waiters when precalc allocation fails
  2026-05-20 17:01 [PATCH 0/3] ntfs: fix mount failure cleanup and free-count setup DaeMyung Kang
  2026-05-20 17:01 ` [PATCH 1/3] ntfs: free volume-wide resources on fill_super failure DaeMyung Kang
@ 2026-05-20 17:01 ` DaeMyung Kang
  2026-05-21  1:03   ` Hyunchul Lee
  2026-05-20 17:01 ` [PATCH 3/3] ntfs: only alias volume $UpCase to default on exact match DaeMyung Kang
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 23+ messages in thread
From: DaeMyung Kang @ 2026-05-20 17:01 UTC (permalink / raw)
  To: Namjae Jeon; +Cc: Hyunchul Lee, linux-fsdevel, linux-kernel, DaeMyung Kang

get_nr_free_clusters() is run from the precalc_free_clusters() worker
queued at the end of ntfs_fill_super().  It is also the only place that
publishes the result by atomic64_set(&vol->free_clusters, ...), sets
NVolSetFreeClusterKnown(), and wakes vol->free_waitq.

The initial kzalloc(sizeof(*ra), ...) can fail before that publication
happens.  Callers that need the free count wait on NVolFreeClusterKnown(),
so this failure can leave statfs, write, and allocation paths blocked
forever.

On the OOM path, publish a conservative free count of zero, initialize
the per-bitmap-page free counters to zero, set NVolFreeClusterKnown, and
wake the wait queue so callers fail with -ENOSPC rather than block
forever.

Signed-off-by: DaeMyung Kang <charsyam@gmail.com>
---
 super.c | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/super.c b/super.c
index 6cf09bbe017d..c90cb5673f98 100644
--- a/super.c
+++ b/super.c
@@ -1980,8 +1980,23 @@ s64 get_nr_free_clusters(struct ntfs_volume *vol)
 		return atomic64_read(&vol->free_clusters);
 
 	ra = kzalloc(sizeof(*ra), GFP_NOFS);
-	if (!ra)
+	if (!ra) {
+		max_index = (((vol->nr_clusters + 7) >> 3) +
+				PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+		/*
+		 * Publish a conservative free count and wake any waiters; the
+		 * NVolFreeClusterKnown flag is the sole signal the wait_event
+		 * loops in statfs/allocation paths use, so failing to set it
+		 * here would leave those callers blocked forever.
+		 */
+		memset(vol->lcn_empty_bits_per_page, 0,
+		       max_index * sizeof(*vol->lcn_empty_bits_per_page));
+		atomic64_set(&vol->free_clusters, 0);
+		NVolSetFreeClusterKnown(vol);
+		wake_up_all(&vol->free_waitq);
 		return 0;
+	}
 
 	file_ra_state_init(ra, mapping);
 
-- 
2.43.0


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 3/3] ntfs: only alias volume $UpCase to default on exact match
  2026-05-20 17:01 [PATCH 0/3] ntfs: fix mount failure cleanup and free-count setup DaeMyung Kang
  2026-05-20 17:01 ` [PATCH 1/3] ntfs: free volume-wide resources on fill_super failure DaeMyung Kang
  2026-05-20 17:01 ` [PATCH 2/3] ntfs: wake free-cluster waiters when precalc allocation fails DaeMyung Kang
@ 2026-05-20 17:01 ` DaeMyung Kang
  2026-05-21  1:04   ` Hyunchul Lee
  2026-05-21  1:02 ` [PATCH 0/3] ntfs: fix mount failure cleanup and free-count setup Hyunchul Lee
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 23+ messages in thread
From: DaeMyung Kang @ 2026-05-20 17:01 UTC (permalink / raw)
  To: Namjae Jeon; +Cc: Hyunchul Lee, linux-fsdevel, linux-kernel, DaeMyung Kang

load_and_init_upcase() currently aliases vol->upcase to the global
default upcase whenever the shared prefix matches, and then truncates
vol->upcase_len to that shorter prefix.  The result is correct only by
accident: upcase[] accesses in name collation are gated by upcase_len,
so the prefix-equality alias produces the same fold output as keeping
the volume's own shorter table.

Still, prefix equality is not equality: the volume table is logically
distinct from the default and should not be replaced by it unless they
are byte-for-byte identical.  Use memcmp() to compare the complete table
in one expression and drop the now-redundant upcase_len rewrite.

No user-visible change is expected for compliant volumes whose $UpCase
has exactly default_upcase_len entries; shorter volume tables are no
longer aliased to the default.

Signed-off-by: DaeMyung Kang <charsyam@gmail.com>
---
 super.c | 12 +++---------
 1 file changed, 3 insertions(+), 9 deletions(-)

diff --git a/super.c b/super.c
index c90cb5673f98..811640cf5669 100644
--- a/super.c
+++ b/super.c
@@ -1344,7 +1344,6 @@ static bool load_and_init_upcase(struct ntfs_volume *vol)
 #endif
 	pgoff_t index, max_index;
 	unsigned int size;
-	int i, max;
 
 	ntfs_debug("Entering.");
 	/* Read upcase table and setup vol->upcase and vol->upcase_len. */
@@ -1405,16 +1404,11 @@ read_partial_upcase_page:
 		mutex_unlock(&ntfs_lock);
 		return true;
 	}
-	max = default_upcase_len;
-	if (max > vol->upcase_len)
-		max = vol->upcase_len;
-	for (i = 0; i < max; i++)
-		if (vol->upcase[i] != default_upcase[i])
-			break;
-	if (i == max) {
+	if (default_upcase_len == vol->upcase_len &&
+	    !memcmp(vol->upcase, default_upcase,
+		    default_upcase_len * sizeof(*default_upcase))) {
 		kvfree(vol->upcase);
 		vol->upcase = default_upcase;
-		vol->upcase_len = max;
 		ntfs_nr_upcase_users++;
 		mutex_unlock(&ntfs_lock);
 		ntfs_debug("Volume specified $UpCase matches default. Using default.");
-- 
2.43.0

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 0/3] ntfs: fix mount failure cleanup and free-count setup
  2026-05-20 17:01 [PATCH 0/3] ntfs: fix mount failure cleanup and free-count setup DaeMyung Kang
                   ` (2 preceding siblings ...)
  2026-05-20 17:01 ` [PATCH 3/3] ntfs: only alias volume $UpCase to default on exact match DaeMyung Kang
@ 2026-05-21  1:02 ` Hyunchul Lee
  2026-05-21 10:17 ` [PATCH v2 " DaeMyung Kang
  2026-05-21 13:00 ` [PATCH v3 0/3] ntfs: fix mount failure cleanup and free-count setup DaeMyung Kang
  5 siblings, 0 replies; 23+ messages in thread
From: Hyunchul Lee @ 2026-05-21  1:02 UTC (permalink / raw)
  To: DaeMyung Kang; +Cc: Namjae Jeon, linux-fsdevel, linux-kernel

Hi DaeMyung,

2026년 5월 21일 (목) 오전 2:01, DaeMyung Kang <charsyam@gmail.com>님이 작성:
>
> Hi Namjae,
>
> This small series is based on current ntfs-next commit d8756162c6ca
> ("ntfs: remove unsupported quota handling").

These patches appear to be intended for an out of tree version on Github.
They need to be ported for the Linux kernel.


>
> The previous quota_ino reference leak fix is intentionally dropped
> because that commit removes load_and_init_quota(), the $Quota/$Q state,
> and the quota out-of-date marker path.
>
> The remaining fixes cover mount failure cleanup, a free-cluster precalc
> OOM path that can otherwise leave waiters blocked forever, and the
> $UpCase default-table alias check.  The free-cluster patch also clears
> the per-bitmap-page free counters on the conservative zero-free-count
> path so later allocation heuristics stay conservative after the known
> flag is published.
>
> Testing:
> - For patch 1, I built a DEBUG_KMEMLEAK/DEBUG_FS kernel and injected an
>   ntfs_fill_super() failure immediately after load_system_files().  Before
>   the fix, kmemleak reported the leaked volume label allocated from
>   ntfs_ucstonls(); after the fix, the same failure path produced no
>   kmemleak report.
> - For patch 2, I used QEMU with a debug injection that forces the initial
>   precalc readahead-state allocation to fail.  Before the fix, statfs
>   remained blocked in D state in ntfs_statfs(); after the fix, the waiter
>   woke up and statfs returned with the conservative zero free-cluster
>   count.
>
> DaeMyung Kang (3):
>   ntfs: free volume-wide resources on fill_super failure
>   ntfs: wake free-cluster waiters when precalc allocation fails
>   ntfs: only alias volume $UpCase to default on exact match
>
>  super.c | 34 ++++++++++++++++++++++------------
>  1 file changed, 22 insertions(+), 12 deletions(-)
>
>
> base-commit: d8756162c6cab1ad4478539d33da6cab413af1ee
> --
> 2.43.0



--
Thanks,
Hyunchul

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 1/3] ntfs: free volume-wide resources on fill_super failure
  2026-05-20 17:01 ` [PATCH 1/3] ntfs: free volume-wide resources on fill_super failure DaeMyung Kang
@ 2026-05-21  1:03   ` Hyunchul Lee
  0 siblings, 0 replies; 23+ messages in thread
From: Hyunchul Lee @ 2026-05-21  1:03 UTC (permalink / raw)
  To: DaeMyung Kang; +Cc: Namjae Jeon, linux-fsdevel, linux-kernel

2026년 5월 21일 (목) 오전 2:01, DaeMyung Kang <charsyam@gmail.com>님이 작성:
>
> ntfs_fill_super()'s err_out_now path frees only the volume struct via
> kfree(vol), leaving several vol-owned allocations behind on mount
> failure.
>
> vol->nls_map is loaded by ntfs_init_fs_context() via load_nls_default()
> or replaced by an explicit nls= option in ntfs_parse_param().
> vol->volume_label is allocated by load_system_files() once the $Volume
> name attribute has been parsed.  vol->lcn_empty_bits_per_page is
> allocated before load_system_files() and was freed only from the upper
> error label.
>
> Move these per-volume frees to err_out_now so every failure path
> releases them exactly once.
>
> Signed-off-by: DaeMyung Kang <charsyam@gmail.com>

Looks good to me.

Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>

> ---
>  super.c | 5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/super.c b/super.c
> index f93f0f8bcc45..6cf09bbe017d 100644
> --- a/super.c
> +++ b/super.c
> @@ -2638,8 +2638,6 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
>         }
>         /* Error exit code path. */
>  unl_upcase_iput_tmp_ino_err_out_now:
> -       if (vol->lcn_empty_bits_per_page)
> -               kvfree(vol->lcn_empty_bits_per_page);
>         /*
>          * Decrease the number of upcase users and destroy the global default
>          * upcase table if necessary.
> @@ -2659,6 +2657,9 @@ iput_tmp_ino_err_out_now:
>         /* Errors at this stage are irrelevant. */
>  err_out_now:
>         sb->s_fs_info = NULL;
> +       kvfree(vol->lcn_empty_bits_per_page);
> +       kfree(vol->volume_label);
> +       unload_nls(vol->nls_map);
>         kfree(vol);
>         ntfs_debug("Failed, returning -EINVAL.");
>         lockdep_on();
> --
> 2.43.0
>


-- 
Thanks,
Hyunchul

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 2/3] ntfs: wake free-cluster waiters when precalc allocation fails
  2026-05-20 17:01 ` [PATCH 2/3] ntfs: wake free-cluster waiters when precalc allocation fails DaeMyung Kang
@ 2026-05-21  1:03   ` Hyunchul Lee
  0 siblings, 0 replies; 23+ messages in thread
From: Hyunchul Lee @ 2026-05-21  1:03 UTC (permalink / raw)
  To: DaeMyung Kang; +Cc: Namjae Jeon, linux-fsdevel, linux-kernel

2026년 5월 21일 (목) 오전 2:02, DaeMyung Kang <charsyam@gmail.com>님이 작성:
>
> get_nr_free_clusters() is run from the precalc_free_clusters() worker
> queued at the end of ntfs_fill_super().  It is also the only place that
> publishes the result by atomic64_set(&vol->free_clusters, ...), sets
> NVolSetFreeClusterKnown(), and wakes vol->free_waitq.
>
> The initial kzalloc(sizeof(*ra), ...) can fail before that publication
> happens.  Callers that need the free count wait on NVolFreeClusterKnown(),
> so this failure can leave statfs, write, and allocation paths blocked
> forever.
>
> On the OOM path, publish a conservative free count of zero, initialize
> the per-bitmap-page free counters to zero, set NVolFreeClusterKnown, and
> wake the wait queue so callers fail with -ENOSPC rather than block
> forever.
>
> Signed-off-by: DaeMyung Kang <charsyam@gmail.com>
> ---
>  super.c | 17 ++++++++++++++++-
>  1 file changed, 16 insertions(+), 1 deletion(-)
>
> diff --git a/super.c b/super.c
> index 6cf09bbe017d..c90cb5673f98 100644
> --- a/super.c
> +++ b/super.c
> @@ -1980,8 +1980,23 @@ s64 get_nr_free_clusters(struct ntfs_volume *vol)
>                 return atomic64_read(&vol->free_clusters);
>
>         ra = kzalloc(sizeof(*ra), GFP_NOFS);
> -       if (!ra)

How about declaring ra as a stack variable?

> +       if (!ra) {
> +               max_index = (((vol->nr_clusters + 7) >> 3) +
> +                               PAGE_SIZE - 1) >> PAGE_SHIFT;
> +
> +               /*
> +                * Publish a conservative free count and wake any waiters; the
> +                * NVolFreeClusterKnown flag is the sole signal the wait_event
> +                * loops in statfs/allocation paths use, so failing to set it
> +                * here would leave those callers blocked forever.
> +                */
> +               memset(vol->lcn_empty_bits_per_page, 0,
> +                      max_index * sizeof(*vol->lcn_empty_bits_per_page));
> +               atomic64_set(&vol->free_clusters, 0);
> +               NVolSetFreeClusterKnown(vol);
> +               wake_up_all(&vol->free_waitq);
>                 return 0;
> +       }
>
>         file_ra_state_init(ra, mapping);
>
> --
> 2.43.0
>


--
Thanks,
Hyunchul

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 3/3] ntfs: only alias volume $UpCase to default on exact match
  2026-05-20 17:01 ` [PATCH 3/3] ntfs: only alias volume $UpCase to default on exact match DaeMyung Kang
@ 2026-05-21  1:04   ` Hyunchul Lee
  0 siblings, 0 replies; 23+ messages in thread
From: Hyunchul Lee @ 2026-05-21  1:04 UTC (permalink / raw)
  To: DaeMyung Kang; +Cc: Namjae Jeon, linux-fsdevel, linux-kernel

2026년 5월 21일 (목) 오전 2:02, DaeMyung Kang <charsyam@gmail.com>님이 작성:
>
> load_and_init_upcase() currently aliases vol->upcase to the global
> default upcase whenever the shared prefix matches, and then truncates
> vol->upcase_len to that shorter prefix.  The result is correct only by
> accident: upcase[] accesses in name collation are gated by upcase_len,
> so the prefix-equality alias produces the same fold output as keeping
> the volume's own shorter table.
>
> Still, prefix equality is not equality: the volume table is logically
> distinct from the default and should not be replaced by it unless they
> are byte-for-byte identical.  Use memcmp() to compare the complete table
> in one expression and drop the now-redundant upcase_len rewrite.
>
> No user-visible change is expected for compliant volumes whose $UpCase
> has exactly default_upcase_len entries; shorter volume tables are no
> longer aliased to the default.
>
> Signed-off-by: DaeMyung Kang <charsyam@gmail.com>

Looks good to me.

Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>

> ---
>  super.c | 12 +++---------
>  1 file changed, 3 insertions(+), 9 deletions(-)
>
> diff --git a/super.c b/super.c
> index c90cb5673f98..811640cf5669 100644
> --- a/super.c
> +++ b/super.c
> @@ -1344,7 +1344,6 @@ static bool load_and_init_upcase(struct ntfs_volume *vol)
>  #endif
>         pgoff_t index, max_index;
>         unsigned int size;
> -       int i, max;
>
>         ntfs_debug("Entering.");
>         /* Read upcase table and setup vol->upcase and vol->upcase_len. */
> @@ -1405,16 +1404,11 @@ read_partial_upcase_page:
>                 mutex_unlock(&ntfs_lock);
>                 return true;
>         }
> -       max = default_upcase_len;
> -       if (max > vol->upcase_len)
> -               max = vol->upcase_len;
> -       for (i = 0; i < max; i++)
> -               if (vol->upcase[i] != default_upcase[i])
> -                       break;
> -       if (i == max) {
> +       if (default_upcase_len == vol->upcase_len &&
> +           !memcmp(vol->upcase, default_upcase,
> +                   default_upcase_len * sizeof(*default_upcase))) {
>                 kvfree(vol->upcase);
>                 vol->upcase = default_upcase;
> -               vol->upcase_len = max;
>                 ntfs_nr_upcase_users++;
>                 mutex_unlock(&ntfs_lock);
>                 ntfs_debug("Volume specified $UpCase matches default. Using default.");
> --
> 2.43.0



-- 
Thanks,
Hyunchul

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH v2 0/3] ntfs: fix mount failure cleanup and free-count setup
  2026-05-20 17:01 [PATCH 0/3] ntfs: fix mount failure cleanup and free-count setup DaeMyung Kang
                   ` (3 preceding siblings ...)
  2026-05-21  1:02 ` [PATCH 0/3] ntfs: fix mount failure cleanup and free-count setup Hyunchul Lee
@ 2026-05-21 10:17 ` DaeMyung Kang
  2026-05-21 10:17   ` [PATCH v2 1/3] ntfs: free volume-wide resources on fill_super failure DaeMyung Kang
                     ` (2 more replies)
  2026-05-21 13:00 ` [PATCH v3 0/3] ntfs: fix mount failure cleanup and free-count setup DaeMyung Kang
  5 siblings, 3 replies; 23+ messages in thread
From: DaeMyung Kang @ 2026-05-21 10:17 UTC (permalink / raw)
  To: Namjae Jeon, Hyunchul Lee; +Cc: linux-fsdevel, linux-kernel, DaeMyung Kang

Hi Namjae,

This v2 is ported to the Linux kernel tree and is based on current
mainline commit 8bc67e4db64a ("Merge tag 'erofs-for-7.1-rc5-fixes' of
git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs").  The
patches now modify fs/ntfs/super.c rather than the out-of-tree Github
layout.

The fixes cover mount failure cleanup, a free-cluster precalc allocation
failure path that can otherwise leave waiters blocked forever, and the
$UpCase default-table alias check.  Per review, the free-cluster patch
now avoids the temporary file_ra_state heap allocation entirely by using
a stack variable for the synchronous bitmap scan.

Testing:
- For patch 1, I built a DEBUG_KMEMLEAK/DEBUG_FS kernel and injected an
  ntfs_fill_super() failure immediately after load_system_files().  Before
  the fix, kmemleak reported the leaked volume label allocated from
  ntfs_ucstonls(); after the fix, the same failure path produced no
  kmemleak report.
- For patch 2, I used QEMU with a debug injection that forces the initial
  precalc readahead-state allocation to fail.  Before the fix, statfs
  remained blocked in D state in ntfs_statfs().  This version removes
  that heap allocation and therefore removes the injected failure point.
  I also mounted a fresh NTFS image with the stack-backed state and
  verified statfs reported the same free count as ntfsinfo -m.

Changes since v1:
- Rebased and regenerated the series for the Linux kernel tree
  (fs/ntfs/super.c), instead of the Github out-of-tree layout.
- Changed patch 2 to declare the temporary file_ra_state on the stack,
  as suggested by Hyunchul Lee, instead of adding an OOM fallback path.
- Zero-initialized patch 2's on-stack file_ra_state because
  file_ra_state_init() only initializes ra_pages and prev_pos.
- Reworded patch 3 to avoid overstating user-visible name comparison
  effects, and used memcmp() for the exact $UpCase table comparison.

DaeMyung Kang (3):
  ntfs: free volume-wide resources on fill_super failure
  ntfs: avoid heap allocation for free-cluster readahead state
  ntfs: only alias volume $UpCase to default on exact match

 fs/ntfs/super.c | 28 +++++++++-------------------
 1 file changed, 9 insertions(+), 19 deletions(-)


base-commit: 8bc67e4db64aa72732c474b44ea8622062c903f0
-- 
2.43.0

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH v2 1/3] ntfs: free volume-wide resources on fill_super failure
  2026-05-21 10:17 ` [PATCH v2 " DaeMyung Kang
@ 2026-05-21 10:17   ` DaeMyung Kang
  2026-05-21 10:17   ` [PATCH v2 2/3] ntfs: avoid heap allocation for free-cluster readahead state DaeMyung Kang
  2026-05-21 10:17   ` [PATCH v2 3/3] ntfs: only alias volume $UpCase to default on exact match DaeMyung Kang
  2 siblings, 0 replies; 23+ messages in thread
From: DaeMyung Kang @ 2026-05-21 10:17 UTC (permalink / raw)
  To: Namjae Jeon, Hyunchul Lee; +Cc: linux-fsdevel, linux-kernel, DaeMyung Kang

ntfs_fill_super()'s err_out_now path frees only the volume struct via
kfree(vol), leaving several vol-owned allocations behind on every mount
failure:

  - vol->nls_map, loaded by ntfs_init_fs_context() via
    load_nls_default() (or replaced by an explicit nls= option in
    ntfs_parse_param()), is never unload_nls()'d.

  - vol->volume_label, allocated by load_system_files() through
    ntfs_ucstonls() once the $Volume name attribute has been parsed, is
    not released by load_system_files()'s own error labels nor by the
    fill_super() inline cleanup that only runs on d_make_root()
    failure.  Any later failure inside load_system_files() leaks it.

  - vol->lcn_empty_bits_per_page was kvfree()'d in
    unl_upcase_iput_tmp_ino_err_out_now without clearing the pointer,
    so it could not be folded into a single common cleanup.

Because the failure paths never call ntfs_volume_free() and never reach
the d_make_root() inline cleanup block (it sits above the label and is
jumped over by the load_system_files() / kvmalloc failure gotos), these
resources accumulate per failed mount attempt with no chance of
recovery short of unloading the module.  This is a silent leak: the
inodes loaded prior to failure remain hashed but generic_shutdown_super()
skips evict_inodes() when sb->s_root is unset, so no CHECK_DATA_CORRUPTION
warning is emitted either.

Move the per-volume frees down to err_out_now and drop the
lcn_empty_bits_per_page kvfree() from the upper label so the cleanup is
performed exactly once on every failure path.  Using unconditional
kvfree() / kfree() / unload_nls() is safe because they all accept NULL
and the upper labels that previously freed nls_map (the d_make_root()
inline cleanup) already clear the pointer.

Signed-off-by: DaeMyung Kang <charsyam@gmail.com>
---
 fs/ntfs/super.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c
index 9e321cc2febe..7e3561265b47 100644
--- a/fs/ntfs/super.c
+++ b/fs/ntfs/super.c
@@ -2530,8 +2530,6 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
 	}
 	/* Error exit code path. */
 unl_upcase_iput_tmp_ino_err_out_now:
-	if (vol->lcn_empty_bits_per_page)
-		kvfree(vol->lcn_empty_bits_per_page);
 	/*
 	 * Decrease the number of upcase users and destroy the global default
 	 * upcase table if necessary.
@@ -2551,6 +2549,9 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
 	/* Errors at this stage are irrelevant. */
 err_out_now:
 	sb->s_fs_info = NULL;
+	kvfree(vol->lcn_empty_bits_per_page);
+	kfree(vol->volume_label);
+	unload_nls(vol->nls_map);
 	kfree(vol);
 	ntfs_debug("Failed, returning -EINVAL.");
 	lockdep_on();
-- 
2.43.0


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH v2 2/3] ntfs: avoid heap allocation for free-cluster readahead state
  2026-05-21 10:17 ` [PATCH v2 " DaeMyung Kang
  2026-05-21 10:17   ` [PATCH v2 1/3] ntfs: free volume-wide resources on fill_super failure DaeMyung Kang
@ 2026-05-21 10:17   ` DaeMyung Kang
  2026-05-21 12:19     ` Namjae Jeon
  2026-05-22  0:00     ` Hyunchul Lee
  2026-05-21 10:17   ` [PATCH v2 3/3] ntfs: only alias volume $UpCase to default on exact match DaeMyung Kang
  2 siblings, 2 replies; 23+ messages in thread
From: DaeMyung Kang @ 2026-05-21 10:17 UTC (permalink / raw)
  To: Namjae Jeon, Hyunchul Lee; +Cc: linux-fsdevel, linux-kernel, DaeMyung Kang

get_nr_free_clusters() is run from the precalc_free_clusters() worker
queued at the end of ntfs_fill_super().  It is also the only place that
publishes the result by atomic64_set(&vol->free_clusters, ...), sets
NVolSetFreeClusterKnown(), and wakes vol->free_waitq.

The function currently allocates a temporary file_ra_state with
kzalloc() before that publication happens.  If the allocation fails,
get_nr_free_clusters() returns 0 without setting NVolFreeClusterKnown()
or waking vol->free_waitq, so callers that wait for the free count can
block forever.

The readahead state is only used synchronously while scanning the bitmap
and struct file_ra_state is small.  Keep it on the stack and pass it to
the readahead helper by address, eliminating the early allocation
failure path.  Zero-initialize the on-stack state because
file_ra_state_init() only sets ra_pages and prev_pos.

Signed-off-by: DaeMyung Kang <charsyam@gmail.com>
---
 fs/ntfs/super.c | 11 +++--------
 1 file changed, 3 insertions(+), 8 deletions(-)

diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c
index 7e3561265b47..14fd244f29fe 100644
--- a/fs/ntfs/super.c
+++ b/fs/ntfs/super.c
@@ -1954,7 +1954,7 @@ s64 get_nr_free_clusters(struct ntfs_volume *vol)
 	struct address_space *mapping = vol->lcnbmp_ino->i_mapping;
 	struct folio *folio;
 	pgoff_t index, max_index;
-	struct file_ra_state *ra;
+	struct file_ra_state ra = {};
 
 	ntfs_debug("Entering.");
 	/* Serialize accesses to the cluster bitmap. */
@@ -1962,11 +1962,7 @@ s64 get_nr_free_clusters(struct ntfs_volume *vol)
 	if (NVolFreeClusterKnown(vol))
 		return atomic64_read(&vol->free_clusters);
 
-	ra = kzalloc(sizeof(*ra), GFP_NOFS);
-	if (!ra)
-		return 0;
-
-	file_ra_state_init(ra, mapping);
+	file_ra_state_init(&ra, mapping);
 
 	/*
 	 * Convert the number of bits into bytes rounded up, then convert into
@@ -1985,7 +1981,7 @@ s64 get_nr_free_clusters(struct ntfs_volume *vol)
 		 * Get folio from page cache, getting it from backing store
 		 * if necessary, and increment the use count.
 		 */
-		folio = ntfs_get_locked_folio(mapping, index, max_index, ra);
+		folio = ntfs_get_locked_folio(mapping, index, max_index, &ra);
 
 		/* Ignore pages which errored synchronously. */
 		if (IS_ERR(folio)) {
@@ -2024,7 +2020,6 @@ s64 get_nr_free_clusters(struct ntfs_volume *vol)
 	else
 		atomic64_set(&vol->free_clusters, nr_free);
 
-	kfree(ra);
 	NVolSetFreeClusterKnown(vol);
 	wake_up_all(&vol->free_waitq);
 	ntfs_debug("Exiting.");
-- 
2.43.0


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH v2 3/3] ntfs: only alias volume $UpCase to default on exact match
  2026-05-21 10:17 ` [PATCH v2 " DaeMyung Kang
  2026-05-21 10:17   ` [PATCH v2 1/3] ntfs: free volume-wide resources on fill_super failure DaeMyung Kang
  2026-05-21 10:17   ` [PATCH v2 2/3] ntfs: avoid heap allocation for free-cluster readahead state DaeMyung Kang
@ 2026-05-21 10:17   ` DaeMyung Kang
  2 siblings, 0 replies; 23+ messages in thread
From: DaeMyung Kang @ 2026-05-21 10:17 UTC (permalink / raw)
  To: Namjae Jeon, Hyunchul Lee; +Cc: linux-fsdevel, linux-kernel, DaeMyung Kang

load_and_init_upcase() currently aliases vol->upcase to the global
default upcase whenever the shared prefix matches, and then truncates
vol->upcase_len to that shorter prefix.  The result is correct only by
accident: upcase[] accesses in name collation are gated by upcase_len,
so the prefix-equality alias produces the same fold output as keeping
the volume's own shorter table.

Still, prefix equality is not equality: the volume table is logically
distinct from the default and should not be replaced by it unless they
are byte-for-byte identical.  Use memcmp() to compare the complete table
in one expression and drop the now-redundant upcase_len rewrite.

No user-visible change is expected for compliant volumes whose $UpCase
has exactly default_upcase_len entries; shorter volume tables are no
longer aliased to the default.

Signed-off-by: DaeMyung Kang <charsyam@gmail.com>
---
 fs/ntfs/super.c | 12 +++---------
 1 file changed, 3 insertions(+), 9 deletions(-)

diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c
index 14fd244f29fe..971c2822f5e3 100644
--- a/fs/ntfs/super.c
+++ b/fs/ntfs/super.c
@@ -1323,7 +1323,6 @@ static bool load_and_init_upcase(struct ntfs_volume *vol)
 	u8 *addr;
 	pgoff_t index, max_index;
 	unsigned int size;
-	int i, max;
 
 	ntfs_debug("Entering.");
 	/* Read upcase table and setup vol->upcase and vol->upcase_len. */
@@ -1374,16 +1373,11 @@ static bool load_and_init_upcase(struct ntfs_volume *vol)
 		mutex_unlock(&ntfs_lock);
 		return true;
 	}
-	max = default_upcase_len;
-	if (max > vol->upcase_len)
-		max = vol->upcase_len;
-	for (i = 0; i < max; i++)
-		if (vol->upcase[i] != default_upcase[i])
-			break;
-	if (i == max) {
+	if (default_upcase_len == vol->upcase_len &&
+	    !memcmp(vol->upcase, default_upcase,
+		    default_upcase_len * sizeof(*default_upcase))) {
 		kvfree(vol->upcase);
 		vol->upcase = default_upcase;
-		vol->upcase_len = max;
 		ntfs_nr_upcase_users++;
 		mutex_unlock(&ntfs_lock);
 		ntfs_debug("Volume specified $UpCase matches default. Using default.");
-- 
2.43.0


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 2/3] ntfs: avoid heap allocation for free-cluster readahead state
  2026-05-21 10:17   ` [PATCH v2 2/3] ntfs: avoid heap allocation for free-cluster readahead state DaeMyung Kang
@ 2026-05-21 12:19     ` Namjae Jeon
  2026-05-21 12:48       ` CharSyam
  2026-05-22  0:00     ` Hyunchul Lee
  1 sibling, 1 reply; 23+ messages in thread
From: Namjae Jeon @ 2026-05-21 12:19 UTC (permalink / raw)
  To: DaeMyung Kang; +Cc: Hyunchul Lee, linux-fsdevel, linux-kernel

>         /*
>          * Convert the number of bits into bytes rounded up, then convert into
> @@ -1985,7 +1981,7 @@ s64 get_nr_free_clusters(struct ntfs_volume *vol)
>                  * Get folio from page cache, getting it from backing store
>                  * if necessary, and increment the use count.
>                  */
> -               folio = ntfs_get_locked_folio(mapping, index, max_index, ra);
> +               folio = ntfs_get_locked_folio(mapping, index, max_index, &ra);
This patch causes a build error when applied. Does it build
successfully for you?

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 2/3] ntfs: avoid heap allocation for free-cluster readahead state
  2026-05-21 12:19     ` Namjae Jeon
@ 2026-05-21 12:48       ` CharSyam
  0 siblings, 0 replies; 23+ messages in thread
From: CharSyam @ 2026-05-21 12:48 UTC (permalink / raw)
  To: Namjae Jeon; +Cc: Hyunchul Lee, linux-fsdevel, linux-kernel

Hi Namjae,

Thanks for testing it.

It built successfully on my local setup with gcc 13.3.0
(gcc (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0).  I tested it on top of
mainline commit 8bc67e4db64a with CONFIG_NTFS_FS=m using:

make O=/tmp/linux-ntfs-mainline-v2-build fs/ntfs/super.o
make O=/tmp/linux-ntfs-mainline-v2-build fs/ntfs/ntfs.ko

However, I found a portability issue in patch 2.  I used:

struct file_ra_state ra = {};

which gcc accepted here, but this can be rejected by stricter builds as
an empty initializer.  I changed it to:

struct file_ra_state ra = { 0 };

and re-tested patch 2 alone and patches 1-2 on a clean mainline tree;
both build fs/ntfs/super.o successfully.  The full series also builds
fs/ntfs/ntfs.ko.

I will send v3 with this fix.  If your build error is different from the
empty-initializer issue, could you please share the exact error log?

Thanks,
DaeMyung

2026년 5월 21일 (목) 오후 9:19, Namjae Jeon <linkinjeon@kernel.org>님이 작성:
>
> >         /*
> >          * Convert the number of bits into bytes rounded up, then convert into
> > @@ -1985,7 +1981,7 @@ s64 get_nr_free_clusters(struct ntfs_volume *vol)
> >                  * Get folio from page cache, getting it from backing store
> >                  * if necessary, and increment the use count.
> >                  */
> > -               folio = ntfs_get_locked_folio(mapping, index, max_index, ra);
> > +               folio = ntfs_get_locked_folio(mapping, index, max_index, &ra);
> This patch causes a build error when applied. Does it build
> successfully for you?

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH v3 0/3] ntfs: fix mount failure cleanup and free-count setup
  2026-05-20 17:01 [PATCH 0/3] ntfs: fix mount failure cleanup and free-count setup DaeMyung Kang
                   ` (4 preceding siblings ...)
  2026-05-21 10:17 ` [PATCH v2 " DaeMyung Kang
@ 2026-05-21 13:00 ` DaeMyung Kang
  2026-05-21 13:00   ` [PATCH v3 1/3] ntfs: free volume-wide resources on fill_super failure DaeMyung Kang
                     ` (3 more replies)
  5 siblings, 4 replies; 23+ messages in thread
From: DaeMyung Kang @ 2026-05-21 13:00 UTC (permalink / raw)
  To: Namjae Jeon, Hyunchul Lee; +Cc: linux-fsdevel, linux-kernel, DaeMyung Kang

Hi Namjae,

This v3 is based on current mainline at 8bc67e4db64a.  The patches
modify fs/ntfs/super.c in the Linux kernel tree.

The fixes cover mount failure cleanup, a free-cluster precalc allocation
failure path that can otherwise leave waiters blocked forever, and the
$UpCase default-table alias check.  Per review, the free-cluster patch
now avoids the temporary file_ra_state heap allocation entirely by using
a stack variable for the synchronous bitmap scan.

Testing:
- Built fs/ntfs/super.o and fs/ntfs/ntfs.ko with gcc 13.3.0.
- For patch 1, I built a DEBUG_KMEMLEAK/DEBUG_FS kernel and injected an
  ntfs_fill_super() failure immediately after load_system_files().  Before
  the fix, kmemleak reported the leaked volume label allocated from
  ntfs_ucstonls(); after the fix, the same failure path produced no
  kmemleak report.
- For patch 2, I used QEMU with a debug injection that forces the initial
  precalc readahead-state allocation to fail.  Before the fix, statfs
  remained blocked in D state in ntfs_statfs().  This version removes
  that heap allocation and therefore removes the injected failure point.
  I also mounted a fresh NTFS image with the stack-backed state and
  verified statfs reported the same free count as ntfsinfo -m.

Changes since v2:
- Changed patch 2's on-stack file_ra_state initializer from the empty
  initializer to { 0 } to avoid build failures with stricter compilers.
- Re-tested patch 2 alone and patches 1-2 on a clean mainline tree.

Changes since v1:
- Rebased and regenerated the series for the Linux kernel tree
  (fs/ntfs/super.c), instead of the Github out-of-tree layout.
- Changed patch 2 to declare the temporary file_ra_state on the stack,
  as suggested by Hyunchul Lee, instead of adding an OOM fallback path.
- Zero-initialized patch 2's on-stack file_ra_state because
  file_ra_state_init() only initializes ra_pages and prev_pos.
- Reworded patch 3 to avoid overstating user-visible name comparison
  effects, and used memcmp() for the exact $UpCase table comparison.

DaeMyung Kang (3):
  ntfs: free volume-wide resources on fill_super failure
  ntfs: avoid heap allocation for free-cluster readahead state
  ntfs: only alias volume $UpCase to default on exact match

 fs/ntfs/super.c | 28 +++++++++-------------------
 1 file changed, 9 insertions(+), 19 deletions(-)


base-commit: 8bc67e4db64aa72732c474b44ea8622062c903f0
-- 
2.43.0

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH v3 1/3] ntfs: free volume-wide resources on fill_super failure
  2026-05-21 13:00 ` [PATCH v3 0/3] ntfs: fix mount failure cleanup and free-count setup DaeMyung Kang
@ 2026-05-21 13:00   ` DaeMyung Kang
  2026-05-21 13:00   ` [PATCH v3 2/3] ntfs: avoid heap allocation for free-cluster readahead state DaeMyung Kang
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 23+ messages in thread
From: DaeMyung Kang @ 2026-05-21 13:00 UTC (permalink / raw)
  To: Namjae Jeon, Hyunchul Lee; +Cc: linux-fsdevel, linux-kernel, DaeMyung Kang

ntfs_fill_super()'s err_out_now path frees only the volume struct via
kfree(vol), leaving several vol-owned allocations behind on every mount
failure:

  - vol->nls_map, loaded by ntfs_init_fs_context() via
    load_nls_default() (or replaced by an explicit nls= option in
    ntfs_parse_param()), is never unload_nls()'d.

  - vol->volume_label, allocated by load_system_files() through
    ntfs_ucstonls() once the $Volume name attribute has been parsed, is
    not released by load_system_files()'s own error labels nor by the
    fill_super() inline cleanup that only runs on d_make_root()
    failure.  Any later failure inside load_system_files() leaks it.

  - vol->lcn_empty_bits_per_page was kvfree()'d in
    unl_upcase_iput_tmp_ino_err_out_now without clearing the pointer,
    so it could not be folded into a single common cleanup.

Because the failure paths never call ntfs_volume_free() and never reach
the d_make_root() inline cleanup block (it sits above the label and is
jumped over by the load_system_files() / kvmalloc failure gotos), these
resources accumulate per failed mount attempt with no chance of
recovery short of unloading the module.  This is a silent leak: the
inodes loaded prior to failure remain hashed but generic_shutdown_super()
skips evict_inodes() when sb->s_root is unset, so no CHECK_DATA_CORRUPTION
warning is emitted either.

Move the per-volume frees down to err_out_now and drop the
lcn_empty_bits_per_page kvfree() from the upper label so the cleanup is
performed exactly once on every failure path.  Using unconditional
kvfree() / kfree() / unload_nls() is safe because they all accept NULL
and the upper labels that previously freed nls_map (the d_make_root()
inline cleanup) already clear the pointer.

Signed-off-by: DaeMyung Kang <charsyam@gmail.com>
---
 fs/ntfs/super.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c
index 9e321cc2febe..7e3561265b47 100644
--- a/fs/ntfs/super.c
+++ b/fs/ntfs/super.c
@@ -2530,8 +2530,6 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
 	}
 	/* Error exit code path. */
 unl_upcase_iput_tmp_ino_err_out_now:
-	if (vol->lcn_empty_bits_per_page)
-		kvfree(vol->lcn_empty_bits_per_page);
 	/*
 	 * Decrease the number of upcase users and destroy the global default
 	 * upcase table if necessary.
@@ -2551,6 +2549,9 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
 	/* Errors at this stage are irrelevant. */
 err_out_now:
 	sb->s_fs_info = NULL;
+	kvfree(vol->lcn_empty_bits_per_page);
+	kfree(vol->volume_label);
+	unload_nls(vol->nls_map);
 	kfree(vol);
 	ntfs_debug("Failed, returning -EINVAL.");
 	lockdep_on();
-- 
2.43.0


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH v3 2/3] ntfs: avoid heap allocation for free-cluster readahead state
  2026-05-21 13:00 ` [PATCH v3 0/3] ntfs: fix mount failure cleanup and free-count setup DaeMyung Kang
  2026-05-21 13:00   ` [PATCH v3 1/3] ntfs: free volume-wide resources on fill_super failure DaeMyung Kang
@ 2026-05-21 13:00   ` DaeMyung Kang
  2026-05-21 13:00   ` [PATCH v3 3/3] ntfs: only alias volume $UpCase to default on exact match DaeMyung Kang
  2026-05-23 14:11   ` [PATCH v3 0/3] ntfs: fix mount failure cleanup and free-count setup Namjae Jeon
  3 siblings, 0 replies; 23+ messages in thread
From: DaeMyung Kang @ 2026-05-21 13:00 UTC (permalink / raw)
  To: Namjae Jeon, Hyunchul Lee; +Cc: linux-fsdevel, linux-kernel, DaeMyung Kang

get_nr_free_clusters() is run from the precalc_free_clusters() worker
queued at the end of ntfs_fill_super().  It is also the only place that
publishes the result by atomic64_set(&vol->free_clusters, ...), sets
NVolSetFreeClusterKnown(), and wakes vol->free_waitq.

The function currently allocates a temporary file_ra_state with
kzalloc() before that publication happens.  If the allocation fails,
get_nr_free_clusters() returns 0 without setting NVolFreeClusterKnown()
or waking vol->free_waitq, so callers that wait for the free count can
block forever.

The readahead state is only used synchronously while scanning the bitmap
and struct file_ra_state is small.  Keep it on the stack and pass it to
the readahead helper by address, eliminating the early allocation
failure path.  Zero-initialize the on-stack state because
file_ra_state_init() only sets ra_pages and prev_pos.

Signed-off-by: DaeMyung Kang <charsyam@gmail.com>
---
 fs/ntfs/super.c | 11 +++--------
 1 file changed, 3 insertions(+), 8 deletions(-)

diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c
index 7e3561265b47..d2c4fb6ea0d4 100644
--- a/fs/ntfs/super.c
+++ b/fs/ntfs/super.c
@@ -1954,7 +1954,7 @@ s64 get_nr_free_clusters(struct ntfs_volume *vol)
 	struct address_space *mapping = vol->lcnbmp_ino->i_mapping;
 	struct folio *folio;
 	pgoff_t index, max_index;
-	struct file_ra_state *ra;
+	struct file_ra_state ra = { 0 };
 
 	ntfs_debug("Entering.");
 	/* Serialize accesses to the cluster bitmap. */
@@ -1962,11 +1962,7 @@ s64 get_nr_free_clusters(struct ntfs_volume *vol)
 	if (NVolFreeClusterKnown(vol))
 		return atomic64_read(&vol->free_clusters);
 
-	ra = kzalloc(sizeof(*ra), GFP_NOFS);
-	if (!ra)
-		return 0;
-
-	file_ra_state_init(ra, mapping);
+	file_ra_state_init(&ra, mapping);
 
 	/*
 	 * Convert the number of bits into bytes rounded up, then convert into
@@ -1985,7 +1981,7 @@ s64 get_nr_free_clusters(struct ntfs_volume *vol)
 		 * Get folio from page cache, getting it from backing store
 		 * if necessary, and increment the use count.
 		 */
-		folio = ntfs_get_locked_folio(mapping, index, max_index, ra);
+		folio = ntfs_get_locked_folio(mapping, index, max_index, &ra);
 
 		/* Ignore pages which errored synchronously. */
 		if (IS_ERR(folio)) {
@@ -2024,7 +2020,6 @@ s64 get_nr_free_clusters(struct ntfs_volume *vol)
 	else
 		atomic64_set(&vol->free_clusters, nr_free);
 
-	kfree(ra);
 	NVolSetFreeClusterKnown(vol);
 	wake_up_all(&vol->free_waitq);
 	ntfs_debug("Exiting.");
-- 
2.43.0


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH v3 3/3] ntfs: only alias volume $UpCase to default on exact match
  2026-05-21 13:00 ` [PATCH v3 0/3] ntfs: fix mount failure cleanup and free-count setup DaeMyung Kang
  2026-05-21 13:00   ` [PATCH v3 1/3] ntfs: free volume-wide resources on fill_super failure DaeMyung Kang
  2026-05-21 13:00   ` [PATCH v3 2/3] ntfs: avoid heap allocation for free-cluster readahead state DaeMyung Kang
@ 2026-05-21 13:00   ` DaeMyung Kang
  2026-05-23 14:11   ` [PATCH v3 0/3] ntfs: fix mount failure cleanup and free-count setup Namjae Jeon
  3 siblings, 0 replies; 23+ messages in thread
From: DaeMyung Kang @ 2026-05-21 13:00 UTC (permalink / raw)
  To: Namjae Jeon, Hyunchul Lee; +Cc: linux-fsdevel, linux-kernel, DaeMyung Kang

load_and_init_upcase() currently aliases vol->upcase to the global
default upcase whenever the shared prefix matches, and then truncates
vol->upcase_len to that shorter prefix.  The result is correct only by
accident: upcase[] accesses in name collation are gated by upcase_len,
so the prefix-equality alias produces the same fold output as keeping
the volume's own shorter table.

Still, prefix equality is not equality: the volume table is logically
distinct from the default and should not be replaced by it unless they
are byte-for-byte identical.  Use memcmp() to compare the complete table
in one expression and drop the now-redundant upcase_len rewrite.

No user-visible change is expected for compliant volumes whose $UpCase
has exactly default_upcase_len entries; shorter volume tables are no
longer aliased to the default.

Signed-off-by: DaeMyung Kang <charsyam@gmail.com>
---
 fs/ntfs/super.c | 12 +++---------
 1 file changed, 3 insertions(+), 9 deletions(-)

diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c
index d2c4fb6ea0d4..876e978370ba 100644
--- a/fs/ntfs/super.c
+++ b/fs/ntfs/super.c
@@ -1323,7 +1323,6 @@ static bool load_and_init_upcase(struct ntfs_volume *vol)
 	u8 *addr;
 	pgoff_t index, max_index;
 	unsigned int size;
-	int i, max;
 
 	ntfs_debug("Entering.");
 	/* Read upcase table and setup vol->upcase and vol->upcase_len. */
@@ -1374,16 +1373,11 @@ static bool load_and_init_upcase(struct ntfs_volume *vol)
 		mutex_unlock(&ntfs_lock);
 		return true;
 	}
-	max = default_upcase_len;
-	if (max > vol->upcase_len)
-		max = vol->upcase_len;
-	for (i = 0; i < max; i++)
-		if (vol->upcase[i] != default_upcase[i])
-			break;
-	if (i == max) {
+	if (default_upcase_len == vol->upcase_len &&
+	    !memcmp(vol->upcase, default_upcase,
+		    default_upcase_len * sizeof(*default_upcase))) {
 		kvfree(vol->upcase);
 		vol->upcase = default_upcase;
-		vol->upcase_len = max;
 		ntfs_nr_upcase_users++;
 		mutex_unlock(&ntfs_lock);
 		ntfs_debug("Volume specified $UpCase matches default. Using default.");
-- 
2.43.0


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 2/3] ntfs: avoid heap allocation for free-cluster readahead state
  2026-05-21 10:17   ` [PATCH v2 2/3] ntfs: avoid heap allocation for free-cluster readahead state DaeMyung Kang
  2026-05-21 12:19     ` Namjae Jeon
@ 2026-05-22  0:00     ` Hyunchul Lee
  2026-05-22  0:28       ` Namjae Jeon
  1 sibling, 1 reply; 23+ messages in thread
From: Hyunchul Lee @ 2026-05-22  0:00 UTC (permalink / raw)
  To: DaeMyung Kang; +Cc: Namjae Jeon, linux-fsdevel, linux-kernel

2026년 5월 21일 (목) 오후 7:18, DaeMyung Kang <charsyam@gmail.com>님이 작성:
>
> get_nr_free_clusters() is run from the precalc_free_clusters() worker
> queued at the end of ntfs_fill_super().  It is also the only place that
> publishes the result by atomic64_set(&vol->free_clusters, ...), sets
> NVolSetFreeClusterKnown(), and wakes vol->free_waitq.
>
> The function currently allocates a temporary file_ra_state with
> kzalloc() before that publication happens.  If the allocation fails,
> get_nr_free_clusters() returns 0 without setting NVolFreeClusterKnown()
> or waking vol->free_waitq, so callers that wait for the free count can
> block forever.
>
> The readahead state is only used synchronously while scanning the bitmap
> and struct file_ra_state is small.  Keep it on the stack and pass it to
> the readahead helper by address, eliminating the early allocation
> failure path.  Zero-initialize the on-stack state because
> file_ra_state_init() only sets ra_pages and prev_pos.
>
> Signed-off-by: DaeMyung Kang <charsyam@gmail.com>
> ---
>  fs/ntfs/super.c | 11 +++--------
>  1 file changed, 3 insertions(+), 8 deletions(-)
>
> diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c
> index 7e3561265b47..14fd244f29fe 100644
> --- a/fs/ntfs/super.c
> +++ b/fs/ntfs/super.c
> @@ -1954,7 +1954,7 @@ s64 get_nr_free_clusters(struct ntfs_volume *vol)
>         struct address_space *mapping = vol->lcnbmp_ino->i_mapping;
>         struct folio *folio;
>         pgoff_t index, max_index;
> -       struct file_ra_state *ra;
> +       struct file_ra_state ra = {};
>
>         ntfs_debug("Entering.");
>         /* Serialize accesses to the cluster bitmap. */
> @@ -1962,11 +1962,7 @@ s64 get_nr_free_clusters(struct ntfs_volume *vol)
>         if (NVolFreeClusterKnown(vol))
>                 return atomic64_read(&vol->free_clusters);
>
> -       ra = kzalloc(sizeof(*ra), GFP_NOFS);
> -       if (!ra)
> -               return 0;
> -
> -       file_ra_state_init(ra, mapping);
> +       file_ra_state_init(&ra, mapping);
>
>         /*
>          * Convert the number of bits into bytes rounded up, then convert into
> @@ -1985,7 +1981,7 @@ s64 get_nr_free_clusters(struct ntfs_volume *vol)
>                  * Get folio from page cache, getting it from backing store
>                  * if necessary, and increment the use count.
>                  */
> -               folio = ntfs_get_locked_folio(mapping, index, max_index, ra);
> +               folio = ntfs_get_locked_folio(mapping, index, max_index, &ra);

This line modifies the __get_nr_free_mft_records function, not the
get_nr_free_clusters function.
Therefore the patch needs to be rebased on ntfs-next branch at
git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/ntfs.git.

>
>                 /* Ignore pages which errored synchronously. */
>                 if (IS_ERR(folio)) {
> @@ -2024,7 +2020,6 @@ s64 get_nr_free_clusters(struct ntfs_volume *vol)
>         else
>                 atomic64_set(&vol->free_clusters, nr_free);
>
> -       kfree(ra);
>         NVolSetFreeClusterKnown(vol);
>         wake_up_all(&vol->free_waitq);
>         ntfs_debug("Exiting.");
> --
> 2.43.0
>


-- 
Thanks,
Hyunchul

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 2/3] ntfs: avoid heap allocation for free-cluster readahead state
  2026-05-22  0:00     ` Hyunchul Lee
@ 2026-05-22  0:28       ` Namjae Jeon
  2026-05-22  1:22         ` CharSyam
  0 siblings, 1 reply; 23+ messages in thread
From: Namjae Jeon @ 2026-05-22  0:28 UTC (permalink / raw)
  To: Hyunchul Lee; +Cc: DaeMyung Kang, linux-fsdevel, linux-kernel

> >          * Convert the number of bits into bytes rounded up, then convert into
> > @@ -1985,7 +1981,7 @@ s64 get_nr_free_clusters(struct ntfs_volume *vol)
> >                  * Get folio from page cache, getting it from backing store
> >                  * if necessary, and increment the use count.
> >                  */
> > -               folio = ntfs_get_locked_folio(mapping, index, max_index, ra);
> > +               folio = ntfs_get_locked_folio(mapping, index, max_index, &ra);
>
> This line modifies the __get_nr_free_mft_records function, not the
> get_nr_free_clusters function.
> Therefore the patch needs to be rebased on ntfs-next branch at
> git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/ntfs.git.
We can change__get_nr_free_mft_records() in the same way as
get_nr_free_clusters().

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 2/3] ntfs: avoid heap allocation for free-cluster readahead state
  2026-05-22  0:28       ` Namjae Jeon
@ 2026-05-22  1:22         ` CharSyam
  2026-05-22  4:31           ` Namjae Jeon
  0 siblings, 1 reply; 23+ messages in thread
From: CharSyam @ 2026-05-22  1:22 UTC (permalink / raw)
  To: Namjae Jeon; +Cc: Hyunchul Lee, linux-fsdevel, linux-kernel

Thanks for the clarification.
I will rebase it onto ntfs-next and resend.

2026년 5월 22일 (금) 오전 9:28, Namjae Jeon <linkinjeon@kernel.org>님이 작성:
>
> > >          * Convert the number of bits into bytes rounded up, then convert into
> > > @@ -1985,7 +1981,7 @@ s64 get_nr_free_clusters(struct ntfs_volume *vol)
> > >                  * Get folio from page cache, getting it from backing store
> > >                  * if necessary, and increment the use count.
> > >                  */
> > > -               folio = ntfs_get_locked_folio(mapping, index, max_index, ra);
> > > +               folio = ntfs_get_locked_folio(mapping, index, max_index, &ra);
> >
> > This line modifies the __get_nr_free_mft_records function, not the
> > get_nr_free_clusters function.
> > Therefore the patch needs to be rebased on ntfs-next branch at
> > git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/ntfs.git.
> We can change__get_nr_free_mft_records() in the same way as
> get_nr_free_clusters().

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 2/3] ntfs: avoid heap allocation for free-cluster readahead state
  2026-05-22  1:22         ` CharSyam
@ 2026-05-22  4:31           ` Namjae Jeon
  0 siblings, 0 replies; 23+ messages in thread
From: Namjae Jeon @ 2026-05-22  4:31 UTC (permalink / raw)
  To: CharSyam; +Cc: Hyunchul Lee, linux-fsdevel, linux-kernel

On Fri, May 22, 2026 at 10:22 AM CharSyam <charsyam@gmail.com> wrote:
>
> Thanks for the clarification.
> I will rebase it onto ntfs-next and resend.
You can just resend this patch, not the entire series.
Thanks.

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 0/3] ntfs: fix mount failure cleanup and free-count setup
  2026-05-21 13:00 ` [PATCH v3 0/3] ntfs: fix mount failure cleanup and free-count setup DaeMyung Kang
                     ` (2 preceding siblings ...)
  2026-05-21 13:00   ` [PATCH v3 3/3] ntfs: only alias volume $UpCase to default on exact match DaeMyung Kang
@ 2026-05-23 14:11   ` Namjae Jeon
  3 siblings, 0 replies; 23+ messages in thread
From: Namjae Jeon @ 2026-05-23 14:11 UTC (permalink / raw)
  To: DaeMyung Kang; +Cc: Hyunchul Lee, linux-fsdevel, linux-kernel

On Thu, May 21, 2026 at 10:00 PM DaeMyung Kang <charsyam@gmail.com> wrote:
>
> Hi Namjae,
>
> This v3 is based on current mainline at 8bc67e4db64a.  The patches
> modify fs/ntfs/super.c in the Linux kernel tree.
>
> The fixes cover mount failure cleanup, a free-cluster precalc allocation
> failure path that can otherwise leave waiters blocked forever, and the
> $UpCase default-table alias check.  Per review, the free-cluster patch
> now avoids the temporary file_ra_state heap allocation entirely by using
> a stack variable for the synchronous bitmap scan.
>
> Testing:
> - Built fs/ntfs/super.o and fs/ntfs/ntfs.ko with gcc 13.3.0.
> - For patch 1, I built a DEBUG_KMEMLEAK/DEBUG_FS kernel and injected an
>   ntfs_fill_super() failure immediately after load_system_files().  Before
>   the fix, kmemleak reported the leaked volume label allocated from
>   ntfs_ucstonls(); after the fix, the same failure path produced no
>   kmemleak report.
> - For patch 2, I used QEMU with a debug injection that forces the initial
>   precalc readahead-state allocation to fail.  Before the fix, statfs
>   remained blocked in D state in ntfs_statfs().  This version removes
>   that heap allocation and therefore removes the injected failure point.
>   I also mounted a fresh NTFS image with the stack-backed state and
>   verified statfs reported the same free count as ntfsinfo -m.
>
> Changes since v2:
> - Changed patch 2's on-stack file_ra_state initializer from the empty
>   initializer to { 0 } to avoid build failures with stricter compilers.
> - Re-tested patch 2 alone and patches 1-2 on a clean mainline tree.
>
> Changes since v1:
> - Rebased and regenerated the series for the Linux kernel tree
>   (fs/ntfs/super.c), instead of the Github out-of-tree layout.
> - Changed patch 2 to declare the temporary file_ra_state on the stack,
>   as suggested by Hyunchul Lee, instead of adding an OOM fallback path.
> - Zero-initialized patch 2's on-stack file_ra_state because
>   file_ra_state_init() only initializes ra_pages and prev_pos.
> - Reworded patch 3 to avoid overstating user-visible name comparison
>   effects, and used memcmp() for the exact $UpCase table comparison.
>
> DaeMyung Kang (3):
>   ntfs: free volume-wide resources on fill_super failure
>   ntfs: avoid heap allocation for free-cluster readahead state
>   ntfs: only alias volume $UpCase to default on exact match
Applied them to #ntfs-next.
Thanks!

^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2026-05-23 14:11 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-05-20 17:01 [PATCH 0/3] ntfs: fix mount failure cleanup and free-count setup DaeMyung Kang
2026-05-20 17:01 ` [PATCH 1/3] ntfs: free volume-wide resources on fill_super failure DaeMyung Kang
2026-05-21  1:03   ` Hyunchul Lee
2026-05-20 17:01 ` [PATCH 2/3] ntfs: wake free-cluster waiters when precalc allocation fails DaeMyung Kang
2026-05-21  1:03   ` Hyunchul Lee
2026-05-20 17:01 ` [PATCH 3/3] ntfs: only alias volume $UpCase to default on exact match DaeMyung Kang
2026-05-21  1:04   ` Hyunchul Lee
2026-05-21  1:02 ` [PATCH 0/3] ntfs: fix mount failure cleanup and free-count setup Hyunchul Lee
2026-05-21 10:17 ` [PATCH v2 " DaeMyung Kang
2026-05-21 10:17   ` [PATCH v2 1/3] ntfs: free volume-wide resources on fill_super failure DaeMyung Kang
2026-05-21 10:17   ` [PATCH v2 2/3] ntfs: avoid heap allocation for free-cluster readahead state DaeMyung Kang
2026-05-21 12:19     ` Namjae Jeon
2026-05-21 12:48       ` CharSyam
2026-05-22  0:00     ` Hyunchul Lee
2026-05-22  0:28       ` Namjae Jeon
2026-05-22  1:22         ` CharSyam
2026-05-22  4:31           ` Namjae Jeon
2026-05-21 10:17   ` [PATCH v2 3/3] ntfs: only alias volume $UpCase to default on exact match DaeMyung Kang
2026-05-21 13:00 ` [PATCH v3 0/3] ntfs: fix mount failure cleanup and free-count setup DaeMyung Kang
2026-05-21 13:00   ` [PATCH v3 1/3] ntfs: free volume-wide resources on fill_super failure DaeMyung Kang
2026-05-21 13:00   ` [PATCH v3 2/3] ntfs: avoid heap allocation for free-cluster readahead state DaeMyung Kang
2026-05-21 13:00   ` [PATCH v3 3/3] ntfs: only alias volume $UpCase to default on exact match DaeMyung Kang
2026-05-23 14:11   ` [PATCH v3 0/3] ntfs: fix mount failure cleanup and free-count setup Namjae Jeon

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

Powered by JetHome