|
@@ -862,6 +862,12 @@ struct ocfs2_write_ctxt {
|
|
|
struct page *w_pages[OCFS2_MAX_CTXT_PAGES];
|
|
|
struct page *w_target_page;
|
|
|
|
|
|
+ /*
|
|
|
+ * w_target_locked is used for page_mkwrite path indicating no unlocking
|
|
|
+ * against w_target_page in ocfs2_write_end_nolock.
|
|
|
+ */
|
|
|
+ unsigned int w_target_locked:1;
|
|
|
+
|
|
|
/*
|
|
|
* ocfs2_write_end() uses this to know what the real range to
|
|
|
* write in the target should be.
|
|
@@ -895,6 +901,24 @@ void ocfs2_unlock_and_free_pages(struct page **pages, int num_pages)
|
|
|
|
|
|
static void ocfs2_free_write_ctxt(struct ocfs2_write_ctxt *wc)
|
|
|
{
|
|
|
+ int i;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * w_target_locked is only set to true in the page_mkwrite() case.
|
|
|
+ * The intent is to allow us to lock the target page from write_begin()
|
|
|
+ * to write_end(). The caller must hold a ref on w_target_page.
|
|
|
+ */
|
|
|
+ if (wc->w_target_locked) {
|
|
|
+ BUG_ON(!wc->w_target_page);
|
|
|
+ for (i = 0; i < wc->w_num_pages; i++) {
|
|
|
+ if (wc->w_target_page == wc->w_pages[i]) {
|
|
|
+ wc->w_pages[i] = NULL;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ mark_page_accessed(wc->w_target_page);
|
|
|
+ page_cache_release(wc->w_target_page);
|
|
|
+ }
|
|
|
ocfs2_unlock_and_free_pages(wc->w_pages, wc->w_num_pages);
|
|
|
|
|
|
brelse(wc->w_di_bh);
|
|
@@ -1132,20 +1156,17 @@ static int ocfs2_grab_pages_for_write(struct address_space *mapping,
|
|
|
*/
|
|
|
lock_page(mmap_page);
|
|
|
|
|
|
+ /* Exit and let the caller retry */
|
|
|
if (mmap_page->mapping != mapping) {
|
|
|
+ WARN_ON(mmap_page->mapping);
|
|
|
unlock_page(mmap_page);
|
|
|
- /*
|
|
|
- * Sanity check - the locking in
|
|
|
- * ocfs2_pagemkwrite() should ensure
|
|
|
- * that this code doesn't trigger.
|
|
|
- */
|
|
|
- ret = -EINVAL;
|
|
|
- mlog_errno(ret);
|
|
|
+ ret = -EAGAIN;
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
page_cache_get(mmap_page);
|
|
|
wc->w_pages[i] = mmap_page;
|
|
|
+ wc->w_target_locked = true;
|
|
|
} else {
|
|
|
wc->w_pages[i] = find_or_create_page(mapping, index,
|
|
|
GFP_NOFS);
|
|
@@ -1160,6 +1181,8 @@ static int ocfs2_grab_pages_for_write(struct address_space *mapping,
|
|
|
wc->w_target_page = wc->w_pages[i];
|
|
|
}
|
|
|
out:
|
|
|
+ if (ret)
|
|
|
+ wc->w_target_locked = false;
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
@@ -1817,11 +1840,23 @@ try_again:
|
|
|
*/
|
|
|
ret = ocfs2_grab_pages_for_write(mapping, wc, wc->w_cpos, pos, len,
|
|
|
cluster_of_pages, mmap_page);
|
|
|
- if (ret) {
|
|
|
+ if (ret && ret != -EAGAIN) {
|
|
|
mlog_errno(ret);
|
|
|
goto out_quota;
|
|
|
}
|
|
|
|
|
|
+ /*
|
|
|
+ * ocfs2_grab_pages_for_write() returns -EAGAIN if it could not lock
|
|
|
+ * the target page. In this case, we exit with no error and no target
|
|
|
+ * page. This will trigger the caller, page_mkwrite(), to re-try
|
|
|
+ * the operation.
|
|
|
+ */
|
|
|
+ if (ret == -EAGAIN) {
|
|
|
+ BUG_ON(wc->w_target_page);
|
|
|
+ ret = 0;
|
|
|
+ goto out_quota;
|
|
|
+ }
|
|
|
+
|
|
|
ret = ocfs2_write_cluster_by_desc(mapping, data_ac, meta_ac, wc, pos,
|
|
|
len);
|
|
|
if (ret) {
|