diff options
author | Chris Mason <chris.mason@oracle.com> | 2009-04-03 10:14:18 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2009-04-03 10:14:18 -0400 |
commit | 8e73f275011b3264a87339fd9f1690e944e381c9 (patch) | |
tree | 865900b191ed0e01f10d2f87e28c9e2ed56e5722 /fs/btrfs/ctree.c | |
parent | c8c42864f6193638eed136e0243f426a0b7f4bc2 (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.c | 88 |
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: | |||
4127 | int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path) | 4127 | int 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); | ||
4152 | again: | ||
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; | ||
4219 | done: | 4257 | done: |
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 | /* |