|
@@ -1701,19 +1701,32 @@ static int __ext4_journalled_writepage(struct page *page,
|
|
|
ext4_walk_page_buffers(handle, page_bufs, 0, len,
|
|
|
NULL, bget_one);
|
|
|
}
|
|
|
- /* As soon as we unlock the page, it can go away, but we have
|
|
|
- * references to buffers so we are safe */
|
|
|
+ /*
|
|
|
+ * We need to release the page lock before we start the
|
|
|
+ * journal, so grab a reference so the page won't disappear
|
|
|
+ * out from under us.
|
|
|
+ */
|
|
|
+ get_page(page);
|
|
|
unlock_page(page);
|
|
|
|
|
|
handle = ext4_journal_start(inode, EXT4_HT_WRITE_PAGE,
|
|
|
ext4_writepage_trans_blocks(inode));
|
|
|
if (IS_ERR(handle)) {
|
|
|
ret = PTR_ERR(handle);
|
|
|
- goto out;
|
|
|
+ put_page(page);
|
|
|
+ goto out_no_pagelock;
|
|
|
}
|
|
|
-
|
|
|
BUG_ON(!ext4_handle_valid(handle));
|
|
|
|
|
|
+ lock_page(page);
|
|
|
+ put_page(page);
|
|
|
+ if (page->mapping != mapping) {
|
|
|
+ /* The page got truncated from under us */
|
|
|
+ ext4_journal_stop(handle);
|
|
|
+ ret = 0;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
if (inline_data) {
|
|
|
BUFFER_TRACE(inode_bh, "get write access");
|
|
|
ret = ext4_journal_get_write_access(handle, inode_bh);
|
|
@@ -1739,6 +1752,8 @@ static int __ext4_journalled_writepage(struct page *page,
|
|
|
NULL, bput_one);
|
|
|
ext4_set_inode_state(inode, EXT4_STATE_JDATA);
|
|
|
out:
|
|
|
+ unlock_page(page);
|
|
|
+out_no_pagelock:
|
|
|
brelse(inode_bh);
|
|
|
return ret;
|
|
|
}
|