xfs: fixes for v4.0-rc2

This update contains:
 o ensure quota type is reset in on-disk dquots
 o fix missing partial EOF block data flush on truncate extension
 o fix transaction leak in error handling for new pnfs block layout
   support
 o add missing target_ip check to RENAME_EXCHANGE
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.12 (GNU/Linux)
 
 iQIcBAABAgAGBQJU78w2AAoJEK3oKUf0dfod68IQALzcN8py4QxvmxVXf8F7+ymo
 PrUc/ZiP8EOS+q2wk4V0RgyoCAFA02pFjCEpWVm3PBdyfsd9DC12w7VYBlbDMO8f
 wApPots48NbqYVQA2+YLzC2+dgHwxLWzzJFyS6jDb/xtrVarHZtbhJU6hvl3a1gH
 8RwEW+mplMmIN8Qh7vxJ2/2K+97lfS2AW0jAnnOZKCsx98XWvSgeCk+3VszwZWjD
 obQn2WrvlfUSSERs0z2sygx5GxR/3Wnm5LrzpiX/+gH6LdPED53o6K/tKf5ncbmF
 maXkYUMxvTs3tOO9ZPohtL4Zc9JarPu2U6sKmMxULOaRgZLwmk6W2cyoCbdW2du5
 0ardLB89fUvGCJGMXojVtxZ6BX8IEoyhSDUX1qGF9/HFr0Rz5zIkeeqAWkj89+Cj
 VYvR/AmLBYwdaUPL+aHmG3P6B07u42n4650UQIVYw29rGEpxYOaBr7BAEYgyWFoM
 Omizf05rsz5aAxXCTjfUl+s9VsO6H0lNCjRyNs+QRIqkGf9rgxJGIAJuoh+bNNOm
 +WcId+5BPInuAy1YFP9Z02fe1NqIkSihTbL6daIlGIYralauXG+wyrsm9DaMsNSq
 VPul6HFMUwv2g5ECjvhiGZcvElOcBKcVQEUBJP3izFczP9o2i5NKcIOVFW/AxwTZ
 NW1qOYsLAQmD/hYpx1p2
 =kTai
 -----END PGP SIGNATURE-----

Merge tag 'xfs-for-linus-4.0-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/dgc/linux-xfs

Pull xfs fixes from Dave Chinner:
 "These are fixes for regressions/bugs introduced in the 4.0 merge cycle
  and problems discovered during the merge window that need to be pushed
  back to stable kernels ASAP.

  This contains:
   - ensure quota type is reset in on-disk dquots
   - fix missing partial EOF block data flush on truncate extension
   - fix transaction leak in error handling for new pnfs block layout
     support
   - add missing target_ip check to RENAME_EXCHANGE"

* tag 'xfs-for-linus-4.0-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/dgc/linux-xfs:
  xfs: cancel failed transaction in xfs_fs_commit_blocks()
  xfs: Ensure we have target_ip for RENAME_EXCHANGE
  xfs: ensure truncate forces zeroed blocks to disk
  xfs: Fix quota type in quota structures when reusing quota file
This commit is contained in:
Linus Torvalds 2015-02-28 10:06:33 -08:00
commit 2aaeb784bf
6 changed files with 41 additions and 31 deletions

View File

