xfs: new truncate sequence
Convert XFS to the new truncate sequence. We still can have errors after updating the file size in xfs_setattr, but these are real I/O errors and lead to a transaction abort and filesystem shutdown, so they are not an issue. Errors from ->write_begin and write_end can now be handled correctly because we can actually get rid of the delalloc extents while previous the buffer state was stipped in block_invalidatepage. There is still no error handling for ->direct_IO, because doing so will need some major restructuring given that we only have the iolock shared and do not hold i_mutex at all. Fortunately leaving the normally allocated blocks behind there is not a major issue and this will get cleaned up by xfs_free_eofblock later. Note: the patch is against Al's vfs.git tree as that contains the nessecary preparations. I'd prefer to get it applied there so that we can get some testing in linux-next. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
committed by
Al Viro
parent
2f246fd0f1
commit
fa9b227e90
@ -1494,6 +1494,22 @@ xfs_vm_direct_IO(
|
||||
return ret;
|
||||
}
|
||||
|
||||
STATIC void
|
||||
xfs_vm_write_failed(
|
||||
struct address_space *mapping,
|
||||
loff_t to)
|
||||
{
|
||||
struct inode *inode = mapping->host;
|
||||
|
||||
if (to > inode->i_size) {
|
||||
struct iattr ia = {
|
||||
.ia_valid = ATTR_SIZE | ATTR_FORCE,
|
||||
.ia_size = inode->i_size,
|
||||
};
|
||||
xfs_setattr(XFS_I(inode), &ia, XFS_ATTR_NOLOCK);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC int
|
||||
xfs_vm_write_begin(
|
||||
struct file *file,
|
||||
@ -1508,12 +1524,26 @@ xfs_vm_write_begin(
|
||||
|
||||
ret = block_write_begin(mapping, pos, len, flags | AOP_FLAG_NOFS,
|
||||
pagep, xfs_get_blocks);
|
||||
if (unlikely(ret)) {
|
||||
loff_t isize = mapping->host->i_size;
|
||||
if (pos + len > isize)
|
||||
vmtruncate(mapping->host, isize);
|
||||
}
|
||||
if (unlikely(ret))
|
||||
xfs_vm_write_failed(mapping, pos + len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
STATIC int
|
||||
xfs_vm_write_end(
|
||||
struct file *file,
|
||||
struct address_space *mapping,
|
||||
loff_t pos,
|
||||
unsigned len,
|
||||
unsigned copied,
|
||||
struct page *page,
|
||||
void *fsdata)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata);
|
||||
if (unlikely(ret < len))
|
||||
xfs_vm_write_failed(mapping, pos + len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1559,7 +1589,7 @@ const struct address_space_operations xfs_address_space_operations = {
|
||||
.releasepage = xfs_vm_releasepage,
|
||||
.invalidatepage = xfs_vm_invalidatepage,
|
||||
.write_begin = xfs_vm_write_begin,
|
||||
.write_end = generic_write_end,
|
||||
.write_end = xfs_vm_write_end,
|
||||
.bmap = xfs_vm_bmap,
|
||||
.direct_IO = xfs_vm_direct_IO,
|
||||
.migratepage = buffer_migrate_page,
|
||||
|
Reference in New Issue
Block a user