diff options
-rw-r--r-- | fs/xfs/xfs_file.c | 163 | ||||
-rw-r--r-- | fs/xfs/xfs_iops.c | 2 |
2 files changed, 63 insertions, 102 deletions
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 3537c8d0af48..75b8fe9229b0 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c | |||
@@ -396,114 +396,96 @@ xfs_file_splice_write( | |||
396 | } | 396 | } |
397 | 397 | ||
398 | /* | 398 | /* |
399 | * This routine is called to handle zeroing any space in the last | 399 | * This routine is called to handle zeroing any space in the last block of the |
400 | * block of the file that is beyond the EOF. We do this since the | 400 | * file that is beyond the EOF. We do this since the size is being increased |
401 | * size is being increased without writing anything to that block | 401 | * without writing anything to that block and we don't want to read the |
402 | * and we don't want anyone to read the garbage on the disk. | 402 | * garbage on the disk. |
403 | */ | 403 | */ |
404 | STATIC int /* error (positive) */ | 404 | STATIC int /* error (positive) */ |
405 | xfs_zero_last_block( | 405 | xfs_zero_last_block( |
406 | xfs_inode_t *ip, | 406 | struct xfs_inode *ip, |
407 | xfs_fsize_t offset, | 407 | xfs_fsize_t offset, |
408 | xfs_fsize_t isize) | 408 | xfs_fsize_t isize) |
409 | { | 409 | { |
410 | xfs_fileoff_t last_fsb; | 410 | struct xfs_mount *mp = ip->i_mount; |
411 | xfs_mount_t *mp = ip->i_mount; | 411 | xfs_fileoff_t last_fsb = XFS_B_TO_FSBT(mp, isize); |
412 | int nimaps; | 412 | int zero_offset = XFS_B_FSB_OFFSET(mp, isize); |
413 | int zero_offset; | 413 | int zero_len; |
414 | int zero_len; | 414 | int nimaps = 1; |
415 | int error = 0; | 415 | int error = 0; |
416 | xfs_bmbt_irec_t imap; | 416 | struct xfs_bmbt_irec imap; |
417 | |||
418 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); | ||
419 | |||
420 | zero_offset = XFS_B_FSB_OFFSET(mp, isize); | ||
421 | if (zero_offset == 0) { | ||
422 | /* | ||
423 | * There are no extra bytes in the last block on disk to | ||
424 | * zero, so return. | ||
425 | */ | ||
426 | return 0; | ||
427 | } | ||
428 | 417 | ||
429 | last_fsb = XFS_B_TO_FSBT(mp, isize); | 418 | xfs_ilock(ip, XFS_ILOCK_EXCL); |
430 | nimaps = 1; | ||
431 | error = xfs_bmapi_read(ip, last_fsb, 1, &imap, &nimaps, 0); | 419 | error = xfs_bmapi_read(ip, last_fsb, 1, &imap, &nimaps, 0); |
420 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | ||
432 | if (error) | 421 | if (error) |
433 | return error; | 422 | return error; |
423 | |||
434 | ASSERT(nimaps > 0); | 424 | ASSERT(nimaps > 0); |
425 | |||
435 | /* | 426 | /* |
436 | * If the block underlying isize is just a hole, then there | 427 | * If the block underlying isize is just a hole, then there |
437 | * is nothing to zero. | 428 | * is nothing to zero. |
438 | */ | 429 | */ |
439 | if (imap.br_startblock == HOLESTARTBLOCK) { | 430 | if (imap.br_startblock == HOLESTARTBLOCK) |
440 | return 0; | 431 | return 0; |
441 | } | ||
442 | /* | ||
443 | * Zero the part of the last block beyond the EOF, and write it | ||
444 | * out sync. We need to drop the ilock while we do this so we | ||
445 | * don't deadlock when the buffer cache calls back to us. | ||
446 | */ | ||
447 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | ||
448 | 432 | ||
449 | zero_len = mp->m_sb.sb_blocksize - zero_offset; | 433 | zero_len = mp->m_sb.sb_blocksize - zero_offset; |
450 | if (isize + zero_len > offset) | 434 | if (isize + zero_len > offset) |
451 | zero_len = offset - isize; | 435 | zero_len = offset - isize; |
452 | error = xfs_iozero(ip, isize, zero_len); | 436 | return xfs_iozero(ip, isize, zero_len); |
453 | |||
454 | xfs_ilock(ip, XFS_ILOCK_EXCL); | ||
455 | ASSERT(error >= 0); | ||
456 | return error; | ||
457 | } | 437 | } |
458 | 438 | ||
459 | /* | 439 | /* |
460 | * Zero any on disk space between the current EOF and the new, | 440 | * Zero any on disk space between the current EOF and the new, larger EOF. |
461 | * larger EOF. This handles the normal case of zeroing the remainder | 441 | * |
462 | * of the last block in the file and the unusual case of zeroing blocks | 442 | * This handles the normal case of zeroing the remainder of the last block in |
463 | * out beyond the size of the file. This second case only happens | 443 | * the file and the unusual case of zeroing blocks out beyond the size of the |
464 | * with fixed size extents and when the system crashes before the inode | 444 | * file. This second case only happens with fixed size extents and when the |
465 | * size was updated but after blocks were allocated. If fill is set, | 445 | * system crashes before the inode size was updated but after blocks were |
466 | * then any holes in the range are filled and zeroed. If not, the holes | 446 | * allocated. |
467 | * are left alone as holes. | 447 | * |
448 | * Expects the iolock to be held exclusive, and will take the ilock internally. | ||
468 | */ | 449 | */ |
469 | |||
470 | int /* error (positive) */ | 450 | int /* error (positive) */ |
471 | xfs_zero_eof( | 451 | xfs_zero_eof( |
472 | xfs_inode_t *ip, | 452 | struct xfs_inode *ip, |
473 | xfs_off_t offset, /* starting I/O offset */ | 453 | xfs_off_t offset, /* starting I/O offset */ |
474 | xfs_fsize_t isize) /* current inode size */ | 454 | xfs_fsize_t isize) /* current inode size */ |
475 | { | 455 | { |
476 | xfs_mount_t *mp = ip->i_mount; | 456 | struct xfs_mount *mp = ip->i_mount; |
477 | xfs_fileoff_t start_zero_fsb; | 457 | xfs_fileoff_t start_zero_fsb; |
478 | xfs_fileoff_t end_zero_fsb; | 458 | xfs_fileoff_t end_zero_fsb; |
479 | xfs_fileoff_t zero_count_fsb; | 459 | xfs_fileoff_t zero_count_fsb; |
480 | xfs_fileoff_t last_fsb; | 460 | xfs_fileoff_t last_fsb; |
481 | xfs_fileoff_t zero_off; | 461 | xfs_fileoff_t zero_off; |
482 | xfs_fsize_t zero_len; | 462 | xfs_fsize_t zero_len; |
483 | int nimaps; | 463 | int nimaps; |
484 | int error = 0; | 464 | int error = 0; |
485 | xfs_bmbt_irec_t imap; | 465 | struct xfs_bmbt_irec imap; |
486 | 466 | ||
487 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_IOLOCK_EXCL)); | 467 | ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL)); |
488 | ASSERT(offset > isize); | 468 | ASSERT(offset > isize); |
489 | 469 | ||
490 | /* | 470 | /* |
491 | * First handle zeroing the block on which isize resides. | 471 | * First handle zeroing the block on which isize resides. |
472 | * | ||
492 | * We only zero a part of that block so it is handled specially. | 473 | * We only zero a part of that block so it is handled specially. |
493 | */ | 474 | */ |
494 | error = xfs_zero_last_block(ip, offset, isize); | 475 | if (XFS_B_FSB_OFFSET(mp, isize) != 0) { |
495 | if (error) { | 476 | error = xfs_zero_last_block(ip, offset, isize); |
496 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_IOLOCK_EXCL)); | 477 | if (error) |
497 | return error; | 478 | return error; |
498 | } | 479 | } |
499 | 480 | ||
500 | /* | 481 | /* |
501 | * Calculate the range between the new size and the old | 482 | * Calculate the range between the new size and the old where blocks |
502 | * where blocks needing to be zeroed may exist. To get the | 483 | * needing to be zeroed may exist. |
503 | * block where the last byte in the file currently resides, | 484 | * |
504 | * we need to subtract one from the size and truncate back | 485 | * To get the block where the last byte in the file currently resides, |
505 | * to a block boundary. We subtract 1 in case the size is | 486 | * we need to subtract one from the size and truncate back to a block |
506 | * exactly on a block boundary. | 487 | * boundary. We subtract 1 in case the size is exactly on a block |
488 | * boundary. | ||
507 | */ | 489 | */ |
508 | last_fsb = isize ? XFS_B_TO_FSBT(mp, isize - 1) : (xfs_fileoff_t)-1; | 490 | last_fsb = isize ? XFS_B_TO_FSBT(mp, isize - 1) : (xfs_fileoff_t)-1; |
509 | start_zero_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)isize); | 491 | start_zero_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)isize); |
@@ -521,23 +503,18 @@ xfs_zero_eof( | |||
521 | while (start_zero_fsb <= end_zero_fsb) { | 503 | while (start_zero_fsb <= end_zero_fsb) { |
522 | nimaps = 1; | 504 | nimaps = 1; |
523 | zero_count_fsb = end_zero_fsb - start_zero_fsb + 1; | 505 | zero_count_fsb = end_zero_fsb - start_zero_fsb + 1; |
506 | |||
507 | xfs_ilock(ip, XFS_ILOCK_EXCL); | ||
524 | error = xfs_bmapi_read(ip, start_zero_fsb, zero_count_fsb, | 508 | error = xfs_bmapi_read(ip, start_zero_fsb, zero_count_fsb, |
525 | &imap, &nimaps, 0); | 509 | &imap, &nimaps, 0); |
526 | if (error) { | 510 | xfs_iunlock(ip, XFS_ILOCK_EXCL); |
527 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_IOLOCK_EXCL)); | 511 | if (error) |
528 | return error; | 512 | return error; |
529 | } | 513 | |
530 | ASSERT(nimaps > 0); | 514 | ASSERT(nimaps > 0); |
531 | 515 | ||
532 | if (imap.br_state == XFS_EXT_UNWRITTEN || | 516 | if (imap.br_state == XFS_EXT_UNWRITTEN || |
533 | imap.br_startblock == HOLESTARTBLOCK) { | 517 | imap.br_startblock == HOLESTARTBLOCK) { |
534 | /* | ||
535 | * This loop handles initializing pages that were | ||
536 | * partially initialized by the code below this | ||
537 | * loop. It basically zeroes the part of the page | ||
538 | * that sits on a hole and sets the page as P_HOLE | ||
539 | * and calls remapf if it is a mapped file. | ||
540 | */ | ||
541 | start_zero_fsb = imap.br_startoff + imap.br_blockcount; | 518 | start_zero_fsb = imap.br_startoff + imap.br_blockcount; |
542 | ASSERT(start_zero_fsb <= (end_zero_fsb + 1)); | 519 | ASSERT(start_zero_fsb <= (end_zero_fsb + 1)); |
543 | continue; | 520 | continue; |
@@ -545,11 +522,7 @@ xfs_zero_eof( | |||
545 | 522 | ||
546 | /* | 523 | /* |
547 | * There are blocks we need to zero. | 524 | * There are blocks we need to zero. |
548 | * Drop the inode lock while we're doing the I/O. | ||
549 | * We'll still have the iolock to protect us. | ||
550 | */ | 525 | */ |
551 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | ||
552 | |||
553 | zero_off = XFS_FSB_TO_B(mp, start_zero_fsb); | 526 | zero_off = XFS_FSB_TO_B(mp, start_zero_fsb); |
554 | zero_len = XFS_FSB_TO_B(mp, imap.br_blockcount); | 527 | zero_len = XFS_FSB_TO_B(mp, imap.br_blockcount); |
555 | 528 | ||
@@ -557,22 +530,14 @@ xfs_zero_eof( | |||
557 | zero_len = offset - zero_off; | 530 | zero_len = offset - zero_off; |
558 | 531 | ||
559 | error = xfs_iozero(ip, zero_off, zero_len); | 532 | error = xfs_iozero(ip, zero_off, zero_len); |
560 | if (error) { | 533 | if (error) |
561 | goto out_lock; | 534 | return error; |
562 | } | ||
563 | 535 | ||
564 | start_zero_fsb = imap.br_startoff + imap.br_blockcount; | 536 | start_zero_fsb = imap.br_startoff + imap.br_blockcount; |
565 | ASSERT(start_zero_fsb <= (end_zero_fsb + 1)); | 537 | ASSERT(start_zero_fsb <= (end_zero_fsb + 1)); |
566 | |||
567 | xfs_ilock(ip, XFS_ILOCK_EXCL); | ||
568 | } | 538 | } |
569 | 539 | ||
570 | return 0; | 540 | return 0; |
571 | |||
572 | out_lock: | ||
573 | xfs_ilock(ip, XFS_ILOCK_EXCL); | ||
574 | ASSERT(error >= 0); | ||
575 | return error; | ||
576 | } | 541 | } |
577 | 542 | ||
578 | /* | 543 | /* |
@@ -612,9 +577,7 @@ restart: | |||
612 | xfs_rw_ilock(ip, *iolock); | 577 | xfs_rw_ilock(ip, *iolock); |
613 | goto restart; | 578 | goto restart; |
614 | } | 579 | } |
615 | xfs_rw_ilock(ip, XFS_ILOCK_EXCL); | ||
616 | error = -xfs_zero_eof(ip, *pos, i_size_read(inode)); | 580 | error = -xfs_zero_eof(ip, *pos, i_size_read(inode)); |
617 | xfs_rw_iunlock(ip, XFS_ILOCK_EXCL); | ||
618 | if (error) | 581 | if (error) |
619 | return error; | 582 | return error; |
620 | } | 583 | } |
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index 0a80543644c8..efdc46114450 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c | |||
@@ -764,9 +764,7 @@ xfs_setattr_size( | |||
764 | * before the inode is joined to the transaction to modify | 764 | * before the inode is joined to the transaction to modify |
765 | * i_size. | 765 | * i_size. |
766 | */ | 766 | */ |
767 | xfs_ilock(ip, XFS_ILOCK_EXCL); | ||
768 | error = xfs_zero_eof(ip, newsize, oldsize); | 767 | error = xfs_zero_eof(ip, newsize, oldsize); |
769 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | ||
770 | if (error) | 768 | if (error) |
771 | goto out_unlock; | 769 | goto out_unlock; |
772 | } | 770 | } |