]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ntfs: avoid heap allocation for free-cluster readahead state
authorDaeMyung Kang <charsyam@gmail.com>
Fri, 22 May 2026 14:20:48 +0000 (23:20 +0900)
committerNamjae Jeon <linkinjeon@kernel.org>
Fri, 5 Jun 2026 15:19:49 +0000 (00:19 +0900)
get_nr_free_clusters() allocates a temporary file_ra_state before it
publishes the precomputed free cluster count, sets NVolFreeClusterKnown(),
and wakes vol->free_waitq. If that allocation fails, the worker returns
without setting the flag or waking waiters, so callers waiting for the free
count can block indefinitely.

The readahead state is only used synchronously while scanning the bitmap.
Keep it on the stack and pass it by address to the readahead helper. This
eliminates the early allocation failure path instead of adding a special
case that publishes a conservative count and wakes the waitqueue.
Zero-initialize the on-stack state because file_ra_state_init() only sets
ra_pages and prev_pos.

Apply the same treatment to __get_nr_free_mft_records(), which scans the
MFT bitmap with the same short-lived readahead state.

Cc: stable@vger.kernel.org # v7.1
Signed-off-by: DaeMyung Kang <charsyam@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
fs/ntfs/super.c

index e51573be2182b1ff2eb81f2d0cef94fd80746591..e30fcce628c29bbcaac1336fc1e3db6463352031 100644 (file)
@@ -1948,7 +1948,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. */
@@ -1956,11 +1956,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
@@ -1979,7 +1975,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)) {
@@ -2018,7 +2014,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.");
@@ -2073,15 +2068,11 @@ static unsigned long __get_nr_free_mft_records(struct ntfs_volume *vol,
        struct address_space *mapping = vol->mftbmp_ino->i_mapping;
        struct folio *folio;
        pgoff_t index;
-       struct file_ra_state *ra;
+       struct file_ra_state ra = { 0 };
 
        ntfs_debug("Entering.");
 
-       ra = kzalloc(sizeof(*ra), GFP_NOFS);
-       if (!ra)
-               return 0;
-
-       file_ra_state_init(ra, mapping);
+       file_ra_state_init(&ra, mapping);
 
        /* Use multiples of 4 bytes, thus max_size is PAGE_SIZE / 4. */
        ntfs_debug("Reading $MFT/$BITMAP, max_index = 0x%lx, max_size = 0x%lx.",
@@ -2093,7 +2084,7 @@ static unsigned long __get_nr_free_mft_records(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)) {
@@ -2125,7 +2116,6 @@ static unsigned long __get_nr_free_mft_records(struct ntfs_volume *vol,
        else
                atomic64_set(&vol->free_mft_records, nr_free);
 
-       kfree(ra);
        ntfs_debug("Exiting.");
        return nr_free;
 }