aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/xfs/xfs_vnodeops.c22
1 files changed, 19 insertions, 3 deletions
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
index 6c187450f1c8..9b6c94e7546e 100644
--- a/fs/xfs/xfs_vnodeops.c
+++ b/fs/xfs/xfs_vnodeops.c
@@ -2315,17 +2315,33 @@ xfs_change_file_space(
2315 case XFS_IOC_ALLOCSP64: 2315 case XFS_IOC_ALLOCSP64:
2316 case XFS_IOC_FREESP: 2316 case XFS_IOC_FREESP:
2317 case XFS_IOC_FREESP64: 2317 case XFS_IOC_FREESP64:
2318 /*
2319 * These operations actually do IO when extending the file, but
2320 * the allocation is done seperately to the zeroing that is
2321 * done. This set of operations need to be serialised against
2322 * other IO operations, such as truncate and buffered IO. We
2323 * need to take the IOLOCK here to serialise the allocation and
2324 * zeroing IO to prevent other IOLOCK holders (e.g. getbmap,
2325 * truncate, direct IO) from racing against the transient
2326 * allocated but not written state we can have here.
2327 */
2328 xfs_ilock(ip, XFS_IOLOCK_EXCL);
2318 if (startoffset > fsize) { 2329 if (startoffset > fsize) {
2319 error = xfs_alloc_file_space(ip, fsize, 2330 error = xfs_alloc_file_space(ip, fsize,
2320 startoffset - fsize, 0, attr_flags); 2331 startoffset - fsize, 0,
2321 if (error) 2332 attr_flags | XFS_ATTR_NOLOCK);
2333 if (error) {
2334 xfs_iunlock(ip, XFS_IOLOCK_EXCL);
2322 break; 2335 break;
2336 }
2323 } 2337 }
2324 2338
2325 iattr.ia_valid = ATTR_SIZE; 2339 iattr.ia_valid = ATTR_SIZE;
2326 iattr.ia_size = startoffset; 2340 iattr.ia_size = startoffset;
2327 2341
2328 error = xfs_setattr_size(ip, &iattr, attr_flags); 2342 error = xfs_setattr_size(ip, &iattr,
2343 attr_flags | XFS_ATTR_NOLOCK);
2344 xfs_iunlock(ip, XFS_IOLOCK_EXCL);
2329 2345
2330 if (error) 2346 if (error)
2331 return error; 2347 return error;