Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2aaeb784 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
parents e9738946 83d5f018
Loading
Loading
Loading
Loading
+10 −4
Original line number Diff line number Diff line
@@ -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);
@@ -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);
}

@@ -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;
@@ -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;
	}
@@ -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));
	}
@@ -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;
	}
+4 −0
Original line number Diff line number Diff line
@@ -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);
+5 −4
Original line number Diff line number Diff line
@@ -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) \
+14 −22
Original line number Diff line number Diff line
@@ -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);

@@ -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;
	}
@@ -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);

	/*
+3 −1
Original line number Diff line number Diff line
@@ -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);
Loading