aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/ctree.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2009-04-03 10:14:18 -0400
committerChris Mason <chris.mason@oracle.com>2009-04-03 10:14:18 -0400
commit8e73f275011b3264a87339fd9f1690e944e381c9 (patch)
tree865900b191ed0e01f10d2f87e28c9e2ed56e5722 /fs/btrfs/ctree.c
parentc8c42864f6193638eed136e0243f426a0b7f4bc2 (diff)
Btrfs: Optimize locking in btrfs_next_leaf()
btrfs_next_leaf was using blocking locks when it could have been using faster spinning ones instead. This adds a few extra checks around the pieces that block and switches over to spinning locks. Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/ctree.c')
-rw-r--r--fs/btrfs/ctree.c88
1 files changed, 65 insertions, 23 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 271b05e507d7..b8082762ca78 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -4127,28 +4127,44 @@ next:
4127int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path) 4127int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path)
4128{ 4128{
4129 int slot; 4129 int slot;
4130 int level = 1; 4130 int level;
4131 struct extent_buffer *c; 4131 struct extent_buffer *c;
4132 struct extent_buffer *next = NULL; 4132 struct extent_buffer *next;
4133 struct btrfs_key key; 4133 struct btrfs_key key;
4134 u32 nritems; 4134 u32 nritems;
4135 int ret; 4135 int ret;
4136 int old_spinning = path->leave_spinning;
4137 int force_blocking = 0;
4136 4138
4137 nritems = btrfs_header_nritems(path->nodes[0]); 4139 nritems = btrfs_header_nritems(path->nodes[0]);
4138 if (nritems == 0) 4140 if (nritems == 0)
4139 return 1; 4141 return 1;
4140 4142
4141 btrfs_item_key_to_cpu(path->nodes[0], &key, nritems - 1); 4143 /*
4144 * we take the blocks in an order that upsets lockdep. Using
4145 * blocking mode is the only way around it.
4146 */
4147#ifdef CONFIG_DEBUG_LOCK_ALLOC
4148 force_blocking = 1;
4149#endif
4142 4150
4151 btrfs_item_key_to_cpu(path->nodes[0], &key, nritems - 1);
4152again:
4153 level = 1;
4154 next = NULL;
4143 btrfs_release_path(root, path); 4155 btrfs_release_path(root, path);
4156
4144 path->keep_locks = 1; 4157 path->keep_locks = 1;
4158
4159 if (!force_blocking)
4160 path->leave_spinning = 1;
4161
4145 ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); 4162 ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
4146 path->keep_locks = 0; 4163 path->keep_locks = 0;
4147 4164
4148 if (ret < 0) 4165 if (ret < 0)
4149 return ret; 4166 return ret;
4150 4167
4151 btrfs_set_path_blocking(path);
4152 nritems = btrfs_header_nritems(path->nodes[0]); 4168 nritems = btrfs_header_nritems(path->nodes[0]);
4153 /* 4169 /*
4154 * by releasing the path above we dropped all our locks. A balance 4170 * by releasing the path above we dropped all our locks. A balance
@@ -4158,19 +4174,24 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path)
4158 */ 4174 */
4159 if (nritems > 0 && path->slots[0] < nritems - 1) { 4175 if (nritems > 0 && path->slots[0] < nritems - 1) {
4160 path->slots[0]++; 4176 path->slots[0]++;
4177 ret = 0;
4161 goto done; 4178 goto done;
4162 } 4179 }
4163 4180
4164 while (level < BTRFS_MAX_LEVEL) { 4181 while (level < BTRFS_MAX_LEVEL) {
4165 if (!path->nodes[level]) 4182 if (!path->nodes[level]) {
4166 return 1; 4183 ret = 1;
4184 goto done;
4185 }
4167 4186
4168 slot = path->slots[level] + 1; 4187 slot = path->slots[level] + 1;
4169 c = path->nodes[level]; 4188 c = path->nodes[level];
4170 if (slot >= btrfs_header_nritems(c)) { 4189 if (slot >= btrfs_header_nritems(c)) {
4171 level++; 4190 level++;
4172 if (level == BTRFS_MAX_LEVEL) 4191 if (level == BTRFS_MAX_LEVEL) {
4173 return 1; 4192 ret = 1;
4193 goto done;
4194 }
4174 continue; 4195 continue;
4175 } 4196 }
4176 4197
@@ -4179,16 +4200,22 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path)
4179 free_extent_buffer(next); 4200 free_extent_buffer(next);
4180 } 4201 }
4181 4202
4182 /* the path was set to blocking above */ 4203 next = c;
4183 if (level == 1 && (path->locks[1] || path->skip_locking) && 4204 ret = read_block_for_search(NULL, root, path, &next, level,
4184 path->reada) 4205 slot, &key);
4185 reada_for_search(root, path, level, slot, 0); 4206 if (ret == -EAGAIN)
4207 goto again;
4186 4208
4187 next = read_node_slot(root, c, slot);
4188 if (!path->skip_locking) { 4209 if (!path->skip_locking) {
4189 btrfs_assert_tree_locked(c); 4210 ret = btrfs_try_spin_lock(next);
4190 btrfs_tree_lock(next); 4211 if (!ret) {
4191 btrfs_set_lock_blocking(next); 4212 btrfs_set_path_blocking(path);
4213 btrfs_tree_lock(next);
4214 if (!force_blocking)
4215 btrfs_clear_path_blocking(path, next);
4216 }
4217 if (force_blocking)
4218 btrfs_set_lock_blocking(next);
4192 } 4219 }
4193 break; 4220 break;
4194 } 4221 }
@@ -4198,27 +4225,42 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path)
4198 c = path->nodes[level]; 4225 c = path->nodes[level];
4199 if (path->locks[level]) 4226 if (path->locks[level])
4200 btrfs_tree_unlock(c); 4227 btrfs_tree_unlock(c);
4228
4201 free_extent_buffer(c); 4229 free_extent_buffer(c);
4202 path->nodes[level] = next; 4230 path->nodes[level] = next;
4203 path->slots[level] = 0; 4231 path->slots[level] = 0;
4204 if (!path->skip_locking) 4232 if (!path->skip_locking)
4205 path->locks[level] = 1; 4233 path->locks[level] = 1;
4234
4206 if (!level) 4235 if (!level)
4207 break; 4236 break;
4208 4237
4209 btrfs_set_path_blocking(path); 4238 ret = read_block_for_search(NULL, root, path, &next, level,
4210 if (level == 1 && path->locks[1] && path->reada) 4239 0, &key);
4211 reada_for_search(root, path, level, slot, 0); 4240 if (ret == -EAGAIN)
4212 next = read_node_slot(root, next, 0); 4241 goto again;
4242
4213 if (!path->skip_locking) { 4243 if (!path->skip_locking) {
4214 btrfs_assert_tree_locked(path->nodes[level]); 4244 btrfs_assert_tree_locked(path->nodes[level]);
4215 btrfs_tree_lock(next); 4245 ret = btrfs_try_spin_lock(next);
4216 btrfs_set_lock_blocking(next); 4246 if (!ret) {
4247 btrfs_set_path_blocking(path);
4248 btrfs_tree_lock(next);
4249 if (!force_blocking)
4250 btrfs_clear_path_blocking(path, next);
4251 }
4252 if (force_blocking)
4253 btrfs_set_lock_blocking(next);
4217 } 4254 }
4218 } 4255 }
4256 ret = 0;
4219done: 4257done:
4220 unlock_up(path, 0, 1); 4258 unlock_up(path, 0, 1);
4221 return 0; 4259 path->leave_spinning = old_spinning;
4260 if (!old_spinning)
4261 btrfs_set_path_blocking(path);
4262
4263 return ret;
4222} 4264}
4223 4265
4224/* 4266/*