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:
Christoph Hellwig
2010-06-14 05:17:31 -04:00
committed by Al Viro
parent 2f246fd0f1
commit fa9b227e90
4 changed files with 56 additions and 42 deletions

View File

@ -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,