|
@@ -2315,17 +2315,33 @@ xfs_change_file_space(
|
|
|
case XFS_IOC_ALLOCSP64:
|
|
|
case XFS_IOC_FREESP:
|
|
|
case XFS_IOC_FREESP64:
|
|
|
+ /*
|
|
|
+ * These operations actually do IO when extending the file, but
|
|
|
+ * the allocation is done seperately to the zeroing that is
|
|
|
+ * done. This set of operations need to be serialised against
|
|
|
+ * other IO operations, such as truncate and buffered IO. We
|
|
|
+ * need to take the IOLOCK here to serialise the allocation and
|
|
|
+ * zeroing IO to prevent other IOLOCK holders (e.g. getbmap,
|
|
|
+ * truncate, direct IO) from racing against the transient
|
|
|
+ * allocated but not written state we can have here.
|
|
|
+ */
|
|
|
+ xfs_ilock(ip, XFS_IOLOCK_EXCL);
|
|
|
if (startoffset > fsize) {
|
|
|
error = xfs_alloc_file_space(ip, fsize,
|
|
|
- startoffset - fsize, 0, attr_flags);
|
|
|
- if (error)
|
|
|
+ startoffset - fsize, 0,
|
|
|
+ attr_flags | XFS_ATTR_NOLOCK);
|
|
|
+ if (error) {
|
|
|
+ xfs_iunlock(ip, XFS_IOLOCK_EXCL);
|
|
|
break;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
iattr.ia_valid = ATTR_SIZE;
|
|
|
iattr.ia_size = startoffset;
|
|
|
|
|
|
- error = xfs_setattr_size(ip, &iattr, attr_flags);
|
|
|
+ error = xfs_setattr_size(ip, &iattr,
|
|
|
+ attr_flags | XFS_ATTR_NOLOCK);
|
|
|
+ xfs_iunlock(ip, XFS_IOLOCK_EXCL);
|
|
|
|
|
|
if (error)
|
|
|
return error;
|