[PATCH] Trivial optimization of ll_rw_block()
[safe/jmp/linux-2.6] / fs / buffer.c
index 5502323..62cfd17 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/percpu.h>
 #include <linux/slab.h>
 #include <linux/smp_lock.h>
+#include <linux/capability.h>
 #include <linux/blkdev.h>
 #include <linux/file.h>
 #include <linux/quotaops.h>
@@ -153,14 +154,8 @@ int sync_blockdev(struct block_device *bdev)
 {
        int ret = 0;
 
-       if (bdev) {
-               int err;
-
-               ret = filemap_fdatawrite(bdev->bd_inode->i_mapping);
-               err = filemap_fdatawait(bdev->bd_inode->i_mapping);
-               if (!ret)
-                       ret = err;
-       }
+       if (bdev)
+               ret = filemap_write_and_wait(bdev->bd_inode->i_mapping);
        return ret;
 }
 EXPORT_SYMBOL(sync_blockdev);
@@ -358,11 +353,11 @@ static long do_fsync(unsigned int fd, int datasync)
         * We need to protect against concurrent writers,
         * which could cause livelocks in fsync_buffers_list
         */
-       down(&mapping->host->i_sem);
+       mutex_lock(&mapping->host->i_mutex);
        err = file->f_op->fsync(file, file->f_dentry, datasync);
        if (!ret)
                ret = err;
-       up(&mapping->host->i_sem);
+       mutex_unlock(&mapping->host->i_mutex);
        err = filemap_fdatawait(mapping);
        if (!ret)
                ret = err;
@@ -1027,12 +1022,13 @@ try_again:
 
                bh->b_state = 0;
                atomic_set(&bh->b_count, 0);
+               bh->b_private = NULL;
                bh->b_size = size;
 
                /* Link the buffer to its page */
                set_bh_page(bh, page, offset);
 
-               bh->b_end_io = NULL;
+               init_buffer(bh, NULL, NULL);
        }
        return head;
 /*
@@ -1170,7 +1166,7 @@ failed:
  * some of those buffers may be aliases of filesystem data.
  * grow_dev_page() will go BUG() if this happens.
  */
-static inline int
+static int
 grow_buffers(struct block_device *bdev, sector_t block, int size)
 {
        struct page *page;
@@ -1396,7 +1392,7 @@ static void bh_lru_install(struct buffer_head *bh)
 /*
  * Look up the bh in this cpu's LRU.  If it's there, move it to the head.
  */
-static inline struct buffer_head *
+static struct buffer_head *
 lookup_bh_lru(struct block_device *bdev, sector_t block, int size)
 {
        struct buffer_head *ret = NULL;
@@ -1546,7 +1542,7 @@ EXPORT_SYMBOL(set_bh_page);
 /*
  * Called when truncating a buffer on a page completely.
  */
-static inline void discard_buffer(struct buffer_head * bh)
+static void discard_buffer(struct buffer_head * bh)
 {
        lock_buffer(bh);
        clear_buffer_dirty(bh);
@@ -1768,7 +1764,7 @@ static int __block_write_full_page(struct inode *inode, struct page *page,
         * handle that here by just cleaning them.
         */
 
-       block = page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits);
+       block = (sector_t)page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits);
        head = page_buffers(page);
        bh = head;
 
@@ -2344,7 +2340,7 @@ int generic_commit_write(struct file *file, struct page *page,
        __block_commit_write(inode,page,from,to);
        /*
         * No need to use i_size_read() here, the i_size
-        * cannot change under us because we hold i_sem.
+        * cannot change under us because we hold i_mutex.
         */
        if (pos > inode->i_size) {
                i_size_write(inode, pos);
@@ -2641,7 +2637,7 @@ int block_truncate_page(struct address_space *mapping,
        pgoff_t index = from >> PAGE_CACHE_SHIFT;
        unsigned offset = from & (PAGE_CACHE_SIZE-1);
        unsigned blocksize;
-       pgoff_t iblock;
+       sector_t iblock;
        unsigned length, pos;
        struct inode *inode = mapping->host;
        struct page *page;
@@ -2657,7 +2653,7 @@ int block_truncate_page(struct address_space *mapping,
                return 0;
 
        length = blocksize - length;
-       iblock = index << (PAGE_CACHE_SHIFT - inode->i_blkbits);
+       iblock = (sector_t)index << (PAGE_CACHE_SHIFT - inode->i_blkbits);
        
        page = grab_cache_page(mapping, index);
        err = -ENOMEM;
@@ -2871,22 +2867,22 @@ void ll_rw_block(int rw, int nr, struct buffer_head *bhs[])
                else if (test_set_buffer_locked(bh))
                        continue;
 
-               get_bh(bh);
                if (rw == WRITE || rw == SWRITE) {
                        if (test_clear_buffer_dirty(bh)) {
                                bh->b_end_io = end_buffer_write_sync;
+                               get_bh(bh);
                                submit_bh(WRITE, bh);
                                continue;
                        }
                } else {
                        if (!buffer_uptodate(bh)) {
                                bh->b_end_io = end_buffer_read_sync;
+                               get_bh(bh);
                                submit_bh(rw, bh);
                                continue;
                        }
                }
                unlock_buffer(bh);
-               put_bh(bh);
        }
 }
 
@@ -3055,6 +3051,66 @@ asmlinkage long sys_bdflush(int func, long data)
 }
 
 /*
+ * Migration function for pages with buffers. This function can only be used
+ * if the underlying filesystem guarantees that no other references to "page"
+ * exist.
+ */
+#ifdef CONFIG_MIGRATION
+int buffer_migrate_page(struct page *newpage, struct page *page)
+{
+       struct address_space *mapping = page->mapping;
+       struct buffer_head *bh, *head;
+
+       if (!mapping)
+               return -EAGAIN;
+
+       if (!page_has_buffers(page))
+               return migrate_page(newpage, page);
+
+       head = page_buffers(page);
+
+       if (migrate_page_remove_references(newpage, page, 3))
+               return -EAGAIN;
+
+       bh = head;
+       do {
+               get_bh(bh);
+               lock_buffer(bh);
+               bh = bh->b_this_page;
+
+       } while (bh != head);
+
+       ClearPagePrivate(page);
+       set_page_private(newpage, page_private(page));
+       set_page_private(page, 0);
+       put_page(page);
+       get_page(newpage);
+
+       bh = head;
+       do {
+               set_bh_page(bh, newpage, bh_offset(bh));
+               bh = bh->b_this_page;
+
+       } while (bh != head);
+
+       SetPagePrivate(newpage);
+
+       migrate_page_copy(newpage, page);
+
+       bh = head;
+       do {
+               unlock_buffer(bh);
+               put_bh(bh);
+               bh = bh->b_this_page;
+
+       } while (bh != head);
+
+       return 0;
+}
+EXPORT_SYMBOL(buffer_migrate_page);
+#endif
+
+/*
  * Buffer-head allocation
  */
 static kmem_cache_t *bh_cachep;