Merge branch 'xfs-misc-fixes-1-for-3.16' into for-next
This commit is contained in:
@@ -829,22 +829,34 @@ xfs_setattr_size(
|
||||
*/
|
||||
inode_dio_wait(inode);
|
||||
|
||||
/*
|
||||
* Do all the page cache truncate work outside the transaction context
|
||||
* as the "lock" order is page lock->log space reservation. i.e.
|
||||
* locking pages inside the transaction can ABBA deadlock with
|
||||
* writeback. We have to do the VFS inode size update before we truncate
|
||||
* the pagecache, however, to avoid racing with page faults beyond the
|
||||
* new EOF they are not serialised against truncate operations except by
|
||||
* page locks and size updates.
|
||||
*
|
||||
* Hence we are in a situation where a truncate can fail with ENOMEM
|
||||
* from xfs_trans_reserve(), but having already truncated the in-memory
|
||||
* version of the file (i.e. made user visible changes). There's not
|
||||
* much we can do about this, except to hope that the caller sees ENOMEM
|
||||
* and retries the truncate operation.
|
||||
*/
|
||||
error = -block_truncate_page(inode->i_mapping, newsize, xfs_get_blocks);
|
||||
if (error)
|
||||
return error;
|
||||
truncate_setsize(inode, newsize);
|
||||
|
||||
tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_SIZE);
|
||||
error = xfs_trans_reserve(tp, &M_RES(mp)->tr_itruncate, 0, 0);
|
||||
if (error)
|
||||
goto out_trans_cancel;
|
||||
|
||||
truncate_setsize(inode, newsize);
|
||||
|
||||
commit_flags = XFS_TRANS_RELEASE_LOG_RES;
|
||||
lock_flags |= XFS_ILOCK_EXCL;
|
||||
|
||||
xfs_ilock(ip, XFS_ILOCK_EXCL);
|
||||
|
||||
xfs_trans_ijoin(tp, ip, 0);
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user