diff options
Diffstat (limited to 'fs/btrfs/locking.c')
-rw-r--r-- | fs/btrfs/locking.c | 42 |
1 files changed, 19 insertions, 23 deletions
diff --git a/fs/btrfs/locking.c b/fs/btrfs/locking.c index 9ebe9385129b..1c36e5cd8f55 100644 --- a/fs/btrfs/locking.c +++ b/fs/btrfs/locking.c | |||
@@ -25,21 +25,10 @@ | |||
25 | #include "extent_io.h" | 25 | #include "extent_io.h" |
26 | #include "locking.h" | 26 | #include "locking.h" |
27 | 27 | ||
28 | /* | ||
29 | * btrfs_header_level() isn't free, so don't call it when lockdep isn't | ||
30 | * on | ||
31 | */ | ||
32 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | ||
33 | static inline void spin_nested(struct extent_buffer *eb) | ||
34 | { | ||
35 | spin_lock_nested(&eb->lock, BTRFS_MAX_LEVEL - btrfs_header_level(eb)); | ||
36 | } | ||
37 | #else | ||
38 | static inline void spin_nested(struct extent_buffer *eb) | 28 | static inline void spin_nested(struct extent_buffer *eb) |
39 | { | 29 | { |
40 | spin_lock(&eb->lock); | 30 | spin_lock(&eb->lock); |
41 | } | 31 | } |
42 | #endif | ||
43 | 32 | ||
44 | /* | 33 | /* |
45 | * Setting a lock to blocking will drop the spinlock and set the | 34 | * Setting a lock to blocking will drop the spinlock and set the |
@@ -71,8 +60,8 @@ void btrfs_clear_lock_blocking(struct extent_buffer *eb) | |||
71 | 60 | ||
72 | /* | 61 | /* |
73 | * unfortunately, many of the places that currently set a lock to blocking | 62 | * unfortunately, many of the places that currently set a lock to blocking |
74 | * don't end up blocking for every long, and often they don't block | 63 | * don't end up blocking for very long, and often they don't block |
75 | * at all. For a dbench 50 run, if we don't spin one the blocking bit | 64 | * at all. For a dbench 50 run, if we don't spin on the blocking bit |
76 | * at all, the context switch rate can jump up to 400,000/sec or more. | 65 | * at all, the context switch rate can jump up to 400,000/sec or more. |
77 | * | 66 | * |
78 | * So, we're still stuck with this crummy spin on the blocking bit, | 67 | * So, we're still stuck with this crummy spin on the blocking bit, |
@@ -82,12 +71,13 @@ void btrfs_clear_lock_blocking(struct extent_buffer *eb) | |||
82 | static int btrfs_spin_on_block(struct extent_buffer *eb) | 71 | static int btrfs_spin_on_block(struct extent_buffer *eb) |
83 | { | 72 | { |
84 | int i; | 73 | int i; |
74 | |||
85 | for (i = 0; i < 512; i++) { | 75 | for (i = 0; i < 512; i++) { |
86 | cpu_relax(); | ||
87 | if (!test_bit(EXTENT_BUFFER_BLOCKING, &eb->bflags)) | 76 | if (!test_bit(EXTENT_BUFFER_BLOCKING, &eb->bflags)) |
88 | return 1; | 77 | return 1; |
89 | if (need_resched()) | 78 | if (need_resched()) |
90 | break; | 79 | break; |
80 | cpu_relax(); | ||
91 | } | 81 | } |
92 | return 0; | 82 | return 0; |
93 | } | 83 | } |
@@ -106,13 +96,15 @@ int btrfs_try_spin_lock(struct extent_buffer *eb) | |||
106 | { | 96 | { |
107 | int i; | 97 | int i; |
108 | 98 | ||
109 | spin_nested(eb); | 99 | if (btrfs_spin_on_block(eb)) { |
110 | if (!test_bit(EXTENT_BUFFER_BLOCKING, &eb->bflags)) | 100 | spin_nested(eb); |
111 | return 1; | 101 | if (!test_bit(EXTENT_BUFFER_BLOCKING, &eb->bflags)) |
112 | spin_unlock(&eb->lock); | 102 | return 1; |
113 | 103 | spin_unlock(&eb->lock); | |
104 | } | ||
114 | /* spin for a bit on the BLOCKING flag */ | 105 | /* spin for a bit on the BLOCKING flag */ |
115 | for (i = 0; i < 2; i++) { | 106 | for (i = 0; i < 2; i++) { |
107 | cpu_relax(); | ||
116 | if (!btrfs_spin_on_block(eb)) | 108 | if (!btrfs_spin_on_block(eb)) |
117 | break; | 109 | break; |
118 | 110 | ||
@@ -159,6 +151,9 @@ int btrfs_tree_lock(struct extent_buffer *eb) | |||
159 | DEFINE_WAIT(wait); | 151 | DEFINE_WAIT(wait); |
160 | wait.func = btrfs_wake_function; | 152 | wait.func = btrfs_wake_function; |
161 | 153 | ||
154 | if (!btrfs_spin_on_block(eb)) | ||
155 | goto sleep; | ||
156 | |||
162 | while(1) { | 157 | while(1) { |
163 | spin_nested(eb); | 158 | spin_nested(eb); |
164 | 159 | ||
@@ -176,9 +171,10 @@ int btrfs_tree_lock(struct extent_buffer *eb) | |||
176 | * spin for a bit, and if the blocking flag goes away, | 171 | * spin for a bit, and if the blocking flag goes away, |
177 | * loop around | 172 | * loop around |
178 | */ | 173 | */ |
174 | cpu_relax(); | ||
179 | if (btrfs_spin_on_block(eb)) | 175 | if (btrfs_spin_on_block(eb)) |
180 | continue; | 176 | continue; |
181 | 177 | sleep: | |
182 | prepare_to_wait_exclusive(&eb->lock_wq, &wait, | 178 | prepare_to_wait_exclusive(&eb->lock_wq, &wait, |
183 | TASK_UNINTERRUPTIBLE); | 179 | TASK_UNINTERRUPTIBLE); |
184 | 180 | ||
@@ -231,8 +227,8 @@ int btrfs_tree_unlock(struct extent_buffer *eb) | |||
231 | return 0; | 227 | return 0; |
232 | } | 228 | } |
233 | 229 | ||
234 | int btrfs_tree_locked(struct extent_buffer *eb) | 230 | void btrfs_assert_tree_locked(struct extent_buffer *eb) |
235 | { | 231 | { |
236 | return test_bit(EXTENT_BUFFER_BLOCKING, &eb->bflags) || | 232 | if (!test_bit(EXTENT_BUFFER_BLOCKING, &eb->bflags)) |
237 | spin_is_locked(&eb->lock); | 233 | assert_spin_locked(&eb->lock); |
238 | } | 234 | } |