Merge branch 'pm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/suspe...
[safe/jmp/linux-2.6] / fs / ceph / addr.c
index 71f5ad1..ce8ef61 100644 (file)
@@ -144,7 +144,7 @@ static int ceph_set_page_dirty(struct page *page)
  */
 static void ceph_invalidatepage(struct page *page, unsigned long offset)
 {
-       struct inode *inode = page->mapping->host;
+       struct inode *inode;
        struct ceph_inode_info *ci;
        struct ceph_snap_context *snapc = (void *)page->private;
 
@@ -153,6 +153,8 @@ static void ceph_invalidatepage(struct page *page, unsigned long offset)
        BUG_ON(!PagePrivate(page));
        BUG_ON(!page->mapping);
 
+       inode = page->mapping->host;
+
        /*
         * We can get non-dirty pages here due to races between
         * set_page_dirty and truncate_complete_page; just spit out a
@@ -514,6 +516,7 @@ static void writepages_finish(struct ceph_osd_request *req,
        u64 bytes = 0;
        struct ceph_client *client = ceph_inode_to_client(inode);
        long writeback_stat;
+       unsigned issued = __ceph_caps_issued(ci, NULL);
 
        /* parse reply */
        replyhead = msg->front.iov_base;
@@ -559,6 +562,16 @@ static void writepages_finish(struct ceph_osd_request *req,
                ceph_put_snap_context(snapc);
                dout("unlocking %d %p\n", i, page);
                end_page_writeback(page);
+
+               /*
+                * We lost the cache cap, need to truncate the page before
+                * it is unlocked, otherwise we'd truncate it later in the
+                * page truncation thread, possibly losing some data that
+                * raced its way in
+                */
+               if ((issued & CEPH_CAP_FILE_CACHE) == 0)
+                       generic_error_remove_page(inode->i_mapping, page);
+
                unlock_page(page);
        }
        dout("%p wrote+cleaned %d pages\n", inode, wrote);
@@ -906,6 +919,10 @@ static int context_is_writeable_or_written(struct inode *inode,
 /*
  * We are only allowed to write into/dirty the page if the page is
  * clean, or already dirty within the same snap context.
+ *
+ * called with page locked.
+ * return success with page locked,
+ * or any failure (incl -EAGAIN) with page unlocked.
  */
 static int ceph_update_writeable_page(struct file *file,
                            loff_t pos, unsigned len,
@@ -948,9 +965,11 @@ retry_locked:
                        snapc = ceph_get_snap_context((void *)page->private);
                        unlock_page(page);
                        ceph_queue_writeback(inode);
-                       wait_event_interruptible(ci->i_cap_wq,
+                       r = wait_event_interruptible(ci->i_cap_wq,
                               context_is_writeable_or_written(inode, snapc));
                        ceph_put_snap_context(snapc);
+                       if (r == -ERESTARTSYS)
+                               return r;
                        return -EAGAIN;
                }
 
@@ -1022,7 +1041,7 @@ static int ceph_write_begin(struct file *file, struct address_space *mapping,
        int r;
 
        do {
-               /* get a page*/
+               /* get a page */
                page = grab_cache_page_write_begin(mapping, index, 0);
                if (!page)
                        return -ENOMEM;