mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-13 23:34:05 +08:00
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:
parent
54b02eb01c
commit
8273d5d4c2
@ -84,6 +84,8 @@ ToDo/Notes:
|
|||||||
- Optimize fs/ntfs/aops.c::ntfs_write_block() by extending the page
|
- Optimize fs/ntfs/aops.c::ntfs_write_block() by extending the page
|
||||||
lock protection over the buffer submission for i/o which allows the
|
lock protection over the buffer submission for i/o which allows the
|
||||||
removal of the get_bh()/put_bh() pairs for each buffer.
|
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
|
2.1.23 - Implement extension of resident files and make writing safe as well as
|
||||||
many bug fixes, cleanups, and enhancements...
|
many bug fixes, cleanups, and enhancements...
|
||||||
|
@ -204,6 +204,7 @@ static int ntfs_read_block(struct page *page)
|
|||||||
nr = i = 0;
|
nr = i = 0;
|
||||||
do {
|
do {
|
||||||
u8 *kaddr;
|
u8 *kaddr;
|
||||||
|
int err;
|
||||||
|
|
||||||
if (unlikely(buffer_uptodate(bh)))
|
if (unlikely(buffer_uptodate(bh)))
|
||||||
continue;
|
continue;
|
||||||
@ -211,6 +212,7 @@ static int ntfs_read_block(struct page *page)
|
|||||||
arr[nr++] = bh;
|
arr[nr++] = bh;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
err = 0;
|
||||||
bh->b_bdev = vol->sb->s_bdev;
|
bh->b_bdev = vol->sb->s_bdev;
|
||||||
/* Is the block within the allowed limits? */
|
/* Is the block within the allowed limits? */
|
||||||
if (iblock < lblock) {
|
if (iblock < lblock) {
|
||||||
@ -252,7 +254,6 @@ lock_retry_remap:
|
|||||||
goto handle_hole;
|
goto handle_hole;
|
||||||
/* If first try and runlist unmapped, map and retry. */
|
/* If first try and runlist unmapped, map and retry. */
|
||||||
if (!is_retry && lcn == LCN_RL_NOT_MAPPED) {
|
if (!is_retry && lcn == LCN_RL_NOT_MAPPED) {
|
||||||
int err;
|
|
||||||
is_retry = TRUE;
|
is_retry = TRUE;
|
||||||
/*
|
/*
|
||||||
* Attempt to map runlist, dropping lock for
|
* Attempt to map runlist, dropping lock for
|
||||||
@ -263,20 +264,30 @@ lock_retry_remap:
|
|||||||
if (likely(!err))
|
if (likely(!err))
|
||||||
goto lock_retry_remap;
|
goto lock_retry_remap;
|
||||||
rl = NULL;
|
rl = NULL;
|
||||||
lcn = err;
|
|
||||||
} else if (!rl)
|
} else if (!rl)
|
||||||
up_read(&ni->runlist.lock);
|
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. */
|
/* Hard error, zero out region. */
|
||||||
|
if (!err)
|
||||||
|
err = -EIO;
|
||||||
bh->b_blocknr = -1;
|
bh->b_blocknr = -1;
|
||||||
SetPageError(page);
|
SetPageError(page);
|
||||||
ntfs_error(vol->sb, "Failed to read from inode 0x%lx, "
|
ntfs_error(vol->sb, "Failed to read from inode 0x%lx, "
|
||||||
"attribute type 0x%x, vcn 0x%llx, "
|
"attribute type 0x%x, vcn 0x%llx, "
|
||||||
"offset 0x%x because its location on "
|
"offset 0x%x because its location on "
|
||||||
"disk could not be determined%s "
|
"disk could not be determined%s "
|
||||||
"(error code %lli).", ni->mft_no,
|
"(error code %i).", ni->mft_no,
|
||||||
ni->type, (unsigned long long)vcn,
|
ni->type, (unsigned long long)vcn,
|
||||||
vcn_ofs, is_retry ? " even after "
|
vcn_ofs, is_retry ? " even after "
|
||||||
"retrying" : "", (long long)lcn);
|
"retrying" : "", err);
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Either iblock was outside lblock limits or
|
* Either iblock was outside lblock limits or
|
||||||
@ -289,9 +300,10 @@ handle_hole:
|
|||||||
handle_zblock:
|
handle_zblock:
|
||||||
kaddr = kmap_atomic(page, KM_USER0);
|
kaddr = kmap_atomic(page, KM_USER0);
|
||||||
memset(kaddr + i * blocksize, 0, blocksize);
|
memset(kaddr + i * blocksize, 0, blocksize);
|
||||||
flush_dcache_page(page);
|
|
||||||
kunmap_atomic(kaddr, KM_USER0);
|
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);
|
} while (i++, iblock++, (bh = bh->b_this_page) != head);
|
||||||
|
|
||||||
/* Release the lock if we took it. */
|
/* Release the lock if we took it. */
|
||||||
@ -711,20 +723,37 @@ lock_retry_remap:
|
|||||||
if (likely(!err))
|
if (likely(!err))
|
||||||
goto lock_retry_remap;
|
goto lock_retry_remap;
|
||||||
rl = NULL;
|
rl = NULL;
|
||||||
lcn = err;
|
|
||||||
} else if (!rl)
|
} else if (!rl)
|
||||||
up_read(&ni->runlist.lock);
|
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. */
|
/* Failed to map the buffer, even after retrying. */
|
||||||
|
if (!err)
|
||||||
|
err = -EIO;
|
||||||
bh->b_blocknr = -1;
|
bh->b_blocknr = -1;
|
||||||
ntfs_error(vol->sb, "Failed to write to inode 0x%lx, "
|
ntfs_error(vol->sb, "Failed to write to inode 0x%lx, "
|
||||||
"attribute type 0x%x, vcn 0x%llx, offset 0x%x "
|
"attribute type 0x%x, vcn 0x%llx, offset 0x%x "
|
||||||
"because its location on disk could not be "
|
"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,
|
ni->type, (unsigned long long)vcn,
|
||||||
vcn_ofs, is_retry ? " even after "
|
vcn_ofs, is_retry ? " even after "
|
||||||
"retrying" : "", (long long)lcn);
|
"retrying" : "", err);
|
||||||
if (!err)
|
|
||||||
err = -EIO;
|
|
||||||
break;
|
break;
|
||||||
} while (block++, (bh = bh->b_this_page) != head);
|
} while (block++, (bh = bh->b_this_page) != head);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user