diff options
Diffstat (limited to 'fs/ntfs')
-rw-r--r-- | fs/ntfs/aops.c | 73 | ||||
-rw-r--r-- | fs/ntfs/aops.h | 13 | ||||
-rw-r--r-- | fs/ntfs/attrib.c | 32 | ||||
-rw-r--r-- | fs/ntfs/compress.c | 6 | ||||
-rw-r--r-- | fs/ntfs/file.c | 17 | ||||
-rw-r--r-- | fs/ntfs/inode.c | 17 | ||||
-rw-r--r-- | fs/ntfs/logfile.c | 2 | ||||
-rw-r--r-- | fs/ntfs/mft.c | 4 | ||||
-rw-r--r-- | fs/ntfs/mft.h | 2 | ||||
-rw-r--r-- | fs/ntfs/super.c | 3 |
10 files changed, 98 insertions, 71 deletions
diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c index bb0a43860ad2..9364d35b4a10 100644 --- a/fs/ntfs/aops.c +++ b/fs/ntfs/aops.c @@ -159,7 +159,7 @@ still_busy: * * Return 0 on success and -errno on error. * - * Contains an adapted version of fs/buffer.c::block_read_full_page(). + * Contains an adapted version of fs/buffer.c::block_read_full_folio(). */ static int ntfs_read_block(struct page *page) { @@ -342,7 +342,7 @@ handle_zblock: for (i = 0; i < nr; i++) { tbh = arr[i]; if (likely(!buffer_uptodate(tbh))) - submit_bh(REQ_OP_READ, 0, tbh); + submit_bh(REQ_OP_READ, tbh); else ntfs_end_buffer_async_read(tbh, 1); } @@ -358,16 +358,16 @@ handle_zblock: } /** - * ntfs_readpage - fill a @page of a @file with data from the device - * @file: open file to which the page @page belongs or NULL - * @page: page cache page to fill with data + * ntfs_read_folio - fill a @folio of a @file with data from the device + * @file: open file to which the folio @folio belongs or NULL + * @folio: page cache folio to fill with data * - * For non-resident attributes, ntfs_readpage() fills the @page of the open - * file @file by calling the ntfs version of the generic block_read_full_page() + * For non-resident attributes, ntfs_read_folio() fills the @folio of the open + * file @file by calling the ntfs version of the generic block_read_full_folio() * function, ntfs_read_block(), which in turn creates and reads in the buffers - * associated with the page asynchronously. + * associated with the folio asynchronously. * - * For resident attributes, OTOH, ntfs_readpage() fills @page by copying the + * For resident attributes, OTOH, ntfs_read_folio() fills @folio by copying the * data from the mft record (which at this stage is most likely in memory) and * fills the remainder with zeroes. Thus, in this case, I/O is synchronous, as * even if the mft record is not cached at this point in time, we need to wait @@ -375,8 +375,9 @@ handle_zblock: * * Return 0 on success and -errno on error. */ -static int ntfs_readpage(struct file *file, struct page *page) +static int ntfs_read_folio(struct file *file, struct folio *folio) { + struct page *page = &folio->page; loff_t i_size; struct inode *vi; ntfs_inode *ni, *base_ni; @@ -458,7 +459,7 @@ retry_readpage: } /* * If a parallel write made the attribute non-resident, drop the mft - * record and retry the readpage. + * record and retry the read_folio. */ if (unlikely(NInoNonResident(ni))) { unmap_mft_record(base_ni); @@ -593,12 +594,12 @@ static int ntfs_write_block(struct page *page, struct writeback_control *wbc) iblock = initialized_size >> blocksize_bits; /* - * Be very careful. We have no exclusion from __set_page_dirty_buffers + * Be very careful. We have no exclusion from block_dirty_folio * here, and the (potentially unmapped) buffers may become dirty at * any time. If a buffer becomes dirty here after we've inspected it * then we just miss that fact, and the page stays dirty. * - * Buffers outside i_size may be dirtied by __set_page_dirty_buffers; + * Buffers outside i_size may be dirtied by block_dirty_folio; * handle that here by just cleaning them. */ @@ -637,10 +638,11 @@ static int ntfs_write_block(struct page *page, struct writeback_control *wbc) if (unlikely((block >= iblock) && (initialized_size < i_size))) { /* - * If this page is fully outside initialized size, zero - * out all pages between the current initialized size - * and the current page. Just use ntfs_readpage() to do - * the zeroing transparently. + * If this page is fully outside initialized + * size, zero out all pages between the current + * initialized size and the current page. Just + * use ntfs_read_folio() to do the zeroing + * transparently. */ if (block > iblock) { // TODO: @@ -653,7 +655,7 @@ static int ntfs_write_block(struct page *page, struct writeback_control *wbc) // Update initialized size in the attribute and // in the inode. // Again, for each page do: - // __set_page_dirty_buffers(); + // block_dirty_folio(); // put_page() // We don't need to wait on the writes. // Update iblock. @@ -798,7 +800,7 @@ lock_retry_remap: /* For the error case, need to reset bh to the beginning. */ bh = head; - /* Just an optimization, so ->readpage() is not called later. */ + /* Just an optimization, so ->read_folio() is not called later. */ if (unlikely(!PageUptodate(page))) { int uptodate = 1; do { @@ -857,7 +859,7 @@ lock_retry_remap: do { struct buffer_head *next = bh->b_this_page; if (buffer_async_write(bh)) { - submit_bh(REQ_OP_WRITE, 0, bh); + submit_bh(REQ_OP_WRITE, bh); need_end_writeback = false; } bh = next; @@ -1185,7 +1187,7 @@ lock_retry_remap: BUG_ON(!buffer_mapped(tbh)); get_bh(tbh); tbh->b_end_io = end_buffer_write_sync; - submit_bh(REQ_OP_WRITE, 0, tbh); + submit_bh(REQ_OP_WRITE, tbh); } /* Synchronize the mft mirror now if not @sync. */ if (is_mft && !sync) @@ -1329,7 +1331,7 @@ done: * vfs inode dirty code path for the inode the mft record belongs to or via the * vm page dirty code path for the page the mft record is in. * - * Based on ntfs_readpage() and fs/buffer.c::block_write_full_page(). + * Based on ntfs_read_folio() and fs/buffer.c::block_write_full_page(). * * Return 0 on success and -errno on error. */ @@ -1350,12 +1352,13 @@ retry_writepage: /* Is the page fully outside i_size? (truncate in progress) */ if (unlikely(page->index >= (i_size + PAGE_SIZE - 1) >> PAGE_SHIFT)) { + struct folio *folio = page_folio(page); /* * The page may have dirty, unmapped buffers. Make them * freeable here, so the page does not leak. */ - block_invalidatepage(page, 0, PAGE_SIZE); - unlock_page(page); + block_invalidate_folio(folio, 0, folio_size(folio)); + folio_unlock(folio); ntfs_debug("Write outside i_size - truncated?"); return 0; } @@ -1650,13 +1653,13 @@ hole: * attributes. */ const struct address_space_operations ntfs_normal_aops = { - .readpage = ntfs_readpage, + .read_folio = ntfs_read_folio, #ifdef NTFS_RW .writepage = ntfs_writepage, - .set_page_dirty = __set_page_dirty_buffers, + .dirty_folio = block_dirty_folio, #endif /* NTFS_RW */ .bmap = ntfs_bmap, - .migratepage = buffer_migrate_page, + .migrate_folio = buffer_migrate_folio, .is_partially_uptodate = block_is_partially_uptodate, .error_remove_page = generic_error_remove_page, }; @@ -1665,12 +1668,12 @@ const struct address_space_operations ntfs_normal_aops = { * ntfs_compressed_aops - address space operations for compressed inodes */ const struct address_space_operations ntfs_compressed_aops = { - .readpage = ntfs_readpage, + .read_folio = ntfs_read_folio, #ifdef NTFS_RW .writepage = ntfs_writepage, - .set_page_dirty = __set_page_dirty_buffers, + .dirty_folio = block_dirty_folio, #endif /* NTFS_RW */ - .migratepage = buffer_migrate_page, + .migrate_folio = buffer_migrate_folio, .is_partially_uptodate = block_is_partially_uptodate, .error_remove_page = generic_error_remove_page, }; @@ -1680,14 +1683,12 @@ const struct address_space_operations ntfs_compressed_aops = { * and attributes */ const struct address_space_operations ntfs_mst_aops = { - .readpage = ntfs_readpage, /* Fill page with data. */ + .read_folio = ntfs_read_folio, /* Fill page with data. */ #ifdef NTFS_RW .writepage = ntfs_writepage, /* Write dirty page to disk. */ - .set_page_dirty = __set_page_dirty_nobuffers, /* Set the page dirty - without touching the buffers - belonging to the page. */ + .dirty_folio = filemap_dirty_folio, #endif /* NTFS_RW */ - .migratepage = buffer_migrate_page, + .migrate_folio = buffer_migrate_folio, .is_partially_uptodate = block_is_partially_uptodate, .error_remove_page = generic_error_remove_page, }; @@ -1747,7 +1748,7 @@ void mark_ntfs_record_dirty(struct page *page, const unsigned int ofs) { set_buffer_dirty(bh); } while ((bh = bh->b_this_page) != head); spin_unlock(&mapping->private_lock); - __set_page_dirty_nobuffers(page); + filemap_dirty_folio(mapping, page_folio(page)); if (unlikely(buffers_to_free)) { do { bh = buffers_to_free->b_this_page; diff --git a/fs/ntfs/aops.h b/fs/ntfs/aops.h index f0962d46bd67..0cac5458c023 100644 --- a/fs/ntfs/aops.h +++ b/fs/ntfs/aops.h @@ -37,9 +37,9 @@ static inline void ntfs_unmap_page(struct page *page) * Read a page from the page cache of the address space @mapping at position * @index, where @index is in units of PAGE_SIZE, and not in bytes. * - * If the page is not in memory it is loaded from disk first using the readpage - * method defined in the address space operations of @mapping and the page is - * added to the page cache of @mapping in the process. + * If the page is not in memory it is loaded from disk first using the + * read_folio method defined in the address space operations of @mapping + * and the page is added to the page cache of @mapping in the process. * * If the page belongs to an mst protected attribute and it is marked as such * in its ntfs inode (NInoMstProtected()) the mst fixups are applied but no @@ -74,13 +74,8 @@ static inline struct page *ntfs_map_page(struct address_space *mapping, { struct page *page = read_mapping_page(mapping, index, NULL); - if (!IS_ERR(page)) { + if (!IS_ERR(page)) kmap(page); - if (!PageError(page)) - return page; - ntfs_unmap_page(page); - return ERR_PTR(-EIO); - } return page; } diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c index d563abc3e136..a3865bc4a0c6 100644 --- a/fs/ntfs/attrib.c +++ b/fs/ntfs/attrib.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-or-later -/** +/* * attrib.c - NTFS attribute operations. Part of the Linux-NTFS project. * * Copyright (c) 2001-2012 Anton Altaparmakov and Tuxera Inc. @@ -592,15 +592,39 @@ static int ntfs_attr_find(const ATTR_TYPE type, const ntfschar *name, a = (ATTR_RECORD*)((u8*)ctx->attr + le32_to_cpu(ctx->attr->length)); for (;; a = (ATTR_RECORD*)((u8*)a + le32_to_cpu(a->length))) { - if ((u8*)a < (u8*)ctx->mrec || (u8*)a > (u8*)ctx->mrec + - le32_to_cpu(ctx->mrec->bytes_allocated)) + u8 *mrec_end = (u8 *)ctx->mrec + + le32_to_cpu(ctx->mrec->bytes_allocated); + u8 *name_end; + + /* check whether ATTR_RECORD wrap */ + if ((u8 *)a < (u8 *)ctx->mrec) break; + + /* check whether Attribute Record Header is within bounds */ + if ((u8 *)a > mrec_end || + (u8 *)a + sizeof(ATTR_RECORD) > mrec_end) + break; + + /* check whether ATTR_RECORD's name is within bounds */ + name_end = (u8 *)a + le16_to_cpu(a->name_offset) + + a->name_length * sizeof(ntfschar); + if (name_end > mrec_end) + break; + ctx->attr = a; if (unlikely(le32_to_cpu(a->type) > le32_to_cpu(type) || a->type == AT_END)) return -ENOENT; if (unlikely(!a->length)) break; + + /* check whether ATTR_RECORD's length wrap */ + if ((u8 *)a + le32_to_cpu(a->length) < (u8 *)a) + break; + /* check whether ATTR_RECORD's length is within bounds */ + if ((u8 *)a + le32_to_cpu(a->length) > mrec_end) + break; + if (a->type != type) continue; /* @@ -1719,7 +1743,7 @@ int ntfs_attr_make_non_resident(ntfs_inode *ni, const u32 data_size) vi->i_blocks = ni->allocated_size >> 9; write_unlock_irqrestore(&ni->size_lock, flags); /* - * This needs to be last since the address space operations ->readpage + * This needs to be last since the address space operations ->read_folio * and ->writepage can run concurrently with us as they are not * serialized on i_mutex. Note, we are not allowed to fail once we flip * this switch, which is another reason to do this last. diff --git a/fs/ntfs/compress.c b/fs/ntfs/compress.c index d2f9d6a0ee32..587e9b187873 100644 --- a/fs/ntfs/compress.c +++ b/fs/ntfs/compress.c @@ -658,7 +658,7 @@ lock_retry_remap: } get_bh(tbh); tbh->b_end_io = end_buffer_read_sync; - submit_bh(REQ_OP_READ, 0, tbh); + submit_bh(REQ_OP_READ, tbh); } /* Wait for io completion on all buffer heads. */ @@ -780,12 +780,12 @@ lock_retry_remap: /* Uncompressed cb, copy it to the destination pages. */ /* * TODO: As a big optimization, we could detect this case - * before we read all the pages and use block_read_full_page() + * before we read all the pages and use block_read_full_folio() * on all full pages instead (we still have to treat partial * pages especially but at least we are getting rid of the * synchronous io for the majority of pages. * Or if we choose not to do the read-ahead/-behind stuff, we - * could just return block_read_full_page(pages[xpage]) as long + * could just return block_read_full_folio(pages[xpage]) as long * as PAGE_SIZE <= cb_size. */ if (cb_max_ofs) diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index 2ae25e48a41a..c481b14e4fd9 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c @@ -219,11 +219,6 @@ do_non_resident_extend: err = PTR_ERR(page); goto init_err_out; } - if (unlikely(PageError(page))) { - put_page(page); - err = -EIO; - goto init_err_out; - } /* * Update the initialized size in the ntfs inode. This is * enough to make ntfs_writepage() work. @@ -251,14 +246,14 @@ do_non_resident_extend: * * TODO: For sparse pages could optimize this workload by using * the FsMisc / MiscFs page bit as a "PageIsSparse" bit. This - * would be set in readpage for sparse pages and here we would + * would be set in read_folio for sparse pages and here we would * not need to mark dirty any pages which have this bit set. * The only caveat is that we have to clear the bit everywhere * where we allocate any clusters that lie in the page or that * contain the page. * * TODO: An even greater optimization would be for us to only - * call readpage() on pages which are not in sparse regions as + * call read_folio() on pages which are not in sparse regions as * determined from the runlist. This would greatly reduce the * number of pages we read and make dirty in the case of sparse * files. @@ -532,12 +527,12 @@ err_out: goto out; } -static inline int ntfs_submit_bh_for_read(struct buffer_head *bh) +static inline void ntfs_submit_bh_for_read(struct buffer_head *bh) { lock_buffer(bh); get_bh(bh); bh->b_end_io = end_buffer_read_sync; - return submit_bh(REQ_OP_READ, 0, bh); + submit_bh(REQ_OP_READ, bh); } /** @@ -1772,11 +1767,11 @@ static ssize_t ntfs_perform_write(struct file *file, struct iov_iter *i, last_vcn = -1; do { VCN vcn; - pgoff_t idx, start_idx; + pgoff_t start_idx; unsigned ofs, do_pages, u; size_t copied; - start_idx = idx = pos >> PAGE_SHIFT; + start_idx = pos >> PAGE_SHIFT; ofs = pos & ~PAGE_MASK; bytes = PAGE_SIZE - ofs; do_pages = 1; diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index 4474adb393ca..08c659332e26 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c @@ -310,7 +310,7 @@ struct inode *ntfs_alloc_big_inode(struct super_block *sb) ntfs_inode *ni; ntfs_debug("Entering."); - ni = kmem_cache_alloc(ntfs_big_inode_cache, GFP_NOFS); + ni = alloc_inode_sb(sb, ntfs_big_inode_cache, GFP_NOFS); if (likely(ni != NULL)) { ni->state = 0; return VFS_I(ni); @@ -1829,10 +1829,17 @@ int ntfs_read_inode_mount(struct inode *vi) goto err_out; } + /* Sanity check offset to the first attribute */ + if (le16_to_cpu(m->attrs_offset) >= le32_to_cpu(m->bytes_allocated)) { + ntfs_error(sb, "Incorrect mft offset to the first attribute %u in superblock.", + le16_to_cpu(m->attrs_offset)); + goto err_out; + } + /* Need this to sanity check attribute list references to $MFT. */ vi->i_generation = ni->seq_no = le16_to_cpu(m->sequence_number); - /* Provides readpage() for map_mft_record(). */ + /* Provides read_folio() for map_mft_record(). */ vi->i_mapping->a_ops = &ntfs_mst_aops; ctx = ntfs_attr_get_search_ctx(ni, m); @@ -1881,6 +1888,10 @@ int ntfs_read_inode_mount(struct inode *vi) } /* Now allocate memory for the attribute list. */ ni->attr_list_size = (u32)ntfs_attr_size(a); + if (!ni->attr_list_size) { + ntfs_error(sb, "Attr_list_size is zero"); + goto put_err_out; + } ni->attr_list = ntfs_malloc_nofs(ni->attr_list_size); if (!ni->attr_list) { ntfs_error(sb, "Not enough memory to allocate buffer " @@ -2499,7 +2510,7 @@ retry_truncate: * between the old data_size, i.e. old_size, and the new_size * has not been zeroed. Fortunately, we do not need to zero it * either since on one hand it will either already be zero due - * to both readpage and writepage clearing partial page data + * to both read_folio and writepage clearing partial page data * beyond i_size in which case there is nothing to do or in the * case of the file being mmap()ped at the same time, POSIX * specifies that the behaviour is unspecified thus we do not diff --git a/fs/ntfs/logfile.c b/fs/ntfs/logfile.c index bc1bf217b38e..6ce60ffc6ac0 100644 --- a/fs/ntfs/logfile.c +++ b/fs/ntfs/logfile.c @@ -807,7 +807,7 @@ map_vcn: * completed ignore errors afterwards as we can assume * that if one buffer worked all of them will work. */ - submit_bh(REQ_OP_WRITE, 0, bh); + submit_bh(REQ_OP_WRITE, bh); if (should_wait) { should_wait = false; wait_on_buffer(bh); diff --git a/fs/ntfs/mft.c b/fs/ntfs/mft.c index 0d62cd5bb7f8..f7bf5ce960cc 100644 --- a/fs/ntfs/mft.c +++ b/fs/ntfs/mft.c @@ -583,7 +583,7 @@ int ntfs_sync_mft_mirror(ntfs_volume *vol, const unsigned long mft_no, clear_buffer_dirty(tbh); get_bh(tbh); tbh->b_end_io = end_buffer_write_sync; - submit_bh(REQ_OP_WRITE, 0, tbh); + submit_bh(REQ_OP_WRITE, tbh); } /* Wait on i/o completion of buffers. */ for (i_bhs = 0; i_bhs < nr_bhs; i_bhs++) { @@ -780,7 +780,7 @@ int write_mft_record_nolock(ntfs_inode *ni, MFT_RECORD *m, int sync) clear_buffer_dirty(tbh); get_bh(tbh); tbh->b_end_io = end_buffer_write_sync; - submit_bh(REQ_OP_WRITE, 0, tbh); + submit_bh(REQ_OP_WRITE, tbh); } /* Synchronize the mft mirror now if not @sync. */ if (!sync && ni->mft_no < vol->mftmirr_size) diff --git a/fs/ntfs/mft.h b/fs/ntfs/mft.h index 17bfefc30271..49c001af16ed 100644 --- a/fs/ntfs/mft.h +++ b/fs/ntfs/mft.h @@ -79,7 +79,7 @@ extern int write_mft_record_nolock(ntfs_inode *ni, MFT_RECORD *m, int sync); * paths and via the page cache write back code paths or between writing * neighbouring mft records residing in the same page. * - * Locking the page also serializes us against ->readpage() if the page is not + * Locking the page also serializes us against ->read_folio() if the page is not * uptodate. * * On success, clean the mft record and return 0. On error, leave the mft diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index 5ae8de09b271..001f4e053c85 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c @@ -2092,7 +2092,8 @@ get_ctx_vol_failed: // TODO: Initialize security. /* Get the extended system files' directory inode. */ vol->extend_ino = ntfs_iget(sb, FILE_Extend); - if (IS_ERR(vol->extend_ino) || is_bad_inode(vol->extend_ino)) { + if (IS_ERR(vol->extend_ino) || is_bad_inode(vol->extend_ino) || + !S_ISDIR(vol->extend_ino->i_mode)) { if (!IS_ERR(vol->extend_ino)) iput(vol->extend_ino); ntfs_error(sb, "Failed to load $Extend."); |