aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2012-04-23 01:58:57 -0400
committerBen Myers <bpm@sgi.com>2012-05-14 17:20:53 -0400
commitbc4010ecb8f4d4316e1a63a879a2715e49d113ad (patch)
tree82d3f15ae571a2c46a9e2a2a44511db71a4fb732
parentaa5c158ec97bd4014f47a2bc0150fb6b20e6c48b (diff)
xfs: use iolock on XFS_IOC_ALLOCSP calls
fsstress has a particular effective way of stopping debug XFS kernels. We keep seeing assert failures due finding delayed allocation extents where there should be none. This shows up when extracting extent maps and we are holding all the locks we should be to prevent races, so this really makes no sense to see these errors. After checking that fsstress does not use mmap, it occurred to me that fsstress uses something that no sane application uses - the XFS_IOC_ALLOCSP ioctl interfaces for preallocation. These interfaces do allocation of blocks beyond EOF without using preallocation, and then call setattr to extend and zero the allocated blocks. THe problem here is this is a buffered write, and hence the allocation is a delayed allocation. Unlike the buffered IO path, the allocation and zeroing are not serialised using the IOLOCK. Hence the ALLOCSP operation can race with operations holding the iolock to prevent buffered IO operations from occurring. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Mark Tinguely <tinguely@sgi.com> Signed-off-by: Ben Myers <bpm@sgi.com>
-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;