@ -397,7 +397,8 @@ STATIC int /* error (positive) */
xfs_zero_last_block( xfs_zero_last_block(
struct xfs_inode *ip, struct xfs_inode *ip,
xfs_fsize_t offset, xfs_fsize_t offset,
xfs_fsize_t isize) xfs_fsize_t isize,
bool *did_zeroing)
{ {
struct xfs_mount *mp = ip->i_mount; struct xfs_mount *mp = ip->i_mount;
xfs_fileoff_t last_fsb = XFS_B_TO_FSBT(mp, isize); xfs_fileoff_t last_fsb = XFS_B_TO_FSBT(mp, isize);
@ -425,6 +426,7 @@ xfs_zero_last_block(
zero_len = mp->m_sb.sb_blocksize - zero_offset; zero_len = mp->m_sb.sb_blocksize - zero_offset;
if (isize + zero_len > offset) if (isize + zero_len > offset)
zero_len = offset - isize; zero_len = offset - isize;
*did_zeroing = true;
return xfs_iozero(ip, isize, zero_len); return xfs_iozero(ip, isize, zero_len);
} }
@ -443,7 +445,8 @@ int /* error (positive) */
xfs_zero_eof( xfs_zero_eof(
struct xfs_inode *ip, struct xfs_inode *ip,
xfs_off_t offset, /* starting I/O offset */ xfs_off_t offset, /* starting I/O offset */
xfs_fsize_t isize) /* current inode size */ xfs_fsize_t isize, /* current inode size */
bool *did_zeroing)
{ {
struct xfs_mount *mp = ip->i_mount; struct xfs_mount *mp = ip->i_mount;
xfs_fileoff_t start_zero_fsb; xfs_fileoff_t start_zero_fsb;
@ -465,7 +468,7 @@ xfs_zero_eof(
* We only zero a part of that block so it is handled specially. * We only zero a part of that block so it is handled specially.
*/ */
if (XFS_B_FSB_OFFSET(mp, isize) != 0) { if (XFS_B_FSB_OFFSET(mp, isize) != 0) {
error = xfs_zero_last_block(ip, offset, isize); error = xfs_zero_last_block(ip, offset, isize, did_zeroing);
if (error) if (error)
return error; return error;
} }
@ -525,6 +528,7 @@ xfs_zero_eof(
if (error) if (error)
return error; return error;
*did_zeroing = true;
start_zero_fsb = imap.br_startoff + imap.br_blockcount; start_zero_fsb = imap.br_startoff + imap.br_blockcount;
ASSERT(start_zero_fsb <= (end_zero_fsb + 1)); ASSERT(start_zero_fsb <= (end_zero_fsb + 1));
} }
@ -567,13 +571,15 @@ restart:
* having to redo all checks before. * having to redo all checks before.
*/ */
if (*pos > i_size_read(inode)) { if (*pos > i_size_read(inode)) {
bool zero = false;
if (*iolock == XFS_IOLOCK_SHARED) { if (*iolock == XFS_IOLOCK_SHARED) {
xfs_rw_iunlock(ip, *iolock); xfs_rw_iunlock(ip, *iolock);
*iolock = XFS_IOLOCK_EXCL; *iolock = XFS_IOLOCK_EXCL;
xfs_rw_ilock(ip, *iolock); xfs_rw_ilock(ip, *iolock);
goto restart; goto restart;
} }
error = xfs_zero_eof(ip, *pos, i_size_read(inode)); error = xfs_zero_eof(ip, *pos, i_size_read(inode), &zero);
if (error) if (error)
return error; return error;
} }

View File

@ -2867,6 +2867,10 @@ xfs_rename(
* Handle RENAME_EXCHANGE flags * Handle RENAME_EXCHANGE flags
*/ */
if (flags & RENAME_EXCHANGE) { if (flags & RENAME_EXCHANGE) {
if (target_ip == NULL) {
error = -EINVAL;
goto error_return;
}
error = xfs_cross_rename(tp, src_dp, src_name, src_ip, error = xfs_cross_rename(tp, src_dp, src_name, src_ip,
target_dp, target_name, target_ip, target_dp, target_name, target_ip,
&free_list, &first_block, spaceres); &free_list, &first_block, spaceres);

View File

@ -384,10 +384,11 @@ enum xfs_prealloc_flags {
XFS_PREALLOC_INVISIBLE = (1 << 4), XFS_PREALLOC_INVISIBLE = (1 << 4),
}; };
int xfs_update_prealloc_flags(struct xfs_inode *, int xfs_update_prealloc_flags(struct xfs_inode *ip,
enum xfs_prealloc_flags); enum xfs_prealloc_flags flags);
int xfs_zero_eof(struct xfs_inode *, xfs_off_t, xfs_fsize_t); int xfs_zero_eof(struct xfs_inode *ip, xfs_off_t offset,
int xfs_iozero(struct xfs_inode *, loff_t, size_t); xfs_fsize_t isize, bool *did_zeroing);
int xfs_iozero(struct xfs_inode *ip, loff_t pos, size_t count);
#define IHOLD(ip) \ #define IHOLD(ip) \

View File

@ -751,6 +751,7 @@ xfs_setattr_size(
int error; int error;
uint lock_flags = 0; uint lock_flags = 0;
uint commit_flags = 0; uint commit_flags = 0;
bool did_zeroing = false;
trace_xfs_setattr(ip); trace_xfs_setattr(ip);
@ -794,20 +795,16 @@ xfs_setattr_size(
return error; return error;
/* /*
* Now we can make the changes. Before we join the inode to the * File data changes must be complete before we start the transaction to
* transaction, take care of the part of the truncation that must be * modify the inode. This needs to be done before joining the inode to
* done without the inode lock. This needs to be done before joining * the transaction because the inode cannot be unlocked once it is a
* the inode to the transaction, because the inode cannot be unlocked * part of the transaction.
* once it is a part of the transaction. *
* Start with zeroing any data block beyond EOF that we may expose on
* file extension.
*/ */
if (newsize > oldsize) { if (newsize > oldsize) {
/* error = xfs_zero_eof(ip, newsize, oldsize, &did_zeroing);
* Do the first part of growing a file: zero any data in the
* last block that is beyond the old EOF. We need to do this
* before the inode is joined to the transaction to modify
* i_size.
*/
error = xfs_zero_eof(ip, newsize, oldsize);
if (error) if (error)
return error; return error;
} }
@ -817,23 +814,18 @@ xfs_setattr_size(
* any previous writes that are beyond the on disk EOF and the new * any previous writes that are beyond the on disk EOF and the new
* EOF that have not been written out need to be written here. If we * EOF that have not been written out need to be written here. If we
* do not write the data out, we expose ourselves to the null files * do not write the data out, we expose ourselves to the null files
* problem. * problem. Note that this includes any block zeroing we did above;
* * otherwise those blocks may not be zeroed after a crash.
* Only flush from the on disk size to the smaller of the in memory
* file size or the new size as that's the range we really care about
* here and prevents waiting for other data not within the range we
* care about here.
*/ */
if (oldsize != ip->i_d.di_size && newsize > ip->i_d.di_size) { if (newsize > ip->i_d.di_size &&
(oldsize != ip->i_d.di_size || did_zeroing)) {
error = filemap_write_and_wait_range(VFS_I(ip)->i_mapping, error = filemap_write_and_wait_range(VFS_I(ip)->i_mapping,
ip->i_d.di_size, newsize); ip->i_d.di_size, newsize);
if (error) if (error)
return error; return error;
} }
/* /* Now wait for all direct I/O to complete. */
* Wait for all direct I/O to complete.
*/
inode_dio_wait(inode); inode_dio_wait(inode);
/* /*

View File

@ -300,8 +300,10 @@ xfs_fs_commit_blocks(
tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE); tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE);
error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 0, 0); error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 0, 0);
if (error) if (error) {
xfs_trans_cancel(tp, 0);
goto out_drop_iolock; goto out_drop_iolock;
}
xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_ilock(ip, XFS_ILOCK_EXCL);
xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);

View File

@ -836,6 +836,11 @@ xfs_qm_reset_dqcounts(
*/ */
xfs_dqcheck(mp, ddq, id+j, type, XFS_QMOPT_DQREPAIR, xfs_dqcheck(mp, ddq, id+j, type, XFS_QMOPT_DQREPAIR,
"xfs_quotacheck"); "xfs_quotacheck");
/*
* Reset type in case we are reusing group quota file for
* project quotas or vice versa
*/
ddq->d_flags = type;
ddq->d_bcount = 0; ddq->d_bcount = 0;
ddq->d_icount = 0; ddq->d_icount = 0;
ddq->d_rtbcount = 0; ddq->d_rtbcount = 0;