aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/xfs/xfs_file.c14
-rw-r--r--fs/xfs/xfs_inode.c4
-rw-r--r--fs/xfs/xfs_inode.h9
-rw-r--r--fs/xfs/xfs_iops.c36
-rw-r--r--fs/xfs/xfs_pnfs.c4
-rw-r--r--fs/xfs/xfs_qm.c5
6 files changed, 41 insertions, 31 deletions
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index ce615d12fb44..a2e1cb8a568b 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -397,7 +397,8 @@ STATIC int /* error (positive) */
397xfs_zero_last_block( 397xfs_zero_last_block(
398 struct xfs_inode *ip, 398 struct xfs_inode *ip,
399 xfs_fsize_t offset, 399 xfs_fsize_t offset,
400 xfs_fsize_t isize) 400 xfs_fsize_t isize,
401 bool *did_zeroing)
401{ 402{
402 struct xfs_mount *mp = ip->i_mount; 403 struct xfs_mount *mp = ip->i_mount;
403 xfs_fileoff_t last_fsb = XFS_B_TO_FSBT(mp, isize); 404 xfs_fileoff_t last_fsb = XFS_B_TO_FSBT(mp, isize);
@@ -425,6 +426,7 @@ xfs_zero_last_block(
425 zero_len = mp->m_sb.sb_blocksize - zero_offset; 426 zero_len = mp->m_sb.sb_blocksize - zero_offset;
426 if (isize + zero_len > offset) 427 if (isize + zero_len > offset)
427 zero_len = offset - isize; 428 zero_len = offset - isize;
429 *did_zeroing = true;
428 return xfs_iozero(ip, isize, zero_len); 430 return xfs_iozero(ip, isize, zero_len);
429} 431}
430 432
@@ -443,7 +445,8 @@ int /* error (positive) */
443xfs_zero_eof( 445xfs_zero_eof(
444 struct xfs_inode *ip, 446 struct xfs_inode *ip,
445 xfs_off_t offset, /* starting I/O offset */ 447 xfs_off_t offset, /* starting I/O offset */
446 xfs_fsize_t isize) /* current inode size */ 448 xfs_fsize_t isize, /* current inode size */
449 bool *did_zeroing)
447{ 450{
448 struct xfs_mount *mp = ip->i_mount; 451 struct xfs_mount *mp = ip->i_mount;
449 xfs_fileoff_t start_zero_fsb; 452 xfs_fileoff_t start_zero_fsb;
@@ -465,7 +468,7 @@ xfs_zero_eof(
465 * We only zero a part of that block so it is handled specially. 468 * We only zero a part of that block so it is handled specially.
466 */ 469 */
467 if (XFS_B_FSB_OFFSET(mp, isize) != 0) { 470 if (XFS_B_FSB_OFFSET(mp, isize) != 0) {
468 error = xfs_zero_last_block(ip, offset, isize); 471 error = xfs_zero_last_block(ip, offset, isize, did_zeroing);
469 if (error) 472 if (error)
470 return error; 473 return error;
471 } 474 }
@@ -525,6 +528,7 @@ xfs_zero_eof(
525 if (error) 528 if (error)
526 return error; 529 return error;
527 530
531 *did_zeroing = true;
528 start_zero_fsb = imap.br_startoff + imap.br_blockcount; 532 start_zero_fsb = imap.br_startoff + imap.br_blockcount;
529 ASSERT(start_zero_fsb <= (end_zero_fsb + 1)); 533 ASSERT(start_zero_fsb <= (end_zero_fsb + 1));
530 } 534 }
@@ -567,13 +571,15 @@ restart:
567 * having to redo all checks before. 571 * having to redo all checks before.
568 */ 572 */
569 if (*pos > i_size_read(inode)) { 573 if (*pos > i_size_read(inode)) {
574 bool zero = false;
575
570 if (*iolock == XFS_IOLOCK_SHARED) { 576 if (*iolock == XFS_IOLOCK_SHARED) {
571 xfs_rw_iunlock(ip, *iolock); 577 xfs_rw_iunlock(ip, *iolock);
572 *iolock = XFS_IOLOCK_EXCL; 578 *iolock = XFS_IOLOCK_EXCL;
573 xfs_rw_ilock(ip, *iolock); 579 xfs_rw_ilock(ip, *iolock);
574 goto restart; 580 goto restart;
575 } 581 }
576 error = xfs_zero_eof(ip, *pos, i_size_read(inode)); 582 error = xfs_zero_eof(ip, *pos, i_size_read(inode), &zero);
577 if (error) 583 if (error)
578 return error; 584 return error;
579 } 585 }
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index d0414f305967..698da0388f22 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -2871,6 +2871,10 @@ xfs_rename(
2871 * Handle RENAME_EXCHANGE flags 2871 * Handle RENAME_EXCHANGE flags
2872 */ 2872 */
2873 if (flags & RENAME_EXCHANGE) { 2873 if (flags & RENAME_EXCHANGE) {
2874 if (target_ip == NULL) {
2875 error = -EINVAL;
2876 goto error_return;
2877 }
2874 error = xfs_cross_rename(tp, src_dp, src_name, src_ip, 2878 error = xfs_cross_rename(tp, src_dp, src_name, src_ip,
2875 target_dp, target_name, target_ip, 2879 target_dp, target_name, target_ip,
2876 &free_list, &first_block, spaceres); 2880 &free_list, &first_block, spaceres);
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
index 8e82b41d2050..c73b63d51bc1 100644
--- a/fs/xfs/xfs_inode.h
+++ b/fs/xfs/xfs_inode.h
@@ -384,10 +384,11 @@ enum xfs_prealloc_flags {
384 XFS_PREALLOC_INVISIBLE = (1 << 4), 384 XFS_PREALLOC_INVISIBLE = (1 << 4),
385}; 385};
386 386
387int xfs_update_prealloc_flags(struct xfs_inode *, 387int xfs_update_prealloc_flags(struct xfs_inode *ip,
388 enum xfs_prealloc_flags); 388 enum xfs_prealloc_flags flags);
389int xfs_zero_eof(struct xfs_inode *, xfs_off_t, xfs_fsize_t); 389int xfs_zero_eof(struct xfs_inode *ip, xfs_off_t offset,
390int xfs_iozero(struct xfs_inode *, loff_t, size_t); 390 xfs_fsize_t isize, bool *did_zeroing);
391int xfs_iozero(struct xfs_inode *ip, loff_t pos, size_t count);
391 392
392 393
393/* from xfs_iops.c */ 394/* from xfs_iops.c */
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index d7782ae1af3c..3ccc28e8d3a0 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -756,6 +756,7 @@ xfs_setattr_size(
756 int error; 756 int error;
757 uint lock_flags = 0; 757 uint lock_flags = 0;
758 uint commit_flags = 0; 758 uint commit_flags = 0;
759 bool did_zeroing = false;
759 760
760 trace_xfs_setattr(ip); 761 trace_xfs_setattr(ip);
761 762
@@ -799,20 +800,16 @@ xfs_setattr_size(
799 return error; 800 return error;
800 801
801 /* 802 /*
802 * Now we can make the changes. Before we join the inode to the 803 * File data changes must be complete before we start the transaction to
803 * transaction, take care of the part of the truncation that must be 804 * modify the inode. This needs to be done before joining the inode to
804 * done without the inode lock. This needs to be done before joining 805 * the transaction because the inode cannot be unlocked once it is a
805 * the inode to the transaction, because the inode cannot be unlocked 806 * part of the transaction.
806 * once it is a part of the transaction. 807 *
808 * Start with zeroing any data block beyond EOF that we may expose on
809 * file extension.
807 */ 810 */
808 if (newsize > oldsize) { 811 if (newsize > oldsize) {
809 /* 812 error = xfs_zero_eof(ip, newsize, oldsize, &did_zeroing);
810 * Do the first part of growing a file: zero any data in the
811 * last block that is beyond the old EOF. We need to do this
812 * before the inode is joined to the transaction to modify
813 * i_size.
814 */
815 error = xfs_zero_eof(ip, newsize, oldsize);
816 if (error) 813 if (error)
817 return error; 814 return error;
818 } 815 }
@@ -822,23 +819,18 @@ xfs_setattr_size(
822 * any previous writes that are beyond the on disk EOF and the new 819 * any previous writes that are beyond the on disk EOF and the new
823 * EOF that have not been written out need to be written here. If we 820 * EOF that have not been written out need to be written here. If we
824 * do not write the data out, we expose ourselves to the null files 821 * do not write the data out, we expose ourselves to the null files
825 * problem. 822 * problem. Note that this includes any block zeroing we did above;
826 * 823 * otherwise those blocks may not be zeroed after a crash.
827 * Only flush from the on disk size to the smaller of the in memory
828 * file size or the new size as that's the range we really care about
829 * here and prevents waiting for other data not within the range we
830 * care about here.
831 */ 824 */
832 if (oldsize != ip->i_d.di_size && newsize > ip->i_d.di_size) { 825 if (newsize > ip->i_d.di_size &&
826 (oldsize != ip->i_d.di_size || did_zeroing)) {
833 error = filemap_write_and_wait_range(VFS_I(ip)->i_mapping, 827 error = filemap_write_and_wait_range(VFS_I(ip)->i_mapping,
834 ip->i_d.di_size, newsize); 828 ip->i_d.di_size, newsize);
835 if (error) 829 if (error)
836 return error; 830 return error;
837 } 831 }
838 832
839 /* 833 /* Now wait for all direct I/O to complete. */
840 * Wait for all direct I/O to complete.
841 */
842 inode_dio_wait(inode); 834 inode_dio_wait(inode);
843 835
844 /* 836 /*
diff --git a/fs/xfs/xfs_pnfs.c b/fs/xfs/xfs_pnfs.c
index 4b33ef112400..365dd57ea760 100644
--- a/fs/xfs/xfs_pnfs.c
+++ b/fs/xfs/xfs_pnfs.c
@@ -300,8 +300,10 @@ xfs_fs_commit_blocks(
300 300
301 tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE); 301 tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE);
302 error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 0, 0); 302 error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 0, 0);
303 if (error) 303 if (error) {
304 xfs_trans_cancel(tp, 0);
304 goto out_drop_iolock; 305 goto out_drop_iolock;
306 }
305 307
306 xfs_ilock(ip, XFS_ILOCK_EXCL); 308 xfs_ilock(ip, XFS_ILOCK_EXCL);
307 xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); 309 xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
index c6b22e1e77ed..5538468c7f63 100644
--- a/fs/xfs/xfs_qm.c
+++ b/fs/xfs/xfs_qm.c
@@ -841,6 +841,11 @@ xfs_qm_reset_dqcounts(
841 */ 841 */
842 xfs_dqcheck(mp, ddq, id+j, type, XFS_QMOPT_DQREPAIR, 842 xfs_dqcheck(mp, ddq, id+j, type, XFS_QMOPT_DQREPAIR,
843 "xfs_quotacheck"); 843 "xfs_quotacheck");
844 /*
845 * Reset type in case we are reusing group quota file for
846 * project quotas or vice versa
847 */
848 ddq->d_flags = type;
844 ddq->d_bcount = 0; 849 ddq->d_bcount = 0;
845 ddq->d_icount = 0; 850 ddq->d_icount = 0;
846 ddq->d_rtbcount = 0; 851 ddq->d_rtbcount = 0;