]> err.no Git - linux-2.6/blobdiff - mm/filemap.c
[PATCH] aio: clean up debug code
[linux-2.6] / mm / filemap.c
index 93595c327bbdc43fcea91b513fd750d1a73edfec..c085af2332d87c81e53fe05dbcbd7202616cbf4c 100644 (file)
@@ -123,8 +123,7 @@ void remove_from_page_cache(struct page *page)
 {
        struct address_space *mapping = page->mapping;
 
-       if (unlikely(!PageLocked(page)))
-               PAGE_BUG(page);
+       BUG_ON(!PageLocked(page));
 
        write_lock_irq(&mapping->tree_lock);
        __remove_from_page_cache(page);
@@ -139,7 +138,25 @@ static int sync_page(void *word)
        page = container_of((page_flags_t *)word, struct page, flags);
 
        /*
-        * FIXME, fercrissake.  What is this barrier here for?
+        * page_mapping() is being called without PG_locked held.
+        * Some knowledge of the state and use of the page is used to
+        * reduce the requirements down to a memory barrier.
+        * The danger here is of a stale page_mapping() return value
+        * indicating a struct address_space different from the one it's
+        * associated with when it is associated with one.
+        * After smp_mb(), it's either the correct page_mapping() for
+        * the page, or an old page_mapping() and the page's own
+        * page_mapping() has gone NULL.
+        * The ->sync_page() address_space operation must tolerate
+        * page_mapping() going NULL. By an amazing coincidence,
+        * this comes about because none of the users of the page
+        * in the ->sync_page() methods make essential use of the
+        * page_mapping(), merely passing the page down to the backing
+        * device's unplug functions when it's non-NULL, which in turn
+        * ignore it for all cases but swap, where only page->private is
+        * of interest. When page_mapping() does go NULL, the entire
+        * call stack gracefully ignores the page and returns.
+        * -- wli
         */
        smp_mb();
        mapping = page_mapping(page);
@@ -1949,7 +1966,7 @@ generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov,
                buf = iov->iov_base + written;
        else {
                filemap_set_next_iovec(&cur_iov, &iov_base, written);
-               buf = iov->iov_base + iov_base;
+               buf = cur_iov->iov_base + iov_base;
        }
 
        do {
@@ -2007,9 +2024,11 @@ generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov,
                                count -= status;
                                pos += status;
                                buf += status;
-                               if (unlikely(nr_segs > 1))
+                               if (unlikely(nr_segs > 1)) {
                                        filemap_set_next_iovec(&cur_iov,
                                                        &iov_base, status);
+                                       buf = cur_iov->iov_base + iov_base;
+                               }
                        }
                }
                if (unlikely(copied != bytes))