Btrfs: extent_map optimizations to cut down on CPU usage

Signed-off-by: Chris Mason <chris.mason@oracle.com>
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index f691542..54a5d00 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -463,6 +463,7 @@
 static int check_block(struct btrfs_root *root, struct btrfs_path *path,
 			int level)
 {
+	return 0;
 #if 0
 	struct extent_buffer *buf = path->nodes[level];
 
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 18994c5..a942a242 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -19,6 +19,8 @@
 #ifndef __BTRFS__
 #define __BTRFS__
 
+#include <linux/mm.h>
+#include <linux/highmem.h>
 #include <linux/fs.h>
 #include <linux/workqueue.h>
 #include <linux/completion.h>
@@ -499,70 +501,22 @@
 #define BTRFS_SETGET_HEADER_FUNCS(name, type, member, bits)		\
 static inline u##bits btrfs_##name(struct extent_buffer *eb)		\
 {									\
-	int err;							\
-	char *map_token;						\
-	char *kaddr;							\
-	unsigned long map_start;					\
-	unsigned long map_len;						\
+	char *kaddr = kmap_atomic(eb->first_page, KM_USER0);		\
 	unsigned long offset = offsetof(type, member);			\
-	int unmap_on_exit = (eb->map_token == NULL);			\
-	if (eb->map_token && offset >= eb->map_start &&			\
-	    offset + sizeof(((type *)0)->member) <= eb->map_start +	\
-	    eb->map_len) {						\
-	    kaddr = eb->kaddr;						\
-	    map_start = eb->map_start;					\
-	    err = 0;							\
-	} else {							\
-		err = map_extent_buffer(eb, offset,			\
-			        sizeof(((type *)0)->member),		\
-				&map_token, &kaddr,			\
-				&map_start, &map_len, KM_USER1);	\
-	}								\
-	if (!err) {							\
-		__le##bits *tmp = (__le##bits *)(kaddr + offset -	\
-					       map_start);		\
-		u##bits res = le##bits##_to_cpu(*tmp);			\
-		if (unmap_on_exit)					\
-			unmap_extent_buffer(eb, map_token, KM_USER1);	\
-		return res;						\
-	} else {							\
-		__le##bits res;						\
-		read_eb_member(eb, NULL, type, member, &res);		\
-		return le##bits##_to_cpu(res);				\
-	}								\
+	u##bits res;							\
+	__le##bits *tmp = (__le##bits *)(kaddr + offset);		\
+	res = le##bits##_to_cpu(*tmp);					\
+	kunmap_atomic(kaddr, KM_USER0);					\
+	return res;							\
 }									\
 static inline void btrfs_set_##name(struct extent_buffer *eb,		\
 				    u##bits val)			\
 {									\
-	int err;							\
-	char *map_token;						\
-	char *kaddr;							\
-	unsigned long map_start;					\
-	unsigned long map_len;						\
+	char *kaddr = kmap_atomic(eb->first_page, KM_USER0);		\
 	unsigned long offset = offsetof(type, member);			\
-	int unmap_on_exit = (eb->map_token == NULL);			\
-	if (eb->map_token && offset >= eb->map_start &&			\
-	    offset + sizeof(((type *)0)->member) <= eb->map_start +	\
-	    eb->map_len) {						\
-	    kaddr = eb->kaddr;						\
-	    map_start = eb->map_start;					\
-	    err = 0;							\
-	} else {							\
-		err = map_extent_buffer(eb, offset,			\
-			        sizeof(((type *)0)->member),		\
-				&map_token, &kaddr,			\
-				&map_start, &map_len, KM_USER1);	\
-	}								\
-	if (!err) {							\
-		__le##bits *tmp = (__le##bits *)(kaddr + offset -	\
-					       map_start);		\
-		*tmp = cpu_to_le##bits(val);				\
-		if (unmap_on_exit)					\
-			unmap_extent_buffer(eb, map_token, KM_USER1);	\
-	} else {							\
-		val = cpu_to_le##bits(val);				\
-		write_eb_member(eb, NULL, type, member, &val);		\
-	}								\
+	__le##bits *tmp = (__le##bits *)(kaddr + offset);		\
+	*tmp = cpu_to_le##bits(val);					\
+	kunmap_atomic(kaddr, KM_USER0);					\
 }
 
 #define BTRFS_SETGET_STACK_FUNCS(name, type, member, bits)		\
