aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/ext4/inode.c24
1 files changed, 22 insertions, 2 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 17ed0d244dbb..8d215881172f 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -1459,7 +1459,7 @@ static int ext4_write_begin(struct file *file, struct address_space *mapping,
1459 struct page **pagep, void **fsdata) 1459 struct page **pagep, void **fsdata)
1460{ 1460{
1461 struct inode *inode = mapping->host; 1461 struct inode *inode = mapping->host;
1462 int ret, needed_blocks = ext4_writepage_trans_blocks(inode); 1462 int ret, needed_blocks;
1463 handle_t *handle; 1463 handle_t *handle;
1464 int retries = 0; 1464 int retries = 0;
1465 struct page *page; 1465 struct page *page;
@@ -1470,6 +1470,11 @@ static int ext4_write_begin(struct file *file, struct address_space *mapping,
1470 "dev %s ino %lu pos %llu len %u flags %u", 1470 "dev %s ino %lu pos %llu len %u flags %u",
1471 inode->i_sb->s_id, inode->i_ino, 1471 inode->i_sb->s_id, inode->i_ino,
1472 (unsigned long long) pos, len, flags); 1472 (unsigned long long) pos, len, flags);
1473 /*
1474 * Reserve one block more for addition to orphan list in case
1475 * we allocate blocks but write fails for some reason
1476 */
1477 needed_blocks = ext4_writepage_trans_blocks(inode) + 1;
1473 index = pos >> PAGE_CACHE_SHIFT; 1478 index = pos >> PAGE_CACHE_SHIFT;
1474 from = pos & (PAGE_CACHE_SIZE - 1); 1479 from = pos & (PAGE_CACHE_SIZE - 1);
1475 to = from + len; 1480 to = from + len;
@@ -1503,15 +1508,30 @@ retry:
1503 1508
1504 if (ret) { 1509 if (ret) {
1505 unlock_page(page); 1510 unlock_page(page);
1506 ext4_journal_stop(handle);
1507 page_cache_release(page); 1511 page_cache_release(page);
1508 /* 1512 /*
1509 * block_write_begin may have instantiated a few blocks 1513 * block_write_begin may have instantiated a few blocks
1510 * outside i_size. Trim these off again. Don't need 1514 * outside i_size. Trim these off again. Don't need
1511 * i_size_read because we hold i_mutex. 1515 * i_size_read because we hold i_mutex.
1516 *
1517 * Add inode to orphan list in case we crash before
1518 * truncate finishes
1512 */ 1519 */
1513 if (pos + len > inode->i_size) 1520 if (pos + len > inode->i_size)
1521 ext4_orphan_add(handle, inode);
1522
1523 ext4_journal_stop(handle);
1524 if (pos + len > inode->i_size) {
1514 vmtruncate(inode, inode->i_size); 1525 vmtruncate(inode, inode->i_size);
1526 /*
1527 * If vmtruncate failed early the inode might
1528 * still be on the orphan list; we need to
1529 * make sure the inode is removed from the
1530 * orphan list in that case.
1531 */
1532 if (inode->i_nlink)
1533 ext4_orphan_del(NULL, inode);
1534 }
1515 } 1535 }
1516 1536
1517 if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) 1537 if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))