Skip to content

Commit

Permalink
Merge tag 'xfs-for-linus-4.0-rc2' of git://git.kernel.org/pub/scm/lin…
Browse files Browse the repository at this point in the history
…ux/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
  • Loading branch information
Linus Torvalds committed Feb 28, 2015
2 parents e973894 + 83d5f01 commit 2aaeb78
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 31 deletions.
14 changes: 10 additions & 4 deletions fs/xfs/xfs_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,8 @@ STATIC int /* error (positive) */
xfs_zero_last_block(
struct xfs_inode *ip,
xfs_fsize_t offset,
xfs_fsize_t isize)
xfs_fsize_t isize,
bool *did_zeroing)
{
struct xfs_mount *mp = ip->i_mount;
xfs_fileoff_t last_fsb = XFS_B_TO_FSBT(mp, isize);
Expand Down Expand Up @@ -425,6 +426,7 @@ xfs_zero_last_block(
zero_len = mp->m_sb.sb_blocksize - zero_offset;
if (isize + zero_len > offset)
zero_len = offset - isize;
*did_zeroing = true;
return xfs_iozero(ip, isize, zero_len);
}

Expand All @@ -443,7 +445,8 @@ int /* error (positive) */
xfs_zero_eof(
struct xfs_inode *ip,
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;
xfs_fileoff_t start_zero_fsb;
Expand All @@ -465,7 +468,7 @@ xfs_zero_eof(
* We only zero a part of that block so it is handled specially.
*/
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)
return error;
}
Expand Down Expand Up @@ -525,6 +528,7 @@ xfs_zero_eof(
if (error)
return error;

*did_zeroing = true;
start_zero_fsb = imap.br_startoff + imap.br_blockcount;
ASSERT(start_zero_fsb <= (end_zero_fsb + 1));
}
Expand Down Expand Up @@ -567,13 +571,15 @@ xfs_file_aio_write_checks(
* having to redo all checks before.
*/
if (*pos > i_size_read(inode)) {
bool zero = false;

if (*iolock == XFS_IOLOCK_SHARED) {
xfs_rw_iunlock(ip, *iolock);
*iolock = XFS_IOLOCK_EXCL;
xfs_rw_ilock(ip, *iolock);
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)
return error;
}
Expand Down
4 changes: 4 additions & 0 deletions fs/xfs/xfs_inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -2867,6 +2867,10 @@ xfs_rename(
* Handle RENAME_EXCHANGE flags
*/
if (flags & RENAME_EXCHANGE) {
if (target_ip == NULL) {
error = -EINVAL;
goto error_return;
}
error = xfs_cross_rename(tp, src_dp, src_name, src_ip,
target_dp, target_name, target_ip,
&free_list, &first_block, spaceres);
Expand Down
9 changes: 5 additions & 4 deletions fs/xfs/xfs_inode.h
Original file line number Diff line number Diff line change
Expand Up @@ -384,10 +384,11 @@ enum xfs_prealloc_flags {
XFS_PREALLOC_INVISIBLE = (1 << 4),
};

int xfs_update_prealloc_flags(struct xfs_inode *,
enum xfs_prealloc_flags);
int xfs_zero_eof(struct xfs_inode *, xfs_off_t, xfs_fsize_t);
int xfs_iozero(struct xfs_inode *, loff_t, size_t);
int xfs_update_prealloc_flags(struct xfs_inode *ip,
enum xfs_prealloc_flags flags);
int xfs_zero_eof(struct xfs_inode *ip, xfs_off_t offset,
xfs_fsize_t isize, bool *did_zeroing);
int xfs_iozero(struct xfs_inode *ip, loff_t pos, size_t count);


#define IHOLD(ip) \
Expand Down
36 changes: 14 additions & 22 deletions fs/xfs/xfs_iops.c
Original file line number Diff line number Diff line change
Expand Up @@ -751,6 +751,7 @@ xfs_setattr_size(
int error;
uint lock_flags = 0;
uint commit_flags = 0;
bool did_zeroing = false;

trace_xfs_setattr(ip);

Expand Down Expand Up @@ -794,20 +795,16 @@ xfs_setattr_size(
return error;

/*
* Now we can make the changes. Before we join the inode to the
* transaction, take care of the part of the truncation that must be
* done without the inode lock. This needs to be done before joining
* the inode to the transaction, because the inode cannot be unlocked
* once it is a part of the transaction.
* File data changes must be complete before we start the transaction to
* modify the inode. This needs to be done before joining the inode to
* the transaction because the inode cannot be unlocked 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) {
/*
* 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);
error = xfs_zero_eof(ip, newsize, oldsize, &did_zeroing);
if (error)
return error;
}
Expand All @@ -817,23 +814,18 @@ xfs_setattr_size(
* 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
* do not write the data out, we expose ourselves to the null files
* problem.
*
* 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.
* problem. Note that this includes any block zeroing we did above;
* otherwise those blocks may not be zeroed after a crash.
*/
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,
ip->i_d.di_size, newsize);
if (error)
return error;
}

/*
* Wait for all direct I/O to complete.
*/
/* Now wait for all direct I/O to complete. */
inode_dio_wait(inode);

/*
Expand Down
4 changes: 3 additions & 1 deletion fs/xfs/xfs_pnfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -300,8 +300,10 @@ xfs_fs_commit_blocks(

tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE);
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;
}

xfs_ilock(ip, XFS_ILOCK_EXCL);
xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
Expand Down
5 changes: 5 additions & 0 deletions fs/xfs/xfs_qm.c
Original file line number Diff line number Diff line change
Expand Up @@ -836,6 +836,11 @@ xfs_qm_reset_dqcounts(
*/
xfs_dqcheck(mp, ddq, id+j, type, XFS_QMOPT_DQREPAIR,
"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_icount = 0;
ddq->d_rtbcount = 0;
Expand Down

0 comments on commit 2aaeb78

Please sign in to comment.