diff options
| -rw-r--r-- | fs/ntfs/aops.c | 48 | ||||
| -rw-r--r-- | fs/ntfs/attrib.c | 16 | ||||
| -rw-r--r-- | fs/ntfs/compress.c | 3 | ||||
| -rw-r--r-- | fs/ntfs/ea.c | 5 | ||||
| -rw-r--r-- | fs/ntfs/file.c | 51 | ||||
| -rw-r--r-- | fs/ntfs/iomap.c | 28 | ||||
| -rw-r--r-- | fs/ntfs/mft.c | 5 |
7 files changed, 114 insertions, 42 deletions
diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c index 78d1ce41958e..1fbf832ad165 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, @@ -238,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, diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c index 78915c1d5128..97b660eaa00c 100644 --- a/fs/ntfs/attrib.c +++ b/fs/ntfs/attrib.c @@ -30,6 +30,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 * @vcn: map runlist part containing this vcn @@ -85,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; @@ -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; 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); 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 */ diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index e5b897a6c1e1..e8bea22b81a7 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) { @@ -534,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: @@ -654,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; @@ -885,14 +875,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; - - 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) + 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) + goto out; + } + if (end_vcn - start_vcn == 1) goto out; start_vcn++; } @@ -901,10 +896,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--; } diff --git a/fs/ntfs/iomap.c b/fs/ntfs/iomap.c index 621645fbbf2e..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; } @@ -384,7 +391,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)); @@ -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; diff --git a/fs/ntfs/mft.c b/fs/ntfs/mft.c index bf028c1aea26..7d989267a82b 100644 --- a/fs/ntfs/mft.c +++ b/fs/ntfs/mft.c @@ -2503,6 +2503,7 @@ mft_rec_already_initialized: folio_unlock(folio); kunmap_local(m); folio_put(folio); + err = -ENOMEM; goto undo_mftbmp_alloc; } @@ -2714,7 +2715,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 +2821,7 @@ flush_bio: 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 |
