[PATCH 1/3] fs: buffer: Create circular buffer list for pages.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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 <fxinrong@xxxxxxxxx>
---
 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




[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]
  Powered by Linux