NTFS: Fix fs/ntfs/aops.c::ntfs_{read,write}_block() to handle the case

where a concurrent truncate has truncated the runlist under our feet.

Signed-off-by: Anton Altaparmakov <aia21@cantab.net>
This commit is contained in:
Anton Altaparmakov 2005-09-08 22:00:33 +01:00
parent 54b02eb01c
commit 8273d5d4c2
2 changed files with 42 additions and 11 deletions

View File

@ -84,6 +84,8 @@ ToDo/Notes:
- Optimize fs/ntfs/aops.c::ntfs_write_block() by extending the page
lock protection over the buffer submission for i/o which allows the
removal of the get_bh()/put_bh() pairs for each buffer.
- Fix fs/ntfs/aops.c::ntfs_{read,write}_block() to handle the case
where a concurrent truncate has truncated the runlist under our feet.
2.1.23 - Implement extension of resident files and make writing safe as well as
many bug fixes, cleanups, and enhancements...

View File

@ -204,6 +204,7 @@ static int ntfs_read_block(struct page *page)
nr = i = 0;
do {
u8 *kaddr;
int err;
if (unlikely(buffer_uptodate(bh)))
continue;
@ -211,6 +212,7 @@ static int ntfs_read_block(struct page *page)
arr[nr++] = bh;
continue;
}
err = 0;
bh->b_bdev = vol->sb->s_bdev;
/* Is the block within the allowed limits? */
if (iblock < lblock) {
@ -252,7 +254,6 @@ lock_retry_remap:
goto handle_hole;
/* If first try and runlist unmapped, map and retry. */
if (!is_retry && lcn == LCN_RL_NOT_MAPPED) {
int err;
is_retry = TRUE;
/*
* Attempt to map runlist, dropping lock for
@ -263,20 +264,30 @@ lock_retry_remap:
if (likely(!err))
goto lock_retry_remap;
rl = NULL;
lcn = err;
} else if (!rl)
up_read(&ni->runlist.lock);
/*
* If buffer is outside the runlist, treat it as a
* hole. This can happen due to concurrent truncate
* for example.
*/
if (err == -ENOENT || lcn == LCN_ENOENT) {
err = 0;
goto handle_hole;
}
/* Hard error, zero out region. */
if (!err)
err = -EIO;
bh->b_blocknr = -1;
SetPageError(page);
ntfs_error(vol->sb, "Failed to read from inode 0x%lx, "
"attribute type 0x%x, vcn 0x%llx, "
"offset 0x%x because its location on "
"disk could not be determined%s "
"(error code %lli).", ni->mft_no,
"(error code %i).", ni->mft_no,
ni->type, (unsigned long long)vcn,
vcn_ofs, is_retry ? " even after "
"retrying" : "", (long long)lcn);
"retrying" : "", err);
}
/*
* Either iblock was outside lblock limits or
@ -289,9 +300,10 @@ handle_hole:
handle_zblock:
kaddr = kmap_atomic(page, KM_USER0);
memset(kaddr + i * blocksize, 0, blocksize);
flush_dcache_page(page);
kunmap_atomic(kaddr, KM_USER0);
set_buffer_uptodate(bh);
flush_dcache_page(page);
if (likely(!err))
set_buffer_uptodate(bh);
} while (i++, iblock++, (bh = bh->b_this_page) != head);
/* Release the lock if we took it. */
@ -711,20 +723,37 @@ lock_retry_remap:
if (likely(!err))
goto lock_retry_remap;
rl = NULL;
lcn = err;
} else if (!rl)
up_read(&ni->runlist.lock);
/*
* If buffer is outside the runlist, truncate has cut it out
* of the runlist. Just clean and clear the buffer and set it
* uptodate so it can get discarded by the VM.
*/
if (err == -ENOENT || lcn == LCN_ENOENT) {
u8 *kaddr;
bh->b_blocknr = -1;
clear_buffer_dirty(bh);
kaddr = kmap_atomic(page, KM_USER0);
memset(kaddr + bh_offset(bh), 0, blocksize);
kunmap_atomic(kaddr, KM_USER0);
flush_dcache_page(page);
set_buffer_uptodate(bh);
err = 0;
continue;
}
/* Failed to map the buffer, even after retrying. */
if (!err)
err = -EIO;
bh->b_blocknr = -1;
ntfs_error(vol->sb, "Failed to write to inode 0x%lx, "
"attribute type 0x%x, vcn 0x%llx, offset 0x%x "
"because its location on disk could not be "
"determined%s (error code %lli).", ni->mft_no,
"determined%s (error code %i).", ni->mft_no,
ni->type, (unsigned long long)vcn,
vcn_ofs, is_retry ? " even after "
"retrying" : "", (long long)lcn);
if (!err)
err = -EIO;
"retrying" : "", err);
break;
} while (block++, (bh = bh->b_this_page) != head);