Skip to content

Commit

Permalink
NTFS: Fix read regression.
Browse files Browse the repository at this point in the history
The regression was caused by:
        commit[a32ea1e] 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: Anton Altaparmakov <[email protected]>
Tested-by:  Mike Galbraith <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
Anton Altaparmakov authored and Linus Torvalds committed Nov 3, 2007
1 parent 74521c2 commit ebab899
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 5 deletions.
10 changes: 9 additions & 1 deletion fs/ntfs/aops.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -413,7 +422,6 @@ static int ntfs_readpage(struct file *file, struct page *page)
unlock_page(page);
return 0;
}
vi = page->mapping->host;
ni = NTFS_I(vi);
/*
* Only $DATA attributes can be encrypted and only unnamed $DATA
Expand Down
5 changes: 1 addition & 4 deletions fs/ntfs/attrib.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
10 changes: 10 additions & 0 deletions fs/ntfs/compress.c
Original file line number Diff line number Diff line change
Expand Up @@ -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++) {
Expand Down

0 comments on commit ebab899

Please sign in to comment.