diff options
| author | Jiri Kosina <jkosina@suse.cz> | 2011-09-15 15:08:05 +0200 | 
|---|---|---|
| committer | Jiri Kosina <jkosina@suse.cz> | 2011-09-15 15:08:18 +0200 | 
| commit | e060c38434b2caa78efe7cedaff4191040b65a15 (patch) | |
| tree | 407361230bf6733f63d8e788e4b5e6566ee04818 /fs/btrfs/ctree.c | |
| parent | 10e4ac572eeffe5317019bd7330b6058a400dfc2 (diff) | |
| parent | cc39c6a9bbdebfcf1a7dee64d83bf302bc38d941 (diff) | |
| download | olio-linux-3.10-e060c38434b2caa78efe7cedaff4191040b65a15.tar.xz olio-linux-3.10-e060c38434b2caa78efe7cedaff4191040b65a15.zip  | |
Merge branch 'master' into for-next
Fast-forward merge with Linus to be able to merge patches
based on more recent version of the tree.
Diffstat (limited to 'fs/btrfs/ctree.c')
| -rw-r--r-- | fs/btrfs/ctree.c | 457 | 
1 files changed, 198 insertions, 259 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 2e667868e0d..011cab3aca8 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -54,8 +54,13 @@ noinline void btrfs_set_path_blocking(struct btrfs_path *p)  {  	int i;  	for (i = 0; i < BTRFS_MAX_LEVEL; i++) { -		if (p->nodes[i] && p->locks[i]) -			btrfs_set_lock_blocking(p->nodes[i]); +		if (!p->nodes[i] || !p->locks[i]) +			continue; +		btrfs_set_lock_blocking_rw(p->nodes[i], p->locks[i]); +		if (p->locks[i] == BTRFS_READ_LOCK) +			p->locks[i] = BTRFS_READ_LOCK_BLOCKING; +		else if (p->locks[i] == BTRFS_WRITE_LOCK) +			p->locks[i] = BTRFS_WRITE_LOCK_BLOCKING;  	}  } @@ -68,7 +73,7 @@ noinline void btrfs_set_path_blocking(struct btrfs_path *p)   * for held   */  noinline void btrfs_clear_path_blocking(struct btrfs_path *p, -					struct extent_buffer *held) +					struct extent_buffer *held, int held_rw)  {  	int i; @@ -79,19 +84,29 @@ noinline void btrfs_clear_path_blocking(struct btrfs_path *p,  	 * really sure by forcing the path to blocking before we clear  	 * the path blocking.  	 */ -	if (held) -		btrfs_set_lock_blocking(held); +	if (held) { +		btrfs_set_lock_blocking_rw(held, held_rw); +		if (held_rw == BTRFS_WRITE_LOCK) +			held_rw = BTRFS_WRITE_LOCK_BLOCKING; +		else if (held_rw == BTRFS_READ_LOCK) +			held_rw = BTRFS_READ_LOCK_BLOCKING; +	}  	btrfs_set_path_blocking(p);  #endif  	for (i = BTRFS_MAX_LEVEL - 1; i >= 0; i--) { -		if (p->nodes[i] && p->locks[i]) -			btrfs_clear_lock_blocking(p->nodes[i]); +		if (p->nodes[i] && p->locks[i]) { +			btrfs_clear_lock_blocking_rw(p->nodes[i], p->locks[i]); +			if (p->locks[i] == BTRFS_WRITE_LOCK_BLOCKING) +				p->locks[i] = BTRFS_WRITE_LOCK; +			else if (p->locks[i] == BTRFS_READ_LOCK_BLOCKING) +				p->locks[i] = BTRFS_READ_LOCK; +		}  	}  #ifdef CONFIG_DEBUG_LOCK_ALLOC  	if (held) -		btrfs_clear_lock_blocking(held); +		btrfs_clear_lock_blocking_rw(held, held_rw);  #endif  } @@ -119,7 +134,7 @@ noinline void btrfs_release_path(struct btrfs_path *p)  		if (!p->nodes[i])  			continue;  		if (p->locks[i]) { -			btrfs_tree_unlock(p->nodes[i]); +			btrfs_tree_unlock_rw(p->nodes[i], p->locks[i]);  			p->locks[i] = 0;  		}  		free_extent_buffer(p->nodes[i]); @@ -167,6 +182,25 @@ struct extent_buffer *btrfs_lock_root_node(struct btrfs_root *root)  	return eb;  } +/* loop around taking references on and locking the root node of the + * tree until you end up with a lock on the root.  A locked buffer + * is returned, with a reference held. + */ +struct extent_buffer *btrfs_read_lock_root_node(struct btrfs_root *root) +{ +	struct extent_buffer *eb; + +	while (1) { +		eb = btrfs_root_node(root); +		btrfs_tree_read_lock(eb); +		if (eb == root->node) +			break; +		btrfs_tree_read_unlock(eb); +		free_extent_buffer(eb); +	} +	return eb; +} +  /* cowonly root (everything not a reference counted cow subvolume), just get   * put onto a simple dirty list.  transaction.c walks this to make sure they   * get properly updated on disk. @@ -626,14 +660,6 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,  	for (i = start_slot; i < end_slot; i++) {  		int close = 1; -		if (!parent->map_token) { -			map_extent_buffer(parent, -					btrfs_node_key_ptr_offset(i), -					sizeof(struct btrfs_key_ptr), -					&parent->map_token, &parent->kaddr, -					&parent->map_start, &parent->map_len, -					KM_USER1); -		}  		btrfs_node_key(parent, &disk_key, i);  		if (!progress_passed && comp_keys(&disk_key, progress) < 0)  			continue; @@ -656,11 +682,6 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,  			last_block = blocknr;  			continue;  		} -		if (parent->map_token) { -			unmap_extent_buffer(parent, parent->map_token, -					    KM_USER1); -			parent->map_token = NULL; -		}  		cur = btrfs_find_tree_block(root, blocknr, blocksize);  		if (cur) @@ -701,11 +722,6 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,  		btrfs_tree_unlock(cur);  		free_extent_buffer(cur);  	} -	if (parent->map_token) { -		unmap_extent_buffer(parent, parent->map_token, -				    KM_USER1); -		parent->map_token = NULL; -	}  	return err;  } @@ -746,7 +762,6 @@ static noinline int generic_bin_search(struct extent_buffer *eb,  	struct btrfs_disk_key *tmp = NULL;  	struct btrfs_disk_key unaligned;  	unsigned long offset; -	char *map_token = NULL;  	char *kaddr = NULL;  	unsigned long map_start = 0;  	unsigned long map_len = 0; @@ -756,18 +771,13 @@ static noinline int generic_bin_search(struct extent_buffer *eb,  		mid = (low + high) / 2;  		offset = p + mid * item_size; -		if (!map_token || offset < map_start || +		if (!kaddr || offset < map_start ||  		    (offset + sizeof(struct btrfs_disk_key)) >  		    map_start + map_len) { -			if (map_token) { -				unmap_extent_buffer(eb, map_token, KM_USER0); -				map_token = NULL; -			}  			err = map_private_extent_buffer(eb, offset,  						sizeof(struct btrfs_disk_key), -						&map_token, &kaddr, -						&map_start, &map_len, KM_USER0); +						&kaddr, &map_start, &map_len);  			if (!err) {  				tmp = (struct btrfs_disk_key *)(kaddr + offset - @@ -790,14 +800,10 @@ static noinline int generic_bin_search(struct extent_buffer *eb,  			high = mid;  		else {  			*slot = mid; -			if (map_token) -				unmap_extent_buffer(eb, map_token, KM_USER0);  			return 0;  		}  	}  	*slot = low; -	if (map_token) -		unmap_extent_buffer(eb, map_token, KM_USER0);  	return 1;  } @@ -890,7 +896,8 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,  	mid = path->nodes[level]; -	WARN_ON(!path->locks[level]); +	WARN_ON(path->locks[level] != BTRFS_WRITE_LOCK && +		path->locks[level] != BTRFS_WRITE_LOCK_BLOCKING);  	WARN_ON(btrfs_header_generation(mid) != trans->transid);  	orig_ptr = btrfs_node_blockptr(mid, orig_slot); @@ -1228,7 +1235,6 @@ static void reada_for_search(struct btrfs_root *root,  	u32 nr;  	u32 blocksize;  	u32 nscan = 0; -	bool map = true;  	if (level != 1)  		return; @@ -1250,19 +1256,8 @@ static void reada_for_search(struct btrfs_root *root,  	nritems = btrfs_header_nritems(node);  	nr = slot; -	if (node->map_token || path->skip_locking) -		map = false;  	while (1) { -		if (map && !node->map_token) { -			unsigned long offset = btrfs_node_key_ptr_offset(nr); -			map_private_extent_buffer(node, offset, -						  sizeof(struct btrfs_key_ptr), -						  &node->map_token, -						  &node->kaddr, -						  &node->map_start, -						  &node->map_len, KM_USER1); -		}  		if (direction < 0) {  			if (nr == 0)  				break; @@ -1281,11 +1276,6 @@ static void reada_for_search(struct btrfs_root *root,  		if ((search <= target && target - search <= 65536) ||  		    (search > target && search - target <= 65536)) {  			gen = btrfs_node_ptr_generation(node, nr); -			if (map && node->map_token) { -				unmap_extent_buffer(node, node->map_token, -						    KM_USER1); -				node->map_token = NULL; -			}  			readahead_tree_block(root, search, blocksize, gen);  			nread += blocksize;  		} @@ -1293,10 +1283,6 @@ static void reada_for_search(struct btrfs_root *root,  		if ((nread > 65536 || nscan > 32))  			break;  	} -	if (map && node->map_token) { -		unmap_extent_buffer(node, node->map_token, KM_USER1); -		node->map_token = NULL; -	}  }  /* @@ -1409,7 +1395,7 @@ static noinline void unlock_up(struct btrfs_path *path, int level,  		t = path->nodes[i];  		if (i >= lowest_unlock && i > skip_level && path->locks[i]) { -			btrfs_tree_unlock(t); +			btrfs_tree_unlock_rw(t, path->locks[i]);  			path->locks[i] = 0;  		}  	} @@ -1436,7 +1422,7 @@ noinline void btrfs_unlock_up_safe(struct btrfs_path *path, int level)  			continue;  		if (!path->locks[i])  			continue; -		btrfs_tree_unlock(path->nodes[i]); +		btrfs_tree_unlock_rw(path->nodes[i], path->locks[i]);  		path->locks[i] = 0;  	}  } @@ -1485,6 +1471,8 @@ read_block_for_search(struct btrfs_trans_handle *trans,  			 * we can trust our generation number  			 */  			free_extent_buffer(tmp); +			btrfs_set_path_blocking(p); +  			tmp = read_tree_block(root, blocknr, blocksize, gen);  			if (tmp && btrfs_buffer_uptodate(tmp, gen)) {  				*eb_ret = tmp; @@ -1540,20 +1528,27 @@ read_block_for_search(struct btrfs_trans_handle *trans,  static int  setup_nodes_for_search(struct btrfs_trans_handle *trans,  		       struct btrfs_root *root, struct btrfs_path *p, -		       struct extent_buffer *b, int level, int ins_len) +		       struct extent_buffer *b, int level, int ins_len, +		       int *write_lock_level)  {  	int ret;  	if ((p->search_for_split || ins_len > 0) && btrfs_header_nritems(b) >=  	    BTRFS_NODEPTRS_PER_BLOCK(root) - 3) {  		int sret; +		if (*write_lock_level < level + 1) { +			*write_lock_level = level + 1; +			btrfs_release_path(p); +			goto again; +		} +  		sret = reada_for_balance(root, p, level);  		if (sret)  			goto again;  		btrfs_set_path_blocking(p);  		sret = split_node(trans, root, p, level); -		btrfs_clear_path_blocking(p, NULL); +		btrfs_clear_path_blocking(p, NULL, 0);  		BUG_ON(sret > 0);  		if (sret) { @@ -1565,13 +1560,19 @@ setup_nodes_for_search(struct btrfs_trans_handle *trans,  		   BTRFS_NODEPTRS_PER_BLOCK(root) / 2) {  		int sret; +		if (*write_lock_level < level + 1) { +			*write_lock_level = level + 1; +			btrfs_release_path(p); +			goto again; +		} +  		sret = reada_for_balance(root, p, level);  		if (sret)  			goto again;  		btrfs_set_path_blocking(p);  		sret = balance_level(trans, root, p, level); -		btrfs_clear_path_blocking(p, NULL); +		btrfs_clear_path_blocking(p, NULL, 0);  		if (sret) {  			ret = sret; @@ -1615,27 +1616,78 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root  	int err;  	int level;  	int lowest_unlock = 1; +	int root_lock; +	/* everything at write_lock_level or lower must be write locked */ +	int write_lock_level = 0;  	u8 lowest_level = 0;  	lowest_level = p->lowest_level;  	WARN_ON(lowest_level && ins_len > 0);  	WARN_ON(p->nodes[0] != NULL); -	if (ins_len < 0) +	if (ins_len < 0) {  		lowest_unlock = 2; +		/* when we are removing items, we might have to go up to level +		 * two as we update tree pointers  Make sure we keep write +		 * for those levels as well +		 */ +		write_lock_level = 2; +	} else if (ins_len > 0) { +		/* +		 * for inserting items, make sure we have a write lock on +		 * level 1 so we can update keys +		 */ +		write_lock_level = 1; +	} + +	if (!cow) +		write_lock_level = -1; + +	if (cow && (p->keep_locks || p->lowest_level)) +		write_lock_level = BTRFS_MAX_LEVEL; +  again: +	/* +	 * we try very hard to do read locks on the root +	 */ +	root_lock = BTRFS_READ_LOCK; +	level = 0;  	if (p->search_commit_root) { +		/* +		 * the commit roots are read only +		 * so we always do read locks +		 */  		b = root->commit_root;  		extent_buffer_get(b); +		level = btrfs_header_level(b);  		if (!p->skip_locking) -			btrfs_tree_lock(b); +			btrfs_tree_read_lock(b);  	} else { -		if (p->skip_locking) +		if (p->skip_locking) {  			b = btrfs_root_node(root); -		else -			b = btrfs_lock_root_node(root); +			level = btrfs_header_level(b); +		} else { +			/* we don't know the level of the root node +			 * until we actually have it read locked +			 */ +			b = btrfs_read_lock_root_node(root); +			level = btrfs_header_level(b); +			if (level <= write_lock_level) { +				/* whoops, must trade for write lock */ +				btrfs_tree_read_unlock(b); +				free_extent_buffer(b); +				b = btrfs_lock_root_node(root); +				root_lock = BTRFS_WRITE_LOCK; + +				/* the level might have changed, check again */ +				level = btrfs_header_level(b); +			} +		}  	} +	p->nodes[level] = b; +	if (!p->skip_locking) +		p->locks[level] = root_lock;  	while (b) {  		level = btrfs_header_level(b); @@ -1644,10 +1696,6 @@ again:  		 * setup the path here so we can release it under lock  		 * contention with the cow code  		 */ -		p->nodes[level] = b; -		if (!p->skip_locking) -			p->locks[level] = 1; -  		if (cow) {  			/*  			 * if we don't really need to cow this block @@ -1659,6 +1707,16 @@ again:  			btrfs_set_path_blocking(p); +			/* +			 * must have write locks on this node and the +			 * parent +			 */ +			if (level + 1 > write_lock_level) { +				write_lock_level = level + 1; +				btrfs_release_path(p); +				goto again; +			} +  			err = btrfs_cow_block(trans, root, b,  					      p->nodes[level + 1],  					      p->slots[level + 1], &b); @@ -1671,10 +1729,7 @@ cow_done:  		BUG_ON(!cow && ins_len);  		p->nodes[level] = b; -		if (!p->skip_locking) -			p->locks[level] = 1; - -		btrfs_clear_path_blocking(p, NULL); +		btrfs_clear_path_blocking(p, NULL, 0);  		/*  		 * we have a lock on b and as long as we aren't changing @@ -1700,7 +1755,7 @@ cow_done:  			}  			p->slots[level] = slot;  			err = setup_nodes_for_search(trans, root, p, b, level, -						     ins_len); +					     ins_len, &write_lock_level);  			if (err == -EAGAIN)  				goto again;  			if (err) { @@ -1710,6 +1765,19 @@ cow_done:  			b = p->nodes[level];  			slot = p->slots[level]; +			/* +			 * slot 0 is special, if we change the key +			 * we have to update the parent pointer +			 * which means we must have a write lock +			 * on the parent +			 */ +			if (slot == 0 && cow && +			    write_lock_level < level + 1) { +				write_lock_level = level + 1; +				btrfs_release_path(p); +				goto again; +			} +  			unlock_up(p, level, lowest_unlock);  			if (level == lowest_level) { @@ -1728,23 +1796,42 @@ cow_done:  			}  			if (!p->skip_locking) { -				btrfs_clear_path_blocking(p, NULL); -				err = btrfs_try_spin_lock(b); - -				if (!err) { -					btrfs_set_path_blocking(p); -					btrfs_tree_lock(b); -					btrfs_clear_path_blocking(p, b); +				level = btrfs_header_level(b); +				if (level <= write_lock_level) { +					err = btrfs_try_tree_write_lock(b); +					if (!err) { +						btrfs_set_path_blocking(p); +						btrfs_tree_lock(b); +						btrfs_clear_path_blocking(p, b, +								  BTRFS_WRITE_LOCK); +					} +					p->locks[level] = BTRFS_WRITE_LOCK; +				} else { +					err = btrfs_try_tree_read_lock(b); +					if (!err) { +						btrfs_set_path_blocking(p); +						btrfs_tree_read_lock(b); +						btrfs_clear_path_blocking(p, b, +								  BTRFS_READ_LOCK); +					} +					p->locks[level] = BTRFS_READ_LOCK;  				} +				p->nodes[level] = b;  			}  		} else {  			p->slots[level] = slot;  			if (ins_len > 0 &&  			    btrfs_leaf_free_space(root, b) < ins_len) { +				if (write_lock_level < 1) { +					write_lock_level = 1; +					btrfs_release_path(p); +					goto again; +				} +  				btrfs_set_path_blocking(p);  				err = split_leaf(trans, root, key,  						 p, ins_len, ret == 0); -				btrfs_clear_path_blocking(p, NULL); +				btrfs_clear_path_blocking(p, NULL, 0);  				BUG_ON(err > 0);  				if (err) { @@ -2025,7 +2112,7 @@ static noinline int insert_new_root(struct btrfs_trans_handle *trans,  	add_root_to_dirty_list(root);  	extent_buffer_get(c);  	path->nodes[level] = c; -	path->locks[level] = 1; +	path->locks[level] = BTRFS_WRITE_LOCK;  	path->slots[level] = 0;  	return 0;  } @@ -2253,14 +2340,6 @@ static noinline int __push_leaf_right(struct btrfs_trans_handle *trans,  		if (path->slots[0] == i)  			push_space += data_size; -		if (!left->map_token) { -			map_extent_buffer(left, (unsigned long)item, -					sizeof(struct btrfs_item), -					&left->map_token, &left->kaddr, -					&left->map_start, &left->map_len, -					KM_USER1); -		} -  		this_item_size = btrfs_item_size(left, item);  		if (this_item_size + sizeof(*item) + push_space > free_space)  			break; @@ -2271,10 +2350,6 @@ static noinline int __push_leaf_right(struct btrfs_trans_handle *trans,  			break;  		i--;  	} -	if (left->map_token) { -		unmap_extent_buffer(left, left->map_token, KM_USER1); -		left->map_token = NULL; -	}  	if (push_items == 0)  		goto out_unlock; @@ -2316,21 +2391,10 @@ static noinline int __push_leaf_right(struct btrfs_trans_handle *trans,  	push_space = BTRFS_LEAF_DATA_SIZE(root);  	for (i = 0; i < right_nritems; i++) {  		item = btrfs_item_nr(right, i); -		if (!right->map_token) { -			map_extent_buffer(right, (unsigned long)item, -					sizeof(struct btrfs_item), -					&right->map_token, &right->kaddr, -					&right->map_start, &right->map_len, -					KM_USER1); -		}  		push_space -= btrfs_item_size(right, item);  		btrfs_set_item_offset(right, item, push_space);  	} -	if (right->map_token) { -		unmap_extent_buffer(right, right->map_token, KM_USER1); -		right->map_token = NULL; -	}  	left_nritems -= push_items;  	btrfs_set_header_nritems(left, left_nritems); @@ -2467,13 +2531,6 @@ static noinline int __push_leaf_left(struct btrfs_trans_handle *trans,  	for (i = 0; i < nr; i++) {  		item = btrfs_item_nr(right, i); -		if (!right->map_token) { -			map_extent_buffer(right, (unsigned long)item, -					sizeof(struct btrfs_item), -					&right->map_token, &right->kaddr, -					&right->map_start, &right->map_len, -					KM_USER1); -		}  		if (!empty && push_items > 0) {  			if (path->slots[0] < i) @@ -2496,11 +2553,6 @@ static noinline int __push_leaf_left(struct btrfs_trans_handle *trans,  		push_space += this_item_size + sizeof(*item);  	} -	if (right->map_token) { -		unmap_extent_buffer(right, right->map_token, KM_USER1); -		right->map_token = NULL; -	} -  	if (push_items == 0) {  		ret = 1;  		goto out; @@ -2530,23 +2582,12 @@ static noinline int __push_leaf_left(struct btrfs_trans_handle *trans,  		u32 ioff;  		item = btrfs_item_nr(left, i); -		if (!left->map_token) { -			map_extent_buffer(left, (unsigned long)item, -					sizeof(struct btrfs_item), -					&left->map_token, &left->kaddr, -					&left->map_start, &left->map_len, -					KM_USER1); -		}  		ioff = btrfs_item_offset(left, item);  		btrfs_set_item_offset(left, item,  		      ioff - (BTRFS_LEAF_DATA_SIZE(root) - old_left_item_size));  	}  	btrfs_set_header_nritems(left, old_left_nritems + push_items); -	if (left->map_token) { -		unmap_extent_buffer(left, left->map_token, KM_USER1); -		left->map_token = NULL; -	}  	/* fixup right node */  	if (push_items > right_nritems) { @@ -2574,21 +2615,9 @@ static noinline int __push_leaf_left(struct btrfs_trans_handle *trans,  	for (i = 0; i < right_nritems; i++) {  		item = btrfs_item_nr(right, i); -		if (!right->map_token) { -			map_extent_buffer(right, (unsigned long)item, -					sizeof(struct btrfs_item), -					&right->map_token, &right->kaddr, -					&right->map_start, &right->map_len, -					KM_USER1); -		} -  		push_space = push_space - btrfs_item_size(right, item);  		btrfs_set_item_offset(right, item, push_space);  	} -	if (right->map_token) { -		unmap_extent_buffer(right, right->map_token, KM_USER1); -		right->map_token = NULL; -	}  	btrfs_mark_buffer_dirty(left);  	if (right_nritems) @@ -2729,23 +2758,10 @@ static noinline int copy_for_split(struct btrfs_trans_handle *trans,  		struct btrfs_item *item = btrfs_item_nr(right, i);  		u32 ioff; -		if (!right->map_token) { -			map_extent_buffer(right, (unsigned long)item, -					sizeof(struct btrfs_item), -					&right->map_token, &right->kaddr, -					&right->map_start, &right->map_len, -					KM_USER1); -		} -  		ioff = btrfs_item_offset(right, item);  		btrfs_set_item_offset(right, item, ioff + rt_data_off);  	} -	if (right->map_token) { -		unmap_extent_buffer(right, right->map_token, KM_USER1); -		right->map_token = NULL; -	} -  	btrfs_set_header_nritems(l, mid);  	ret = 0;  	btrfs_item_key(right, &disk_key, 0); @@ -3264,23 +3280,10 @@ int btrfs_truncate_item(struct btrfs_trans_handle *trans,  		u32 ioff;  		item = btrfs_item_nr(leaf, i); -		if (!leaf->map_token) { -			map_extent_buffer(leaf, (unsigned long)item, -					sizeof(struct btrfs_item), -					&leaf->map_token, &leaf->kaddr, -					&leaf->map_start, &leaf->map_len, -					KM_USER1); -		} -  		ioff = btrfs_item_offset(leaf, item);  		btrfs_set_item_offset(leaf, item, ioff + size_diff);  	} -	if (leaf->map_token) { -		unmap_extent_buffer(leaf, leaf->map_token, KM_USER1); -		leaf->map_token = NULL; -	} -  	/* shift the data */  	if (from_end) {  		memmove_extent_buffer(leaf, btrfs_leaf_data(leaf) + @@ -3377,22 +3380,10 @@ int btrfs_extend_item(struct btrfs_trans_handle *trans,  		u32 ioff;  		item = btrfs_item_nr(leaf, i); -		if (!leaf->map_token) { -			map_extent_buffer(leaf, (unsigned long)item, -					sizeof(struct btrfs_item), -					&leaf->map_token, &leaf->kaddr, -					&leaf->map_start, &leaf->map_len, -					KM_USER1); -		}  		ioff = btrfs_item_offset(leaf, item);  		btrfs_set_item_offset(leaf, item, ioff - data_size);  	} -	if (leaf->map_token) { -		unmap_extent_buffer(leaf, leaf->map_token, KM_USER1); -		leaf->map_token = NULL; -	} -  	/* shift the data */  	memmove_extent_buffer(leaf, btrfs_leaf_data(leaf) +  		      data_end - data_size, btrfs_leaf_data(leaf) + @@ -3494,27 +3485,13 @@ int btrfs_insert_some_items(struct btrfs_trans_handle *trans,  		 * item0..itemN ... dataN.offset..dataN.size .. data0.size  		 */  		/* first correct the data pointers */ -		WARN_ON(leaf->map_token);  		for (i = slot; i < nritems; i++) {  			u32 ioff;  			item = btrfs_item_nr(leaf, i); -			if (!leaf->map_token) { -				map_extent_buffer(leaf, (unsigned long)item, -					sizeof(struct btrfs_item), -					&leaf->map_token, &leaf->kaddr, -					&leaf->map_start, &leaf->map_len, -					KM_USER1); -			} -  			ioff = btrfs_item_offset(leaf, item);  			btrfs_set_item_offset(leaf, item, ioff - total_data);  		} -		if (leaf->map_token) { -			unmap_extent_buffer(leaf, leaf->map_token, KM_USER1); -			leaf->map_token = NULL; -		} -  		/* shift the items */  		memmove_extent_buffer(leaf, btrfs_item_nr_offset(slot + nr),  			      btrfs_item_nr_offset(slot), @@ -3608,27 +3585,13 @@ int setup_items_for_insert(struct btrfs_trans_handle *trans,  		 * item0..itemN ... dataN.offset..dataN.size .. data0.size  		 */  		/* first correct the data pointers */ -		WARN_ON(leaf->map_token);  		for (i = slot; i < nritems; i++) {  			u32 ioff;  			item = btrfs_item_nr(leaf, i); -			if (!leaf->map_token) { -				map_extent_buffer(leaf, (unsigned long)item, -					sizeof(struct btrfs_item), -					&leaf->map_token, &leaf->kaddr, -					&leaf->map_start, &leaf->map_len, -					KM_USER1); -			} -  			ioff = btrfs_item_offset(leaf, item);  			btrfs_set_item_offset(leaf, item, ioff - total_data);  		} -		if (leaf->map_token) { -			unmap_extent_buffer(leaf, leaf->map_token, KM_USER1); -			leaf->map_token = NULL; -		} -  		/* shift the items */  		memmove_extent_buffer(leaf, btrfs_item_nr_offset(slot + nr),  			      btrfs_item_nr_offset(slot), @@ -3840,22 +3803,10 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,  			u32 ioff;  			item = btrfs_item_nr(leaf, i); -			if (!leaf->map_token) { -				map_extent_buffer(leaf, (unsigned long)item, -					sizeof(struct btrfs_item), -					&leaf->map_token, &leaf->kaddr, -					&leaf->map_start, &leaf->map_len, -					KM_USER1); -			}  			ioff = btrfs_item_offset(leaf, item);  			btrfs_set_item_offset(leaf, item, ioff + dsize);  		} -		if (leaf->map_token) { -			unmap_extent_buffer(leaf, leaf->map_token, KM_USER1); -			leaf->map_token = NULL; -		} -  		memmove_extent_buffer(leaf, btrfs_item_nr_offset(slot),  			      btrfs_item_nr_offset(slot + nr),  			      sizeof(struct btrfs_item) * @@ -4004,11 +3955,11 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,  	WARN_ON(!path->keep_locks);  again: -	cur = btrfs_lock_root_node(root); +	cur = btrfs_read_lock_root_node(root);  	level = btrfs_header_level(cur);  	WARN_ON(path->nodes[level]);  	path->nodes[level] = cur; -	path->locks[level] = 1; +	path->locks[level] = BTRFS_READ_LOCK;  	if (btrfs_header_generation(cur) < min_trans) {  		ret = 1; @@ -4098,12 +4049,12 @@ find_next_key:  		cur = read_node_slot(root, cur, slot);  		BUG_ON(!cur); -		btrfs_tree_lock(cur); +		btrfs_tree_read_lock(cur); -		path->locks[level - 1] = 1; +		path->locks[level - 1] = BTRFS_READ_LOCK;  		path->nodes[level - 1] = cur;  		unlock_up(path, level, 1); -		btrfs_clear_path_blocking(path, NULL); +		btrfs_clear_path_blocking(path, NULL, 0);  	}  out:  	if (ret == 0) @@ -4218,30 +4169,21 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path)  	u32 nritems;  	int ret;  	int old_spinning = path->leave_spinning; -	int force_blocking = 0; +	int next_rw_lock = 0;  	nritems = btrfs_header_nritems(path->nodes[0]);  	if (nritems == 0)  		return 1; -	/* -	 * we take the blocks in an order that upsets lockdep.  Using -	 * blocking mode is the only way around it. -	 */ -#ifdef CONFIG_DEBUG_LOCK_ALLOC -	force_blocking = 1; -#endif -  	btrfs_item_key_to_cpu(path->nodes[0], &key, nritems - 1);  again:  	level = 1;  	next = NULL; +	next_rw_lock = 0;  	btrfs_release_path(path);  	path->keep_locks = 1; - -	if (!force_blocking) -		path->leave_spinning = 1; +	path->leave_spinning = 1;  	ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);  	path->keep_locks = 0; @@ -4281,11 +4223,12 @@ again:  		}  		if (next) { -			btrfs_tree_unlock(next); +			btrfs_tree_unlock_rw(next, next_rw_lock);  			free_extent_buffer(next);  		}  		next = c; +		next_rw_lock = path->locks[level];  		ret = read_block_for_search(NULL, root, path, &next, level,  					    slot, &key);  		if (ret == -EAGAIN) @@ -4297,15 +4240,14 @@ again:  		}  		if (!path->skip_locking) { -			ret = btrfs_try_spin_lock(next); +			ret = btrfs_try_tree_read_lock(next);  			if (!ret) {  				btrfs_set_path_blocking(path); -				btrfs_tree_lock(next); -				if (!force_blocking) -					btrfs_clear_path_blocking(path, next); +				btrfs_tree_read_lock(next); +				btrfs_clear_path_blocking(path, next, +							  BTRFS_READ_LOCK);  			} -			if (force_blocking) -				btrfs_set_lock_blocking(next); +			next_rw_lock = BTRFS_READ_LOCK;  		}  		break;  	} @@ -4314,14 +4256,13 @@ again:  		level--;  		c = path->nodes[level];  		if (path->locks[level]) -			btrfs_tree_unlock(c); +			btrfs_tree_unlock_rw(c, path->locks[level]);  		free_extent_buffer(c);  		path->nodes[level] = next;  		path->slots[level] = 0;  		if (!path->skip_locking) -			path->locks[level] = 1; - +			path->locks[level] = next_rw_lock;  		if (!level)  			break; @@ -4336,16 +4277,14 @@ again:  		}  		if (!path->skip_locking) { -			btrfs_assert_tree_locked(path->nodes[level]); -			ret = btrfs_try_spin_lock(next); +			ret = btrfs_try_tree_read_lock(next);  			if (!ret) {  				btrfs_set_path_blocking(path); -				btrfs_tree_lock(next); -				if (!force_blocking) -					btrfs_clear_path_blocking(path, next); +				btrfs_tree_read_lock(next); +				btrfs_clear_path_blocking(path, next, +							  BTRFS_READ_LOCK);  			} -			if (force_blocking) -				btrfs_set_lock_blocking(next); +			next_rw_lock = BTRFS_READ_LOCK;  		}  	}  	ret = 0;  |