Make alloc_page_buffers to create circular buffer list instead linear
list.
Remove unnecessary traversal in link_dev_buffers to create circular
buffer list.
Make nobh_write_begin and nobh_write_end to support circular buffer list
traversal.

Signed-off-by: Sean Fu <[email protected]>
---
 fs/buffer.c | 48 +++++++++++++++++++++---------------------------
 1 file changed, 21 insertions(+), 27 deletions(-)

diff --git a/fs/buffer.c b/fs/buffer.c
index 0736a6a..7e62c75 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -842,29 +842,36 @@ int remove_inode_buffers(struct inode *inode)
 struct buffer_head *alloc_page_buffers(struct page *page, unsigned long size,
                bool retry)
 {
-       struct buffer_head *bh, *head;
+       struct buffer_head *bh, *head, *tail;
        gfp_t gfp = GFP_NOFS;
        long offset;
 
        if (retry)
                gfp |= __GFP_NOFAIL;
 
-       head = NULL;
+       head = tail = NULL;
        offset = PAGE_SIZE;
        while ((offset -= size) >= 0) {
                bh = alloc_buffer_head(gfp);
                if (!bh)
                        goto no_grow;
 
-               bh->b_this_page = head;
+               if (unlikely(!head))
+                       tail = bh;
+               else
+                       bh->b_this_page = head;
+
                bh->b_blocknr = -1;
                head = bh;
-
                bh->b_size = size;
 
                /* Link the buffer to its page */
                set_bh_page(bh, page, offset);
        }
+
+       if (tail)
+               tail->b_this_page = head;
+
        return head;
 /*
  * In case anything failed, we just free everything we got.
@@ -882,20 +889,6 @@ struct buffer_head *alloc_page_buffers(struct page *page, 
unsigned long size,
 }
 EXPORT_SYMBOL_GPL(alloc_page_buffers);
 
-static inline void
-link_dev_buffers(struct page *page, struct buffer_head *head)
-{
-       struct buffer_head *bh, *tail;
-
-       bh = head;
-       do {
-               tail = bh;
-               bh = bh->b_this_page;
-       } while (bh);
-       tail->b_this_page = head;
-       attach_page_buffers(page, head);
-}
-
 static sector_t blkdev_max_block(struct block_device *bdev, unsigned int size)
 {
        sector_t retval = ~((sector_t)0);
@@ -993,7 +986,7 @@ grow_dev_page(struct block_device *bdev, sector_t block,
         * run under the page lock.
         */
        spin_lock(&inode->i_mapping->private_lock);
-       link_dev_buffers(page, bh);
+       attach_page_buffers(page, bh);
        end_block = init_page_buffers(page, bdev, (sector_t)index << sizebits,
                        size);
        spin_unlock(&inode->i_mapping->private_lock);
@@ -1533,16 +1526,14 @@ EXPORT_SYMBOL(block_invalidatepage);
 void create_empty_buffers(struct page *page,
                        unsigned long blocksize, unsigned long b_state)
 {
-       struct buffer_head *bh, *head, *tail;
+       struct buffer_head *bh, *head;
 
        head = alloc_page_buffers(page, blocksize, true);
        bh = head;
        do {
                bh->b_state |= b_state;
-               tail = bh;
                bh = bh->b_this_page;
-       } while (bh);
-       tail->b_this_page = head;
+       } while (bh != head);
 
        spin_lock(&page->mapping->private_lock);
        if (PageUptodate(page) || PageDirty(page)) {
@@ -2655,11 +2646,14 @@ int nobh_write_begin(struct address_space *mapping,
                 * any VM or truncate activity.  Hence we don't need to care
                 * for the buffer_head refcounts.
                 */
-               for (bh = head; bh; bh = bh->b_this_page) {
+               bh = head;
+               do {
                        wait_on_buffer(bh);
                        if (!buffer_uptodate(bh))
                                ret = -EIO;
-               }
+                       bh = bh->b_this_page;
+               } while (bh != head);
+
                if (ret)
                        goto failed;
        }
@@ -2717,11 +2711,11 @@ int nobh_write_end(struct file *file, struct 
address_space *mapping,
        unlock_page(page);
        put_page(page);
 
-       while (head) {
+       do {
                bh = head;
                head = head->b_this_page;
                free_buffer_head(bh);
-       }
+       } while (head != fsdata);
 
        return copied;
 }
-- 
2.6.2

Reply via email to