ext4: fix a BUG_ON crash by checking that page has buffers attached to it
Theodore Ts'o [Thu, 1 Oct 2009 02:57:41 +0000 (22:57 -0400)]
In ext4_num_dirty_pages() we were calling page_buffers() before
checking to see if the page actually had pages attached to it; this
would cause a BUG check crash in the inline function page_buffers().

Thanks to Markus Trippelsdorf for reporting this bug.

Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>

fs/ext4/inode.c

index ec367bc..6e65d0e 100644 (file)
@@ -1146,8 +1146,8 @@ static int check_block_validity(struct inode *inode, const char *msg,
 }
 
 /*
- * Return the number of dirty pages in the given inode starting at
- * page frame idx.
+ * Return the number of contiguous dirty pages in a given inode
+ * starting at page frame idx.
  */
 static pgoff_t ext4_num_dirty_pages(struct inode *inode, pgoff_t idx,
                                    unsigned int max_pages)
@@ -1181,15 +1181,15 @@ static pgoff_t ext4_num_dirty_pages(struct inode *inode, pgoff_t idx,
                                unlock_page(page);
                                break;
                        }
-                       head = page_buffers(page);
-                       bh = head;
-                       do {
-                               if (!buffer_delay(bh) &&
-                                   !buffer_unwritten(bh)) {
-                                       done = 1;
-                                       break;
-                               }
-                       } while ((bh = bh->b_this_page) != head);
+                       if (page_has_buffers(page)) {
+                               bh = head = page_buffers(page);
+                               do {
+                                       if (!buffer_delay(bh) &&
+                                           !buffer_unwritten(bh))
+                                               done = 1;
+                                       bh = bh->b_this_page;
+                               } while (!done && (bh != head));
+                       }
                        unlock_page(page);
                        if (done)
                                break;