aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ntfs/aops.c
diff options
context:
space:
mode:
authorAnton Altaparmakov <aia21@cantab.net>2005-09-08 17:00:33 -0400
committerAnton Altaparmakov <aia21@cantab.net>2005-09-08 17:00:33 -0400
commit8273d5d4c28a9fde68f830cc6ff61e37e8ae1dca (patch)
treed4abd74f9b9b5ea9d84f1b9bcfe80e75f72f36d3 /fs/ntfs/aops.c
parent54b02eb01c0172294e43e2b54d6815f65637c111 (diff)
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>
Diffstat (limited to 'fs/ntfs/aops.c')
-rw-r--r--fs/ntfs/aops.c51
1 files changed, 40 insertions, 11 deletions
diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c
index 821dad7d14c8..59389a8801bc 100644
--- a/fs/ntfs/aops.c
+++ b/fs/ntfs/aops.c
@@ -204,6 +204,7 @@ static int ntfs_read_block(struct page *page)
204 nr = i = 0; 204 nr = i = 0;
205 do { 205 do {
206 u8 *kaddr; 206 u8 *kaddr;
207 int err;
207 208
208 if (unlikely(buffer_uptodate(bh))) 209 if (unlikely(buffer_uptodate(bh)))
209 continue; 210 continue;
@@ -211,6 +212,7 @@ static int ntfs_read_block(struct page *page)
211 arr[nr++] = bh; 212 arr[nr++] = bh;
212 continue; 213 continue;
213 } 214 }
215 err = 0;
214 bh->b_bdev = vol->sb->s_bdev; 216 bh->b_bdev = vol->sb->s_bdev;
215 /* Is the block within the allowed limits? */ 217 /* Is the block within the allowed limits? */
216 if (iblock < lblock) { 218 if (iblock < lblock) {
@@ -252,7 +254,6 @@ lock_retry_remap:
252 goto handle_hole; 254 goto handle_hole;
253 /* If first try and runlist unmapped, map and retry. */ 255 /* If first try and runlist unmapped, map and retry. */
254 if (!is_retry && lcn == LCN_RL_NOT_MAPPED) { 256 if (!is_retry && lcn == LCN_RL_NOT_MAPPED) {
255 int err;
256 is_retry = TRUE; 257 is_retry = TRUE;
257 /* 258 /*
258 * Attempt to map runlist, dropping lock for 259 * Attempt to map runlist, dropping lock for
@@ -263,20 +264,30 @@ lock_retry_remap:
263 if (likely(!err)) 264 if (likely(!err))
264 goto lock_retry_remap; 265 goto lock_retry_remap;
265 rl = NULL; 266 rl = NULL;
266 lcn = err;
267 } else if (!rl) 267 } else if (!rl)
268 up_read(&ni->runlist.lock); 268 up_read(&ni->runlist.lock);
269 /*
270 * If buffer is outside the runlist, treat it as a
271 * hole. This can happen due to concurrent truncate
272 * for example.
273 */
274 if (err == -ENOENT || lcn == LCN_ENOENT) {
275 err = 0;
276 goto handle_hole;
277 }
269 /* Hard error, zero out region. */ 278 /* Hard error, zero out region. */
279 if (!err)
280 err = -EIO;
270 bh->b_blocknr = -1; 281 bh->b_blocknr = -1;
271 SetPageError(page); 282 SetPageError(page);
272 ntfs_error(vol->sb, "Failed to read from inode 0x%lx, " 283 ntfs_error(vol->sb, "Failed to read from inode 0x%lx, "
273 "attribute type 0x%x, vcn 0x%llx, " 284 "attribute type 0x%x, vcn 0x%llx, "
274 "offset 0x%x because its location on " 285 "offset 0x%x because its location on "
275 "disk could not be determined%s " 286 "disk could not be determined%s "
276 "(error code %lli).", ni->mft_no, 287 "(error code %i).", ni->mft_no,
277 ni->type, (unsigned long long)vcn, 288 ni->type, (unsigned long long)vcn,
278 vcn_ofs, is_retry ? " even after " 289 vcn_ofs, is_retry ? " even after "
279 "retrying" : "", (long long)lcn); 290 "retrying" : "", err);
280 } 291 }
281 /* 292 /*
282 * Either iblock was outside lblock limits or 293 * Either iblock was outside lblock limits or
@@ -289,9 +300,10 @@ handle_hole:
289handle_zblock: 300handle_zblock:
290 kaddr = kmap_atomic(page, KM_USER0); 301 kaddr = kmap_atomic(page, KM_USER0);
291 memset(kaddr + i * blocksize, 0, blocksize); 302 memset(kaddr + i * blocksize, 0, blocksize);
292 flush_dcache_page(page);
293 kunmap_atomic(kaddr, KM_USER0); 303 kunmap_atomic(kaddr, KM_USER0);
294 set_buffer_uptodate(bh); 304 flush_dcache_page(page);
305 if (likely(!err))
306 set_buffer_uptodate(bh);
295 } while (i++, iblock++, (bh = bh->b_this_page) != head); 307 } while (i++, iblock++, (bh = bh->b_this_page) != head);
296 308
297 /* Release the lock if we took it. */ 309 /* Release the lock if we took it. */
@@ -711,20 +723,37 @@ lock_retry_remap:
711 if (likely(!err)) 723 if (likely(!err))
712 goto lock_retry_remap; 724 goto lock_retry_remap;
713 rl = NULL; 725 rl = NULL;
714 lcn = err;
715 } else if (!rl) 726 } else if (!rl)
716 up_read(&ni->runlist.lock); 727 up_read(&ni->runlist.lock);
728 /*
729 * If buffer is outside the runlist, truncate has cut it out
730 * of the runlist. Just clean and clear the buffer and set it
731 * uptodate so it can get discarded by the VM.
732 */
733 if (err == -ENOENT || lcn == LCN_ENOENT) {
734 u8 *kaddr;
735
736 bh->b_blocknr = -1;
737 clear_buffer_dirty(bh);
738 kaddr = kmap_atomic(page, KM_USER0);
739 memset(kaddr + bh_offset(bh), 0, blocksize);
740 kunmap_atomic(kaddr, KM_USER0);
741 flush_dcache_page(page);
742 set_buffer_uptodate(bh);
743 err = 0;
744 continue;
745 }
717 /* Failed to map the buffer, even after retrying. */ 746 /* Failed to map the buffer, even after retrying. */
747 if (!err)
748 err = -EIO;
718 bh->b_blocknr = -1; 749 bh->b_blocknr = -1;
719 ntfs_error(vol->sb, "Failed to write to inode 0x%lx, " 750 ntfs_error(vol->sb, "Failed to write to inode 0x%lx, "
720 "attribute type 0x%x, vcn 0x%llx, offset 0x%x " 751 "attribute type 0x%x, vcn 0x%llx, offset 0x%x "
721 "because its location on disk could not be " 752 "because its location on disk could not be "
722 "determined%s (error code %lli).", ni->mft_no, 753 "determined%s (error code %i).", ni->mft_no,
723 ni->type, (unsigned long long)vcn, 754 ni->type, (unsigned long long)vcn,
724 vcn_ofs, is_retry ? " even after " 755 vcn_ofs, is_retry ? " even after "
725 "retrying" : "", (long long)lcn); 756 "retrying" : "", err);
726 if (!err)
727 err = -EIO;
728 break; 757 break;
729 } while (block++, (bh = bh->b_this_page) != head); 758 } while (block++, (bh = bh->b_this_page) != head);
730 759