xfs: clean up unwritten buffers on write failure
The xfs_vm_write_failed() handler is currently responsible for cleaning up any delalloc blocks over the range of a failed write beyond EOF. Failure to do so results in warning messages and other inconsistencies between buffer and extent state. The ->releasepage() handler currently warns in the event of a page being released with either unwritten or delalloc buffers, as neither is ever expected by the time a page is released. As has been reproduced by generic/083 on a -bsize=1k fs, it is currently possible to trigger the ->releasepage() warning for a page with unwritten buffers when a filesystem is near ENOSPC. This is reproduced by the following sequence: $ mkfs.xfs -f -b size=1k -d size=100m <dev> $ mount <dev> /mnt/ $ $ xfs_io -fc "falloc -k 0 1k" /mnt/file $ dd if=/dev/zero of=/mnt/enospc conv=notrunc oflag=append $ $ xfs_io -c "pwrite 512 1k" /mnt/file $ xfs_io -d -c "pwrite 16k 1k" /mnt/file The first pwrite command attempts a block unaligned write across an unwritten block and a hole. The delalloc for the hole fails with ENOSPC and the subsequent error handling does not clean up the unwritten buffer that was instantiated during the first ->get_block() call. The second pwrite triggers a warning as part of the inode mapping invalidation that occurs prior to direct I/O. The releasepage() handler detects the unwritten buffer at this time, warns and prevents the release of the page. To deal with this problem, update xfs_vm_write_failed() to clean up unwritten as well as delalloc buffers that are beyond EOF and within the range of the failed write. Signed-off-by: Brian Foster <bfoster@redhat.com> Reviewed-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Dave Chinner <david@fromorbit.com>
This commit is contained in:
parent
244efeafb6
commit
60630fe66e
|
@ -1783,14 +1783,22 @@ xfs_vm_write_failed(
|
|||
if (block_start >= to)
|
||||
break;
|
||||
|
||||
if (!buffer_delay(bh))
|
||||
/*
|
||||
* Process delalloc and unwritten buffers beyond EOF. We can
|
||||
* encounter unwritten buffers in the event that a file has
|
||||
* post-EOF unwritten extents and an extending write happens to
|
||||
* fail (e.g., an unaligned write that also involves a delalloc
|
||||
* to the same page).
|
||||
*/
|
||||
if (!buffer_delay(bh) && !buffer_unwritten(bh))
|
||||
continue;
|
||||
|
||||
if (!buffer_new(bh) && block_offset < i_size_read(inode))
|
||||
continue;
|
||||
|
||||
xfs_vm_kill_delalloc_range(inode, block_offset,
|
||||
block_offset + bh->b_size);
|
||||
if (buffer_delay(bh))
|
||||
xfs_vm_kill_delalloc_range(inode, block_offset,
|
||||
block_offset + bh->b_size);
|
||||
|
||||
/*
|
||||
* This buffer does not contain data anymore. make sure anyone
|
||||
|
@ -1801,6 +1809,7 @@ xfs_vm_write_failed(
|
|||
clear_buffer_mapped(bh);
|
||||
clear_buffer_new(bh);
|
||||
clear_buffer_dirty(bh);
|
||||
clear_buffer_unwritten(bh);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue