aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@infradead.org>2010-06-14 05:17:31 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2010-08-09 16:47:42 -0400
commitfa9b227e9019ebaeeb06224ba531a490f91144b3 (patch)
treeff3644c6572d2b22db0d8b71f1a79ae0ad33d102
parent2f246fd0f126f3b3c23a4e6b7109350e83356bd6 (diff)
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>
-rw-r--r--fs/xfs/linux-2.6/xfs_aops.c42
-rw-r--r--fs/xfs/linux-2.6/xfs_iops.c16
-rw-r--r--fs/xfs/linux-2.6/xfs_linux.h2
-rw-r--r--fs/xfs/xfs_vnodeops.c38
4 files changed, 56 insertions, 42 deletions
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c
index bf7aad0d78b8..15412fe15c3a 100644
--- a/fs/xfs/linux-2.6/xfs_aops.c
+++ b/fs/xfs/linux-2.6/xfs_aops.c
@@ -1494,6 +1494,22 @@ xfs_vm_direct_IO(
1494 return ret; 1494 return ret;
1495} 1495}
1496 1496
1497STATIC void
1498xfs_vm_write_failed(
1499 struct address_space *mapping,
1500 loff_t to)
1501{
1502 struct inode *inode = mapping->host;
1503
1504 if (to > inode->i_size) {
1505 struct iattr ia = {
1506 .ia_valid = ATTR_SIZE | ATTR_FORCE,
1507 .ia_size = inode->i_size,
1508 };
1509 xfs_setattr(XFS_I(inode), &ia, XFS_ATTR_NOLOCK);
1510 }
1511}
1512
1497STATIC int 1513STATIC int
1498xfs_vm_write_begin( 1514xfs_vm_write_begin(
1499 struct file *file, 1515 struct file *file,
@@ -1508,12 +1524,26 @@ xfs_vm_write_begin(
1508 1524
1509 ret = block_write_begin(mapping, pos, len, flags | AOP_FLAG_NOFS, 1525 ret = block_write_begin(mapping, pos, len, flags | AOP_FLAG_NOFS,
1510 pagep, xfs_get_blocks); 1526 pagep, xfs_get_blocks);
1511 if (unlikely(ret)) { 1527 if (unlikely(ret))
1512 loff_t isize = mapping->host->i_size; 1528 xfs_vm_write_failed(mapping, pos + len);
1513 if (pos + len > isize) 1529 return ret;
1514 vmtruncate(mapping->host, isize); 1530}
1515 } 1531
1532STATIC int
1533xfs_vm_write_end(
1534 struct file *file,
1535 struct address_space *mapping,
1536 loff_t pos,
1537 unsigned len,
1538 unsigned copied,
1539 struct page *page,
1540 void *fsdata)
1541{
1542 int ret;
1516 1543
1544 ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata);
1545 if (unlikely(ret < len))
1546 xfs_vm_write_failed(mapping, pos + len);
1517 return ret; 1547 return ret;
1518} 1548}
1519 1549
@@ -1559,7 +1589,7 @@ const struct address_space_operations xfs_address_space_operations = {
1559 .releasepage = xfs_vm_releasepage, 1589 .releasepage = xfs_vm_releasepage,
1560 .invalidatepage = xfs_vm_invalidatepage, 1590 .invalidatepage = xfs_vm_invalidatepage,
1561 .write_begin = xfs_vm_write_begin, 1591 .write_begin = xfs_vm_write_begin,
1562 .write_end = generic_write_end, 1592 .write_end = xfs_vm_write_end,
1563 .bmap = xfs_vm_bmap, 1593 .bmap = xfs_vm_bmap,
1564 .direct_IO = xfs_vm_direct_IO, 1594 .direct_IO = xfs_vm_direct_IO,
1565 .migratepage = buffer_migrate_page, 1595 .migratepage = buffer_migrate_page,
diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c
index 536b81e63a3d..62dd349facee 100644
--- a/fs/xfs/linux-2.6/xfs_iops.c
+++ b/fs/xfs/linux-2.6/xfs_iops.c
@@ -540,21 +540,6 @@ xfs_vn_setattr(
540 return -xfs_setattr(XFS_I(dentry->d_inode), iattr, 0); 540 return -xfs_setattr(XFS_I(dentry->d_inode), iattr, 0);
541} 541}
542 542
543/*
544 * block_truncate_page can return an error, but we can't propagate it
545 * at all here. Leave a complaint + stack trace in the syslog because
546 * this could be bad. If it is bad, we need to propagate the error further.
547 */
548STATIC void
549xfs_vn_truncate(
550 struct inode *inode)
551{
552 int error;
553 error = block_truncate_page(inode->i_mapping, inode->i_size,
554 xfs_get_blocks);
555 WARN_ON(error);
556}
557
558STATIC long 543STATIC long
559xfs_vn_fallocate( 544xfs_vn_fallocate(
560 struct inode *inode, 545 struct inode *inode,
@@ -694,7 +679,6 @@ xfs_vn_fiemap(
694 679
695static const struct inode_operations xfs_inode_operations = { 680static const struct inode_operations xfs_inode_operations = {
696 .check_acl = xfs_check_acl, 681 .check_acl = xfs_check_acl,
697 .truncate = xfs_vn_truncate,
698 .getattr = xfs_vn_getattr, 682 .getattr = xfs_vn_getattr,
699 .setattr = xfs_vn_setattr, 683 .setattr = xfs_vn_setattr,
700 .setxattr = generic_setxattr, 684 .setxattr = generic_setxattr,
diff --git a/fs/xfs/linux-2.6/xfs_linux.h b/fs/xfs/linux-2.6/xfs_linux.h
index 998a9d7fb9c8..2fa0bd9ebc7f 100644
--- a/fs/xfs/linux-2.6/xfs_linux.h
+++ b/fs/xfs/linux-2.6/xfs_linux.h
@@ -156,8 +156,6 @@
156 */ 156 */
157#define xfs_sort(a,n,s,fn) sort(a,n,s,fn,NULL) 157#define xfs_sort(a,n,s,fn) sort(a,n,s,fn,NULL)
158#define xfs_stack_trace() dump_stack() 158#define xfs_stack_trace() dump_stack()
159#define xfs_itruncate_data(ip, off) \
160 (-vmtruncate(VFS_I(ip), (off)))
161 159
162 160
163/* Move the kernel do_div definition off to one side */ 161/* Move the kernel do_div definition off to one side */
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
index 3ac137dd531b..66d585c6917c 100644
--- a/fs/xfs/xfs_vnodeops.c
+++ b/fs/xfs/xfs_vnodeops.c
@@ -221,8 +221,11 @@ xfs_setattr(
221 * transaction to modify the i_size. 221 * transaction to modify the i_size.
222 */ 222 */
223 code = xfs_zero_eof(ip, iattr->ia_size, ip->i_size); 223 code = xfs_zero_eof(ip, iattr->ia_size, ip->i_size);
224 if (code)
225 goto error_return;
224 } 226 }
225 xfs_iunlock(ip, XFS_ILOCK_EXCL); 227 xfs_iunlock(ip, XFS_ILOCK_EXCL);
228 lock_flags &= ~XFS_ILOCK_EXCL;
226 229
227 /* 230 /*
228 * We are going to log the inode size change in this 231 * We are going to log the inode size change in this
@@ -236,36 +239,35 @@ xfs_setattr(
236 * really care about here and prevents waiting for other data 239 * really care about here and prevents waiting for other data
237 * not within the range we care about here. 240 * not within the range we care about here.
238 */ 241 */
239 if (!code && 242 if (ip->i_size != ip->i_d.di_size &&
240 ip->i_size != ip->i_d.di_size &&
241 iattr->ia_size > ip->i_d.di_size) { 243 iattr->ia_size > ip->i_d.di_size) {
242 code = xfs_flush_pages(ip, 244 code = xfs_flush_pages(ip,
243 ip->i_d.di_size, iattr->ia_size, 245 ip->i_d.di_size, iattr->ia_size,
244 XBF_ASYNC, FI_NONE); 246 XBF_ASYNC, FI_NONE);
247 if (code)
248 goto error_return;
245 } 249 }
246 250
247 /* wait for all I/O to complete */ 251 /* wait for all I/O to complete */
248 xfs_ioend_wait(ip); 252 xfs_ioend_wait(ip);
249 253
250 if (!code) 254 code = -block_truncate_page(inode->i_mapping, iattr->ia_size,
251 code = xfs_itruncate_data(ip, iattr->ia_size); 255 xfs_get_blocks);
252 if (code) { 256 if (code)
253 ASSERT(tp == NULL);
254 lock_flags &= ~XFS_ILOCK_EXCL;
255 ASSERT(lock_flags == XFS_IOLOCK_EXCL || !need_iolock);
256 goto error_return; 257 goto error_return;
257 } 258
258 tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_SIZE); 259 tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_SIZE);
259 if ((code = xfs_trans_reserve(tp, 0, 260 code = xfs_trans_reserve(tp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0,
260 XFS_ITRUNCATE_LOG_RES(mp), 0, 261 XFS_TRANS_PERM_LOG_RES,
261 XFS_TRANS_PERM_LOG_RES, 262 XFS_ITRUNCATE_LOG_COUNT);
262 XFS_ITRUNCATE_LOG_COUNT))) { 263 if (code)
263 xfs_trans_cancel(tp, 0); 264 goto error_return;
264 if (need_iolock) 265
265 xfs_iunlock(ip, XFS_IOLOCK_EXCL); 266 truncate_setsize(inode, iattr->ia_size);
266 return code; 267
267 }
268 commit_flags = XFS_TRANS_RELEASE_LOG_RES; 268 commit_flags = XFS_TRANS_RELEASE_LOG_RES;
269 lock_flags |= XFS_ILOCK_EXCL;
270
269 xfs_ilock(ip, XFS_ILOCK_EXCL); 271 xfs_ilock(ip, XFS_ILOCK_EXCL);
270 272
271 xfs_trans_ijoin(tp, ip); 273 xfs_trans_ijoin(tp, ip);