@@ -659,13 +613,13 @@
 	btrfs_set_key_blockptr(eb, (struct btrfs_key_ptr *)ptr, val);
 }
 
-static unsigned long btrfs_node_key_ptr_offset(int nr)
+static inline unsigned long btrfs_node_key_ptr_offset(int nr)
 {
 	return offsetof(struct btrfs_node, ptrs) +
 		sizeof(struct btrfs_key_ptr) * nr;
 }
 
-static void btrfs_node_key(struct extent_buffer *eb,
+static inline void btrfs_node_key(struct extent_buffer *eb,
 			   struct btrfs_disk_key *disk_key, int nr)
 {
 	unsigned long ptr;
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index fd7e6c1..16f0260 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -644,20 +644,20 @@
 
 int btrfs_buffer_uptodate(struct extent_buffer *buf)
 {
-	struct inode *btree_inode = buf->last_page->mapping->host;
+	struct inode *btree_inode = buf->first_page->mapping->host;
 	return extent_buffer_uptodate(&BTRFS_I(btree_inode)->extent_tree, buf);
 }
 
 int btrfs_set_buffer_uptodate(struct extent_buffer *buf)
 {
-	struct inode *btree_inode = buf->last_page->mapping->host;
+	struct inode *btree_inode = buf->first_page->mapping->host;
 	return set_extent_buffer_uptodate(&BTRFS_I(btree_inode)->extent_tree,
 					  buf);
 }
 
 void btrfs_mark_buffer_dirty(struct extent_buffer *buf)
 {
-	struct btrfs_root *root = BTRFS_I(buf->last_page->mapping->host)->root;
+	struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root;
 	u64 transid = btrfs_header_generation(buf);
 	struct inode *btree_inode = root->fs_info->btree_inode;
 
@@ -678,7 +678,7 @@
 
 void btrfs_set_buffer_defrag(struct extent_buffer *buf)
 {
-	struct btrfs_root *root = BTRFS_I(buf->last_page->mapping->host)->root;
+	struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root;
 	struct inode *btree_inode = root->fs_info->btree_inode;
 	set_extent_bits(&BTRFS_I(btree_inode)->extent_tree, buf->start,
 			buf->start + buf->len - 1, EXTENT_DEFRAG, GFP_NOFS);
@@ -686,7 +686,7 @@
 
 void btrfs_set_buffer_defrag_done(struct extent_buffer *buf)
 {
-	struct btrfs_root *root = BTRFS_I(buf->last_page->mapping->host)->root;
+	struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root;
 	struct inode *btree_inode = root->fs_info->btree_inode;
 	set_extent_bits(&BTRFS_I(btree_inode)->extent_tree, buf->start,
 			buf->start + buf->len - 1, EXTENT_DEFRAG_DONE,
@@ -695,7 +695,7 @@
 
 int btrfs_buffer_defrag(struct extent_buffer *buf)
 {
-	struct btrfs_root *root = BTRFS_I(buf->last_page->mapping->host)->root;
+	struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root;
 	struct inode *btree_inode = root->fs_info->btree_inode;
 	return test_range_bit(&BTRFS_I(btree_inode)->extent_tree,
 		     buf->start, buf->start + buf->len - 1, EXTENT_DEFRAG, 0);
@@ -703,7 +703,7 @@
 
 int btrfs_buffer_defrag_done(struct extent_buffer *buf)
 {
-	struct btrfs_root *root = BTRFS_I(buf->last_page->mapping->host)->root;
+	struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root;
 	struct inode *btree_inode = root->fs_info->btree_inode;
 	return test_range_bit(&BTRFS_I(btree_inode)->extent_tree,
 		     buf->start, buf->start + buf->len - 1,
@@ -712,7 +712,7 @@
 
 int btrfs_clear_buffer_defrag_done(struct extent_buffer *buf)
 {
-	struct btrfs_root *root = BTRFS_I(buf->last_page->mapping->host)->root;
+	struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root;
 	struct inode *btree_inode = root->fs_info->btree_inode;
 	return clear_extent_bits(&BTRFS_I(btree_inode)->extent_tree,
 		     buf->start, buf->start + buf->len - 1,
@@ -721,7 +721,7 @@
 
 int btrfs_clear_buffer_defrag(struct extent_buffer *buf)
 {
-	struct btrfs_root *root = BTRFS_I(buf->last_page->mapping->host)->root;
+	struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root;
 	struct inode *btree_inode = root->fs_info->btree_inode;
 	return clear_extent_bits(&BTRFS_I(btree_inode)->extent_tree,
 		     buf->start, buf->start + buf->len - 1,
@@ -730,7 +730,7 @@
 
 int btrfs_read_buffer(struct extent_buffer *buf)
 {
-	struct btrfs_root *root = BTRFS_I(buf->last_page->mapping->host)->root;
+	struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root;
 	struct inode *btree_inode = root->fs_info->btree_inode;
 	return read_extent_buffer_pages(&BTRFS_I(btree_inode)->extent_tree,
 					buf, 1);
diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c
index 85b28a6..f8aaba8 100644
--- a/fs/btrfs/extent_map.c
+++ b/fs/btrfs/extent_map.c
@@ -1963,9 +1963,9 @@
 	struct page *p;
 
 	if (i == 0)
-		return eb->last_page;
+		return eb->first_page;
 	i += eb->start >> PAGE_CACHE_SHIFT;
-	p = find_get_page(eb->last_page->mapping, i);
+	p = find_get_page(eb->first_page->mapping, i);
 	page_cache_release(p);
 	return p;
 }
@@ -2037,7 +2037,7 @@
 		}
 		set_page_extent_mapped(p);
 		if (i == 0)
-			eb->last_page = p;
+			eb->first_page = p;
 		if (!PageUptodate(p))
 			uptodate = 0;
 		unlock_page(p);
@@ -2083,7 +2083,7 @@
 		}
 		set_page_extent_mapped(p);
 		if (i == 0)
-			eb->last_page = p;
+			eb->first_page = p;
 		if (!PageUptodate(p))
 			uptodate = 0;
 		unlock_page(p);
@@ -2169,7 +2169,15 @@
 int set_extent_buffer_dirty(struct extent_map_tree *tree,
 			     struct extent_buffer *eb)
 {
-	return set_range_dirty(tree, eb->start, eb->start + eb->len - 1);
+	unsigned long i;
+	unsigned long num_pages;
+
+	num_pages = num_extent_pages(eb->start, eb->len);
+	for (i = 0; i < num_pages; i++) {
+		__set_page_dirty_nobuffers(extent_buffer_page(eb, i));
+	}
+	return set_extent_dirty(tree, eb->start,
+				eb->start + eb->len - 1, GFP_NOFS);
 }
 EXPORT_SYMBOL(set_extent_buffer_dirty);
 
@@ -2317,16 +2325,11 @@
 	size_t start_offset = eb->start & ((u64)PAGE_CACHE_SIZE - 1);
 	unsigned long i = (start_offset + start) >> PAGE_CACHE_SHIFT;
 	unsigned long end_i = (start_offset + start + min_len) >>
-				PAGE_CACHE_SHIFT;
+		PAGE_CACHE_SHIFT;
 
 	if (i != end_i)
 		return -EINVAL;
 
-	if (start >= eb->len) {
-		printk("bad start in map eb start %Lu len %lu caller start %lu min %lu\n", eb->start, eb->len, start, min_len);
-		WARN_ON(1);
-	}
-
 	if (i == 0) {
 		offset = start_offset;
 		*map_start = 0;
@@ -2353,14 +2356,6 @@
 	int err;
 	int save = 0;
 	if (eb->map_token) {
-		if (start >= eb->map_start &&
-		    start + min_len <= eb->map_start + eb->map_len) {
-			*token = eb->map_token;
-			*map = eb->kaddr;
-			*map_start = eb->map_start;
-			*map_len = eb->map_len;
-			return 0;
-		}
 		unmap_extent_buffer(eb, eb->map_token, km);
 		eb->map_token = NULL;
 		save = 1;
diff --git a/fs/btrfs/extent_map.h b/fs/btrfs/extent_map.h
index 52a8b93..f1dc28d 100644
--- a/fs/btrfs/extent_map.h
+++ b/fs/btrfs/extent_map.h
@@ -75,7 +75,7 @@
 	char *kaddr;
 	unsigned long map_start;
 	unsigned long map_len;
-	struct page *last_page;
+	struct page *first_page;
 	struct list_head lru;
 	atomic_t refs;
 	int flags;
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 1af2b65..fe28404 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -289,7 +289,6 @@
 	 */
 	inline_size = end_pos;
 	if (isize >= BTRFS_MAX_INLINE_DATA_SIZE(root) ||
-	    inline_size > 16384 ||
 	    inline_size >= BTRFS_MAX_INLINE_DATA_SIZE(root)) {
 		u64 last_end;