]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
kclient: don't fall over on !dirty page in invalidatepage
authorSage Weil <sage@newdream.net>
Thu, 5 Mar 2009 23:35:39 +0000 (15:35 -0800)
committerSage Weil <sage@newdream.net>
Fri, 6 Mar 2009 00:29:14 +0000 (16:29 -0800)
Spit out a warning, in case we end up with writeback accounting
errors.  I _think_ it's ok, though.

src/kernel/addr.c

index 54dd65f65490bfa20eca1bed36904b86b0c8d6fc..4d774d18694aa24af2a27faf09f1b4d1b829207d 100644 (file)
@@ -55,8 +55,9 @@ int ceph_debug_addr __read_mostly = -1;
  * i_snap_realm.  Otherwise, redirty a page within the context of
  * the given *snapc.
  *
- * Note that the caller (e.g., write_begin) _should_ be holding
- * a read lock on mdsc->snap_rwsem.
+ * Caller may or may not have locked *page.  That means we can race
+ * with truncate_complete_page and end up with a non-dirty page with
+ * private data.
  */
 static int ceph_set_page_dirty(struct page *page,
                               struct ceph_snap_context *snapc)
@@ -75,9 +76,6 @@ static int ceph_set_page_dirty(struct page *page,
                return 0;
        }
 
-       BUG_ON(page->private);
-       BUG_ON(PagePrivate(page));
-
        /*
         * optimistically adjust accounting, on the assumption that
         * we won't race with invalidate.
@@ -143,8 +141,6 @@ static int ceph_set_page_dirty(struct page *page,
                 * Reference snap context in page->private.  Also set
                 * PagePrivate so that we get invalidatepage callback.
                 */
-               BUG_ON(page->private);
-               BUG_ON(PagePrivate(page));
                page->private = (unsigned long)snapc;
                SetPagePrivate(page);
        } else {
@@ -179,7 +175,7 @@ static int ceph_set_page_dirty_vfs(struct page *page)
  */
 static void ceph_invalidatepage(struct page *page, unsigned long offset)
 {
-       struct inode *inode;
+       struct inode *inode = page->mapping->host;
        struct ceph_inode_info *ci;
        struct ceph_snap_context *snapc = (void *)page->private;
 
@@ -187,12 +183,18 @@ static void ceph_invalidatepage(struct page *page, unsigned long offset)
        BUG_ON(!page->private);
        BUG_ON(!PagePrivate(page));
        BUG_ON(!page->mapping);
-       BUG_ON(!PageDirty(page));
+
+       /*
+        * We can get non-dirty pages here due to races between
+        * set_page_dirty and truncate_complete_page; just spit out a
+        * warning, in case we end up with accounting problems later.
+        */
+       if (!PageDirty(page))
+               dout(0, "%p invalidatepage %p page not dirty\n", inode, page);
 
        if (offset == 0)
                ClearPageChecked(page);
 
-       inode = page->mapping->host;
        ci = ceph_inode(inode);
        if (offset == 0) {
                dout(20, "%p invalidatepage %p idx %lu full dirty page %lu\n",