diff options
Diffstat (limited to 'fs/btrfs/ctree.c')
| -rw-r--r-- | fs/btrfs/ctree.c | 121 | 
1 files changed, 68 insertions, 53 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 60a45f3a4e9..3fdcc0512d3 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -557,19 +557,7 @@ static int comp_keys(struct btrfs_disk_key *disk, struct btrfs_key *k2)  	btrfs_disk_key_to_cpu(&k1, disk); -	if (k1.objectid > k2->objectid) -		return 1; -	if (k1.objectid < k2->objectid) -		return -1; -	if (k1.type > k2->type) -		return 1; -	if (k1.type < k2->type) -		return -1; -	if (k1.offset > k2->offset) -		return 1; -	if (k1.offset < k2->offset) -		return -1; -	return 0; +	return btrfs_comp_cpu_keys(&k1, k2);  }  /* @@ -1052,9 +1040,6 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,  	    BTRFS_NODEPTRS_PER_BLOCK(root) / 4)  		return 0; -	if (btrfs_header_nritems(mid) > 2) -		return 0; -  	if (btrfs_header_nritems(mid) < 2)  		err_on_enospc = 1; @@ -1701,6 +1686,7 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root  	struct extent_buffer *b;  	int slot;  	int ret; +	int err;  	int level;  	int lowest_unlock = 1;  	u8 lowest_level = 0; @@ -1737,8 +1723,6 @@ again:  			p->locks[level] = 1;  		if (cow) { -			int wret; -  			/*  			 * if we don't really need to cow this block  			 * then we don't want to set the path blocking, @@ -1749,12 +1733,12 @@ again:  			btrfs_set_path_blocking(p); -			wret = btrfs_cow_block(trans, root, b, -					       p->nodes[level + 1], -					       p->slots[level + 1], &b); -			if (wret) { +			err = btrfs_cow_block(trans, root, b, +					      p->nodes[level + 1], +					      p->slots[level + 1], &b); +			if (err) {  				free_extent_buffer(b); -				ret = wret; +				ret = err;  				goto done;  			}  		} @@ -1793,41 +1777,45 @@ cow_done:  		ret = bin_search(b, key, level, &slot);  		if (level != 0) { -			if (ret && slot > 0) +			int dec = 0; +			if (ret && slot > 0) { +				dec = 1;  				slot -= 1; +			}  			p->slots[level] = slot; -			ret = setup_nodes_for_search(trans, root, p, b, level, +			err = setup_nodes_for_search(trans, root, p, b, level,  						     ins_len); -			if (ret == -EAGAIN) +			if (err == -EAGAIN)  				goto again; -			else if (ret) +			if (err) { +				ret = err;  				goto done; +			}  			b = p->nodes[level];  			slot = p->slots[level];  			unlock_up(p, level, lowest_unlock); -			/* this is only true while dropping a snapshot */  			if (level == lowest_level) { -				ret = 0; +				if (dec) +					p->slots[level]++;  				goto done;  			} -			ret = read_block_for_search(trans, root, p, +			err = read_block_for_search(trans, root, p,  						    &b, level, slot, key); -			if (ret == -EAGAIN) +			if (err == -EAGAIN)  				goto again; - -			if (ret == -EIO) +			if (err) { +				ret = err;  				goto done; +			}  			if (!p->skip_locking) { -				int lret; -  				btrfs_clear_path_blocking(p, NULL); -				lret = btrfs_try_spin_lock(b); +				err = btrfs_try_spin_lock(b); -				if (!lret) { +				if (!err) {  					btrfs_set_path_blocking(p);  					btrfs_tree_lock(b);  					btrfs_clear_path_blocking(p, b); @@ -1837,16 +1825,14 @@ cow_done:  			p->slots[level] = slot;  			if (ins_len > 0 &&  			    btrfs_leaf_free_space(root, b) < ins_len) { -				int sret; -  				btrfs_set_path_blocking(p); -				sret = split_leaf(trans, root, key, -						      p, ins_len, ret == 0); +				err = split_leaf(trans, root, key, +						 p, ins_len, ret == 0);  				btrfs_clear_path_blocking(p, NULL); -				BUG_ON(sret > 0); -				if (sret) { -					ret = sret; +				BUG_ON(err > 0); +				if (err) { +					ret = err;  					goto done;  				}  			} @@ -3807,7 +3793,7 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,  		}  		/* delete the leaf if it is mostly empty */ -		if (used < BTRFS_LEAF_DATA_SIZE(root) / 2) { +		if (used < BTRFS_LEAF_DATA_SIZE(root) / 3) {  			/* push_leaf_left fixes the path.  			 * make sure the path still points to our leaf  			 * for possible call to del_ptr below @@ -4042,10 +4028,9 @@ out:   * calling this function.   */  int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path, -			struct btrfs_key *key, int lowest_level, +			struct btrfs_key *key, int level,  			int cache_only, u64 min_trans)  { -	int level = lowest_level;  	int slot;  	struct extent_buffer *c; @@ -4058,11 +4043,40 @@ int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path,  		c = path->nodes[level];  next:  		if (slot >= btrfs_header_nritems(c)) { -			level++; -			if (level == BTRFS_MAX_LEVEL) +			int ret; +			int orig_lowest; +			struct btrfs_key cur_key; +			if (level + 1 >= BTRFS_MAX_LEVEL || +			    !path->nodes[level + 1])  				return 1; -			continue; + +			if (path->locks[level + 1]) { +				level++; +				continue; +			} + +			slot = btrfs_header_nritems(c) - 1; +			if (level == 0) +				btrfs_item_key_to_cpu(c, &cur_key, slot); +			else +				btrfs_node_key_to_cpu(c, &cur_key, slot); + +			orig_lowest = path->lowest_level; +			btrfs_release_path(root, path); +			path->lowest_level = level; +			ret = btrfs_search_slot(NULL, root, &cur_key, path, +						0, 0); +			path->lowest_level = orig_lowest; +			if (ret < 0) +				return ret; + +			c = path->nodes[level]; +			slot = path->slots[level]; +			if (ret == 0) +				slot++; +			goto next;  		} +  		if (level == 0)  			btrfs_item_key_to_cpu(c, key, slot);  		else { @@ -4146,7 +4160,8 @@ again:  	 * advance the path if there are now more items available.  	 */  	if (nritems > 0 && path->slots[0] < nritems - 1) { -		path->slots[0]++; +		if (ret == 0) +			path->slots[0]++;  		ret = 0;  		goto done;  	} @@ -4278,10 +4293,10 @@ int btrfs_previous_item(struct btrfs_root *root,  			path->slots[0]--;  		btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); -		if (found_key.type == type) -			return 0;  		if (found_key.objectid < min_objectid)  			break; +		if (found_key.type == type) +			return 0;  		if (found_key.objectid == min_objectid &&  		    found_key.type < type)  			break;  |