Skip to content

Commit

Permalink
NTFS: Fix fs/ntfs/aops.c::ntfs_{read,write}_block() to handle the case
Browse files Browse the repository at this point in the history
      where a concurrent truncate has truncated the runlist under our feet.

Signed-off-by: Anton Altaparmakov <aia21@cantab.net>
  • Loading branch information
AntonAltaparmakov committed Sep 8, 2005
1 parent 54b02eb commit 8273d5d
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 11 deletions.
2 changes: 2 additions & 0 deletions fs/ntfs/ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -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...
Expand Down
51 changes: 40 additions & 11 deletions fs/ntfs/aops.c
Original file line number Diff line number Diff line change
Expand Up @@ -204,13 +204,15 @@ static int ntfs_read_block(struct page *page)
nr = i = 0;
do {
u8 *kaddr;
int err;

if (unlikely(buffer_uptodate(bh)))
continue;
if (unlikely(buffer_mapped(bh))) {
arr[nr++] = bh;
continue;
}
err = 0;
bh->b_bdev = vol->sb->s_bdev;
/* Is the block within the allowed limits? */
if (iblock < lblock) {
Expand Down Expand Up @@ -252,7 +254,6 @@ static int ntfs_read_block(struct page *page)
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
Expand All @@ -263,20 +264,30 @@ static int ntfs_read_block(struct page *page)
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
Expand All @@ -289,9 +300,10 @@ static int ntfs_read_block(struct page *page)
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. */
Expand Down Expand Up @@ -711,20 +723,37 @@ static int ntfs_write_block(struct page *page, struct writeback_control *wbc)
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);

Expand Down

0 comments on commit 8273d5d

Please sign in to comment.