From 8b4064e6146efc6c0202d671c4e26bcbd26e3555 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Wed, 1 Apr 2026 16:24:57 +0900 Subject: [PATCH 01/13] ntfs: zero out stale data in straddle block beyond initialized_size ntfs_read_iomap_begin_non_resident() rounds up MAPPED extents to the block boundary of initialized_size. This ensures that any subsequent blocks are treated as IOMAP_UNWRITTEN, but it also causes the "straddle block" containing initialized_size to be read from disk. The disk data beyond initialized_size in this block is stale and must be zeroed to prevent data leakage. Signed-off-by: Hyunchul Lee Signed-off-by: Namjae Jeon --- fs/ntfs/aops.c | 47 +++++++++++++++++++++++++++++++++++++++++++++-- fs/ntfs/file.c | 9 --------- 2 files changed, 45 insertions(+), 11 deletions(-) diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c index 78d1ce41958e..b59f3cc313ed 100644 --- a/fs/ntfs/aops.c +++ b/fs/ntfs/aops.c @@ -15,6 +15,41 @@ #include "debug.h" #include "iomap.h" +static void ntfs_iomap_read_end_io(struct bio *bio) +{ + int error = blk_status_to_errno(bio->bi_status); + struct folio_iter iter; + + bio_for_each_folio_all(iter, bio) { + struct folio *folio = iter.folio; + struct ntfs_inode *ni = NTFS_I(folio->mapping->host); + s64 init_size; + loff_t pos = folio_pos(folio); + + init_size = ni->initialized_size; + if (pos + iter.offset < init_size && + pos + iter.offset + iter.length > init_size) + folio_zero_segment(folio, offset_in_folio(folio, init_size), + iter.offset + iter.length); + + iomap_finish_folio_read(folio, iter.offset, iter.length, error); + } + bio_put(bio); +} + +static void ntfs_iomap_bio_submit_read(const struct iomap_iter *iter, + struct iomap_read_folio_ctx *ctx) +{ + struct bio *bio = ctx->read_ctx; + bio->bi_end_io = ntfs_iomap_read_end_io; + submit_bio(bio); +} + +static const struct iomap_read_ops ntfs_iomap_bio_read_ops = { + .read_folio_range = iomap_bio_read_folio_range, + .submit_read = ntfs_iomap_bio_submit_read, +}; + /* * ntfs_read_folio - Read data for a folio from the device * @file: open file to which the folio @folio belongs or NULL @@ -35,6 +70,10 @@ static int ntfs_read_folio(struct file *file, struct folio *folio) { struct ntfs_inode *ni = NTFS_I(folio->mapping->host); + struct iomap_read_folio_ctx ctx = { + .cur_folio = folio, + .ops = &ntfs_iomap_bio_read_ops, + }; /* * Only $DATA attributes can be encrypted and only unnamed $DATA @@ -58,7 +97,7 @@ static int ntfs_read_folio(struct file *file, struct folio *folio) return ntfs_read_compressed_block(folio); } - iomap_bio_read_folio(folio, &ntfs_read_iomap_ops); + iomap_read_folio(&ntfs_read_iomap_ops, &ctx, NULL); return 0; } @@ -188,6 +227,10 @@ static void ntfs_readahead(struct readahead_control *rac) struct address_space *mapping = rac->mapping; struct inode *inode = mapping->host; struct ntfs_inode *ni = NTFS_I(inode); + struct iomap_read_folio_ctx ctx = { + .ops = &ntfs_iomap_bio_read_ops, + .rac = rac, + }; /* * Resident files are not cached in the page cache, @@ -195,7 +238,7 @@ static void ntfs_readahead(struct readahead_control *rac) */ if (!NInoNonResident(ni) || NInoCompressed(ni)) return; - iomap_bio_readahead(rac, &ntfs_read_iomap_ops); + iomap_readahead(&ntfs_read_iomap_ops, &ctx, NULL); } static int ntfs_writepages(struct address_space *mapping, diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index e5b897a6c1e1..e1a9ba544644 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c @@ -267,15 +267,6 @@ static int ntfs_setattr_size(struct inode *vi, struct iattr *attr) return err; inode_dio_wait(vi); - /* Serialize against page faults */ - if (NInoNonResident(NTFS_I(vi)) && attr->ia_size < old_size) { - err = iomap_truncate_page(vi, attr->ia_size, NULL, - &ntfs_read_iomap_ops, - &ntfs_iomap_folio_ops, NULL); - if (err) - return err; - } - truncate_setsize(vi, attr->ia_size); err = ntfs_truncate_vfs(vi, attr->ia_size, old_size); if (err) { From ca513e492fb8ac59f5e3092a79d836cd2e687a2a Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Fri, 3 Apr 2026 08:54:11 +0900 Subject: [PATCH 02/13] ntfs: not zero out range beyond init in punch_hole The area beyond initialized_size are read as zero values, there is no need to zero out that region. Signed-off-by: Hyunchul Lee Signed-off-by: Namjae Jeon --- fs/ntfs/file.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index e1a9ba544644..34003fa07dd1 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c @@ -876,14 +876,19 @@ static int ntfs_punch_hole(struct ntfs_inode *ni, int mode, loff_t offset, end_vcn = ntfs_bytes_to_cluster(vol, end_offset - 1) + 1; if (offset & vol->cluster_size_mask) { - loff_t to; + if (offset < ni->initialized_size) { + loff_t to; - to = min_t(loff_t, ntfs_cluster_to_bytes(vol, start_vcn + 1), - end_offset); - err = iomap_zero_range(vi, offset, to - offset, NULL, - &ntfs_seek_iomap_ops, - &ntfs_iomap_folio_ops, NULL); - if (err < 0 || (end_vcn - start_vcn) == 1) + to = min_t(loff_t, + ntfs_cluster_to_bytes(vol, start_vcn + 1), + end_offset); + err = iomap_zero_range(vi, offset, to - offset, + NULL, &ntfs_seek_iomap_ops, + &ntfs_iomap_folio_ops, NULL); + if (err < 0) + goto out; + } + if (end_vcn - start_vcn == 1) goto out; start_vcn++; } @@ -892,10 +897,14 @@ static int ntfs_punch_hole(struct ntfs_inode *ni, int mode, loff_t offset, loff_t from; from = ntfs_cluster_to_bytes(vol, end_vcn - 1); - err = iomap_zero_range(vi, from, end_offset - from, NULL, - &ntfs_seek_iomap_ops, - &ntfs_iomap_folio_ops, NULL); - if (err < 0 || (end_vcn - start_vcn) == 1) + if (from < ni->initialized_size) { + err = iomap_zero_range(vi, from, end_offset - from, + NULL, &ntfs_seek_iomap_ops, + &ntfs_iomap_folio_ops, NULL); + if (err < 0) + goto out; + } + if (end_vcn - start_vcn == 1) goto out; end_vcn--; } From 0b79de3299079e4132972ab5e04136c770e38038 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Fri, 3 Apr 2026 10:10:39 +0900 Subject: [PATCH 03/13] ntfs: limit memory allocation in ntfs_attr_readall check an attribute size before memory allocation, and reject if the size is over the maximum size. Signed-off-by: Hyunchul Lee Signed-off-by: Namjae Jeon --- fs/ntfs/attrib.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c index 78915c1d5128..e8cc74c9c9a7 100644 --- a/fs/ntfs/attrib.c +++ b/fs/ntfs/attrib.c @@ -29,6 +29,13 @@ __le16 AT_UNNAMED[] = { cpu_to_le16('\0') }; +/* + * Maximum size allowed for reading attributes by ntfs_attr_readall(). + * Extended attribute, reparse point are not expected to be larger than this size. + */ + +#define NTFS_ATTR_READALL_MAX_SIZE (64 * 1024) + /* * ntfs_map_runlist_nolock - map (a part of) a runlist of an ntfs inode * @ni: ntfs inode for which to map (part of) a runlist @@ -5117,6 +5124,13 @@ void *ntfs_attr_readall(struct ntfs_inode *ni, const __le32 type, } bmp_ni = NTFS_I(bmp_vi); + if (bmp_ni->data_size > NTFS_ATTR_READALL_MAX_SIZE && + (bmp_ni->type != AT_BITMAP || + bmp_ni->data_size > ((ni->vol->nr_clusters + 7) >> 3))) { + ntfs_error(sb, "Invalid attribute data size"); + goto out; + } + data = kvmalloc(bmp_ni->data_size, GFP_NOFS); if (!data) goto out; From cf29a21b3d9105c5309e679ba875df1e987cabfa Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Mon, 6 Apr 2026 10:24:16 +0900 Subject: [PATCH 04/13] ntfs: remove noop_direct_IO from address_space_operations Since commit a2ad63daa88b ("VFS: add FMODE_CAN_ODIRECT file flag"), noop_direct_io is not required. Signed-off-by: Hyunchul Lee Signed-off-by: Namjae Jeon --- fs/ntfs/aops.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c index b59f3cc313ed..1fbf832ad165 100644 --- a/fs/ntfs/aops.c +++ b/fs/ntfs/aops.c @@ -281,7 +281,6 @@ const struct address_space_operations ntfs_aops = { .read_folio = ntfs_read_folio, .readahead = ntfs_readahead, .writepages = ntfs_writepages, - .direct_IO = noop_direct_IO, .dirty_folio = iomap_dirty_folio, .bmap = ntfs_bmap, .migrate_folio = filemap_migrate_folio, From 8a59a2d84fa3de2b4bbb8759b52e62c9c06d9d32 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Fri, 10 Apr 2026 20:29:44 +0900 Subject: [PATCH 05/13] ntfs: fix uninitialized variable in ntfs_write_simple_iomap_begin_non_resident Smatch reported that err could be used uninitialized if the code path does not enter the first ntfs_zero_range() block. Reported-by: Dan Carpenter Reviewed-by: Hyunchul Lee Signed-off-by: Namjae Jeon --- fs/ntfs/iomap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ntfs/iomap.c b/fs/ntfs/iomap.c index 621645fbbf2e..3d1458dea90f 100644 --- a/fs/ntfs/iomap.c +++ b/fs/ntfs/iomap.c @@ -384,7 +384,7 @@ static int ntfs_write_simple_iomap_begin_non_resident(struct inode *inode, loff_ loff_t vcn_ofs, rl_length; struct runlist_element *rl, *rlc; bool is_retry = false; - int err; + int err = 0; s64 vcn, lcn; s64 max_clu_count = ntfs_bytes_to_cluster(vol, round_up(length, vol->cluster_size)); From 545834ac412fb42d41a41442aee7998c1d2dcced Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Fri, 10 Apr 2026 23:49:01 +0900 Subject: [PATCH 06/13] ntfs: fix uninitialized pointer in ntfs_write_mft_block Smatch reported that the variable rl could be used uninitialized in ntfs_write_mft_block(). After analyzing the code, when vol->cluster_size == NTFS_BLOCK_SIZE (512), it is smaller than folio_size, so rl is guaranteed to be initialized. If vol->cluster_size is larger, the condition to access rl becomes false, so a runtime error is not expected to occur. However, to make the static checker happy, this patch initializes rl to NULL and adds an explicit check before its usage. Reported-by: Dan Carpenter Reviewed-by: Hyunchul Lee Signed-off-by: Namjae Jeon --- fs/ntfs/mft.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/ntfs/mft.c b/fs/ntfs/mft.c index bf028c1aea26..60d64de51d21 100644 --- a/fs/ntfs/mft.c +++ b/fs/ntfs/mft.c @@ -2714,7 +2714,7 @@ static int ntfs_write_mft_block(struct folio *folio, struct writeback_control *w s64 vcn = ntfs_pidx_to_cluster(vol, folio->index); s64 end_vcn = ntfs_bytes_to_cluster(vol, ni->allocated_size); unsigned int folio_sz; - struct runlist_element *rl; + struct runlist_element *rl = NULL; loff_t i_size = i_size_read(vi); ntfs_debug("Entering for inode 0x%llx, attribute type 0x%x, folio index 0x%lx.", @@ -2820,7 +2820,7 @@ static int ntfs_write_mft_block(struct folio *folio, struct writeback_control *w if (vol->cluster_size == NTFS_BLOCK_SIZE && (mft_record_off || - rl->length - (vcn_off - rl->vcn) == 1 || + (rl && rl->length - (vcn_off - rl->vcn) == 1) || mft_ofs + NTFS_BLOCK_SIZE >= PAGE_SIZE)) folio_sz = NTFS_BLOCK_SIZE; else From cd8d29c1b3c3397493115a9e919a806ea28aef05 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sat, 11 Apr 2026 00:02:49 +0900 Subject: [PATCH 07/13] ntfs: fix uninitialized variables in ntfs_ea_set_wsl_inode() Smatch reported uninitialized symbol warnings in ntfs_ea_set_wsl_inode() and __ntfs_create(). In ntfs_ea_set_wsl_inode(), the err variable could be returned without initialization if no flags are set and rdev is zero. Additionally, ea_size might remain uninitialized from the caller's perspective if no EA operations are performed. While these cases might not be triggered under current logic, we initialize them to zero to satisfy the static checker. Reported-by: Dan Carpenter Reviewed-by: Hyunchul Lee Signed-off-by: Namjae Jeon --- fs/ntfs/ea.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/ntfs/ea.c b/fs/ntfs/ea.c index ee99baf9c7d2..c4a4a3e3e599 100644 --- a/fs/ntfs/ea.c +++ b/fs/ntfs/ea.c @@ -406,7 +406,10 @@ int ntfs_ea_set_wsl_inode(struct inode *inode, dev_t rdev, __le16 *ea_size, unsigned int flags) { __le32 v; - int err; + int err = 0; + + if (ea_size) + *ea_size = 0; if (flags & NTFS_EA_UID) { /* Store uid to lxuid EA */ From e8b79d09e3121390ebd04591ac1d8c4dea811815 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 10 Apr 2026 09:47:25 +0300 Subject: [PATCH 08/13] ntfs: add missing error code in ntfs_mft_record_alloc() Return -ENOMEM if the kmalloc() fails. Don't return success. Signed-off-by: Dan Carpenter Reviewed-by: Hyunchul Lee Signed-off-by: Namjae Jeon --- fs/ntfs/mft.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/ntfs/mft.c b/fs/ntfs/mft.c index 60d64de51d21..7d989267a82b 100644 --- a/fs/ntfs/mft.c +++ b/fs/ntfs/mft.c @@ -2503,6 +2503,7 @@ int ntfs_mft_record_alloc(struct ntfs_volume *vol, const int mode, folio_unlock(folio); kunmap_local(m); folio_put(folio); + err = -ENOMEM; goto undo_mftbmp_alloc; } From 32ba4750dfc6f4139b90fefe59ce8866b2eab56d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 10 Apr 2026 13:10:57 +0300 Subject: [PATCH 09/13] ntfs: delete dead code We know "ret2" is zero so there is no need to check. Delete the if statement. Signed-off-by: Dan Carpenter Reviewed-by: Hyunchul Lee Signed-off-by: Namjae Jeon --- fs/ntfs/file.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index 34003fa07dd1..ffd753740fcf 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c @@ -525,10 +525,9 @@ static ssize_t ntfs_dio_write_iter(struct kiocb *iocb, struct iov_iter *from) ret = -EIO; goto out; } - if (!ret2) - invalidate_mapping_pages(iocb->ki_filp->f_mapping, - offset >> PAGE_SHIFT, - end >> PAGE_SHIFT); + invalidate_mapping_pages(iocb->ki_filp->f_mapping, + offset >> PAGE_SHIFT, + end >> PAGE_SHIFT); } out: From dacc18029ef69ed225fdb4d7c3215c285e9e8ef4 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sat, 11 Apr 2026 00:18:30 +0900 Subject: [PATCH 10/13] ntfs: fix uninitialized variable in ntfs_map_runlist_nolock Smatch reported that ctx_needs_reset could be used uninitialized if ntfs_map_runlist_nolock() fails early when a search context is provided. Specifically, if the function returns -EIO because the attribute is resident, the code jumps to err_out. This initializes ctx_needs_reset to false to satisfy the static checker. Reported-by: Dan Carpenter Reviewed-by: Hyunchul Lee Signed-off-by: Namjae Jeon --- fs/ntfs/attrib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c index e8cc74c9c9a7..97b660eaa00c 100644 --- a/fs/ntfs/attrib.c +++ b/fs/ntfs/attrib.c @@ -92,7 +92,7 @@ int ntfs_map_runlist_nolock(struct ntfs_inode *ni, s64 vcn, struct ntfs_attr_sea struct runlist_element *rl; struct folio *put_this_folio = NULL; int err = 0; - bool ctx_is_temporary = false, ctx_needs_reset; + bool ctx_is_temporary = false, ctx_needs_reset = false; struct ntfs_attr_search_ctx old_ctx = { NULL, }; size_t new_rl_count; From 660b982305cebd242df52fe87adf6b203a12f9be Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 11 Apr 2026 00:24:49 +0900 Subject: [PATCH 11/13] ntfs: fix potential 32-bit truncation in ntfs_write_cb() Smatch warned that the bitwise negation in ntfs_write_cb() might lead to unintended truncation. Casting the block size to loff_t before bitwise negation prevents the upper 32 bits of pos from being incorrectly zeroed out during the calculation of new_vcn. Signed-off-by: Dan Carpenter Reviewed-by: Hyunchul Lee Signed-off-by: Namjae Jeon --- fs/ntfs/compress.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/ntfs/compress.c b/fs/ntfs/compress.c index 71a8d9c42674..76bd806b41ed 100644 --- a/fs/ntfs/compress.c +++ b/fs/ntfs/compress.c @@ -1374,7 +1374,8 @@ static int ntfs_write_cb(struct ntfs_inode *ni, loff_t pos, struct page **pages, bio_size = insz; } - new_vcn = ntfs_bytes_to_cluster(vol, pos & ~(ni->itype.compressed.block_size - 1)); + new_vcn = ntfs_bytes_to_cluster(vol, + pos & ~((loff_t)ni->itype.compressed.block_size - 1)); new_length = ntfs_bytes_to_cluster(vol, round_up(bio_size, vol->cluster_size)); err = ntfs_non_resident_attr_punch_hole(ni, new_vcn, ni->itype.compressed.block_clusters); From 6e0152c75d70725add4cef3b1cb10abc6efa6ad9 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Tue, 21 Apr 2026 08:13:57 +0900 Subject: [PATCH 12/13] ntfs: fix mmap_prepare writable check for shared mappings Linus pointed out that checking only VMA_WRITE_BIT is incorrect. Private writable mappings (MAP_PRIVATE) set VM_WRITE but do not write back to the filesystem. Also, mappings that can become writable via mprotect() (VM_MAYWRITE) must be handled. Use vma_desc_test_all(VMA_SHARED_BIT, VMA_MAYWRITE_BIT) instead, which matches what other filesystems do. Suggested-by: Linus Torvalds Reviewed-by: Hyunchul Lee Signed-off-by: Namjae Jeon --- fs/ntfs/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index ffd753740fcf..e8bea22b81a7 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c @@ -644,7 +644,7 @@ static int ntfs_file_mmap_prepare(struct vm_area_desc *desc) if (NInoCompressed(NTFS_I(inode))) return -EOPNOTSUPP; - if (vma_desc_test(desc, VMA_WRITE_BIT)) { + if (vma_desc_test_all(desc, VMA_SHARED_BIT, VMA_MAYWRITE_BIT)) { struct inode *inode = file_inode(file); loff_t from, to; int err; From 36ee1313199b7f16bf963c6ac0241861585125d9 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Wed, 22 Apr 2026 11:56:12 +0900 Subject: [PATCH 13/13] ntfs: use page allocation for resident attribute inline data The current kmemdup() based allocation for IOMAP_INLINE can result in inline_data pointer having a non-zero page offset. This causes iomap_inline_data_valid() to fail the check: iomap->length <= PAGE_SIZE - offset_in_page(iomap->inline_data) and triggers the kernel BUG at fs/iomap/buffered-io.c:1061. This particularly affects workloads with frequent small file access (e.g. Firefox Nightly profile on NTFS with bind mount) when using the new ntfs. This fix this by allocating a full page with alloc_page() so that page_address() always returns a page-aligned address. Reviewed-by: Hyunchul Lee Signed-off-by: Namjae Jeon --- fs/ntfs/iomap.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/fs/ntfs/iomap.c b/fs/ntfs/iomap.c index 3d1458dea90f..74a4d3e971f4 100644 --- a/fs/ntfs/iomap.c +++ b/fs/ntfs/iomap.c @@ -89,6 +89,7 @@ static int ntfs_read_iomap_begin_resident(struct inode *inode, loff_t offset, lo u32 attr_len; int err = 0; char *kattr; + struct page *ipage; if (NInoAttr(ni)) base_ni = ni->ext.base_ntfs_ino; @@ -129,15 +130,18 @@ static int ntfs_read_iomap_begin_resident(struct inode *inode, loff_t offset, lo kattr = (u8 *)ctx->attr + le16_to_cpu(ctx->attr->data.resident.value_offset); - iomap->inline_data = kmemdup(kattr, attr_len, GFP_KERNEL); - if (!iomap->inline_data) { + ipage = alloc_page(GFP_NOFS | __GFP_ZERO); + if (!ipage) { err = -ENOMEM; goto out; } + memcpy(page_address(ipage), kattr, attr_len); iomap->type = IOMAP_INLINE; + iomap->inline_data = page_address(ipage); iomap->offset = 0; iomap->length = attr_len; + iomap->private = ipage; out: if (ctx) @@ -285,8 +289,11 @@ static int ntfs_read_iomap_begin(struct inode *inode, loff_t offset, loff_t leng static int ntfs_read_iomap_end(struct inode *inode, loff_t pos, loff_t length, ssize_t written, unsigned int flags, struct iomap *iomap) { - if (iomap->type == IOMAP_INLINE) - kfree(iomap->inline_data); + if (iomap->type == IOMAP_INLINE) { + struct page *ipage = iomap->private; + + put_page(ipage); + } return written; } @@ -652,6 +659,7 @@ static int ntfs_write_iomap_begin_resident(struct inode *inode, loff_t offset, u32 attr_len; int err = 0; char *kattr; + struct page *ipage; ctx = ntfs_attr_get_search_ctx(ni, NULL); if (!ctx) { @@ -672,16 +680,19 @@ static int ntfs_write_iomap_begin_resident(struct inode *inode, loff_t offset, attr_len = le32_to_cpu(a->data.resident.value_length); kattr = (u8 *)a + le16_to_cpu(a->data.resident.value_offset); - iomap->inline_data = kmemdup(kattr, attr_len, GFP_KERNEL); - if (!iomap->inline_data) { + ipage = alloc_page(GFP_NOFS | __GFP_ZERO); + if (!ipage) { err = -ENOMEM; goto out; } + memcpy(page_address(ipage), kattr, attr_len); iomap->type = IOMAP_INLINE; + iomap->inline_data = page_address(ipage); iomap->offset = 0; /* iomap requires there is only one INLINE_DATA extent */ iomap->length = attr_len; + iomap->private = ipage; out: if (ctx) @@ -771,6 +782,7 @@ static int ntfs_write_iomap_end_resident(struct inode *inode, loff_t pos, u32 attr_len; int err; char *kattr; + struct page *ipage = iomap->private; mutex_lock(&ni->mrec_lock); ctx = ntfs_attr_get_search_ctx(ni, NULL); @@ -799,7 +811,7 @@ static int ntfs_write_iomap_end_resident(struct inode *inode, loff_t pos, mark_mft_record_dirty(ctx->ntfs_ino); err_out: ntfs_attr_put_search_ctx(ctx); - kfree(iomap->inline_data); + put_page(ipage); mutex_unlock(&ni->mrec_lock); return written;