Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ebab8990 authored by Anton Altaparmakov's avatar Anton Altaparmakov Committed by Linus Torvalds
Browse files

NTFS: Fix read regression.



The regression was caused by:
        commit[a32ea1e1] Fix read/truncate race

This causes ntfs_readpage() to be called for a zero i_size inode, which
failed when the file was compressed and non-resident.

Thanks a lot to Mike Galbraith for reporting the issue and tracking down
the commit that caused the regression.

Looking into it I found three bugs which the patch fixes.

Signed-off-by: default avatarAnton Altaparmakov <aia21@cantab.net>
Tested-by: default avatarMike Galbraith <efault@gmx.de>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 74521c28
Loading
Loading
Loading
Loading
+9 −1
Original line number Diff line number Diff line
@@ -405,6 +405,15 @@ static int ntfs_readpage(struct file *file, struct page *page)

retry_readpage:
	BUG_ON(!PageLocked(page));
	vi = page->mapping->host;
	i_size = i_size_read(vi);
	/* Is the page fully outside i_size? (truncate in progress) */
	if (unlikely(page->index >= (i_size + PAGE_CACHE_SIZE - 1) >>
			PAGE_CACHE_SHIFT)) {
		zero_user_page(page, 0, PAGE_CACHE_SIZE, KM_USER0);
		ntfs_debug("Read outside i_size - truncated?");
		goto done;
	}
	/*
	 * This can potentially happen because we clear PageUptodate() during
	 * ntfs_writepage() of MstProtected() attributes.
@@ -413,7 +422,6 @@ retry_readpage:
		unlock_page(page);
		return 0;
	}
	vi = page->mapping->host;
	ni = NTFS_I(vi);
	/*
	 * Only $DATA attributes can be encrypted and only unnamed $DATA
+1 −4
Original line number Diff line number Diff line
@@ -179,10 +179,7 @@ int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn, ntfs_attr_search_ctx *ctx)
	 * ntfs_mapping_pairs_decompress() fails.
	 */
	end_vcn = sle64_to_cpu(a->data.non_resident.highest_vcn) + 1;
	if (!a->data.non_resident.lowest_vcn && end_vcn == 1)
		end_vcn = sle64_to_cpu(a->data.non_resident.allocated_size) >>
				ni->vol->cluster_size_bits;
	if (unlikely(vcn >= end_vcn)) {
	if (unlikely(vcn && vcn >= end_vcn)) {
		err = -ENOENT;
		goto err_out;
	}
+10 −0
Original line number Diff line number Diff line
@@ -561,6 +561,16 @@ int ntfs_read_compressed_block(struct page *page)
	read_unlock_irqrestore(&ni->size_lock, flags);
	max_page = ((i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT) -
			offset;
	/* Is the page fully outside i_size? (truncate in progress) */
	if (xpage >= max_page) {
		kfree(bhs);
		kfree(pages);
		zero_user_page(page, 0, PAGE_CACHE_SIZE, KM_USER0);
		ntfs_debug("Compressed read outside i_size - truncated?");
		SetPageUptodate(page);
		unlock_page(page);
		return 0;
	}
	if (nr_pages < max_page)
		max_page = nr_pages;
	for (i = 0; i < max_page; i++, offset++) {