diff options
author | Josef Bacik <josef@redhat.com> | 2009-07-13 21:29:25 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2009-07-24 09:23:39 -0400 |
commit | 817d52f8dba26d0295c26035531c30ce5f1e3c3e (patch) | |
tree | 5230153e86323de48e7e1440352d1b74d2d9961d /fs/btrfs/free-space-cache.c | |
parent | 963030817060e4f109be1993b9ae8f81dbf5e11a (diff) |
Btrfs: async block group caching
This patch moves the caching of the block group off to a kthread in order to
allow people to allocate sooner. Instead of blocking up behind the caching
mutex, we instead kick of the caching kthread, and then attempt to make an
allocation. If we cannot, we wait on the block groups caching waitqueue, which
the caching kthread will wake the waiting threads up everytime it finds 2 meg
worth of space, and then again when its finished caching. This is how I tested
the speedup from this
mkfs the disk
mount the disk
fill the disk up with fs_mark
unmount the disk
mount the disk
time touch /mnt/foo
Without my changes this took 11 seconds on my box, with these changes it now
takes 1 second.
Another change thats been put in place is we lock the super mirror's in the
pinned extent map in order to keep us from adding that stuff as free space when
caching the block group. This doesn't really change anything else as far as the
pinned extent map is concerned, since for actual pinned extents we use
EXTENT_DIRTY, but it does mean that when we unmount we have to go in and unlock
those extents to keep from leaking memory.
I've also added a check where when we are reading block groups from disk, if the
amount of space used == the size of the block group, we go ahead and mark the
block group as cached. This drastically reduces the amount of time it takes to
cache the block groups. Using the same test as above, except doing a dd to a
file and then unmounting, it used to take 33 seconds to umount, now it takes 3
seconds.
This version uses the commit_root in the caching kthread, and then keeps track
of how many async caching threads are running at any given time so if one of the
async threads is still running as we cross transactions we can wait until its
finished before handling the pinned extents. Thank you,
Signed-off-by: Josef Bacik <jbacik@redhat.com>
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/free-space-cache.c')
-rw-r--r-- | fs/btrfs/free-space-cache.c | 42 |
1 files changed, 23 insertions, 19 deletions
diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index ab8cad8b46c9..af99b78b288e 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c | |||
@@ -238,6 +238,7 @@ static void unlink_free_space(struct btrfs_block_group_cache *block_group, | |||
238 | { | 238 | { |
239 | rb_erase(&info->offset_index, &block_group->free_space_offset); | 239 | rb_erase(&info->offset_index, &block_group->free_space_offset); |
240 | block_group->free_extents--; | 240 | block_group->free_extents--; |
241 | block_group->free_space -= info->bytes; | ||
241 | } | 242 | } |
242 | 243 | ||
243 | static int link_free_space(struct btrfs_block_group_cache *block_group, | 244 | static int link_free_space(struct btrfs_block_group_cache *block_group, |
@@ -251,6 +252,7 @@ static int link_free_space(struct btrfs_block_group_cache *block_group, | |||
251 | if (ret) | 252 | if (ret) |
252 | return ret; | 253 | return ret; |
253 | 254 | ||
255 | block_group->free_space += info->bytes; | ||
254 | block_group->free_extents++; | 256 | block_group->free_extents++; |
255 | return ret; | 257 | return ret; |
256 | } | 258 | } |
@@ -285,36 +287,40 @@ static void recalculate_thresholds(struct btrfs_block_group_cache *block_group) | |||
285 | } | 287 | } |
286 | } | 288 | } |
287 | 289 | ||
288 | static void bitmap_clear_bits(struct btrfs_free_space *info, u64 offset, u64 bytes, | 290 | static void bitmap_clear_bits(struct btrfs_block_group_cache *block_group, |
289 | u64 sectorsize) | 291 | struct btrfs_free_space *info, u64 offset, |
292 | u64 bytes) | ||
290 | { | 293 | { |
291 | unsigned long start, end; | 294 | unsigned long start, end; |
292 | unsigned long i; | 295 | unsigned long i; |
293 | 296 | ||
294 | start = offset_to_bit(info->offset, sectorsize, offset); | 297 | start = offset_to_bit(info->offset, block_group->sectorsize, offset); |
295 | end = start + bytes_to_bits(bytes, sectorsize); | 298 | end = start + bytes_to_bits(bytes, block_group->sectorsize); |
296 | BUG_ON(end > BITS_PER_BITMAP); | 299 | BUG_ON(end > BITS_PER_BITMAP); |
297 | 300 | ||
298 | for (i = start; i < end; i++) | 301 | for (i = start; i < end; i++) |
299 | clear_bit(i, info->bitmap); | 302 | clear_bit(i, info->bitmap); |
300 | 303 | ||
301 | info->bytes -= bytes; | 304 | info->bytes -= bytes; |
305 | block_group->free_space -= bytes; | ||
302 | } | 306 | } |
303 | 307 | ||
304 | static void bitmap_set_bits(struct btrfs_free_space *info, u64 offset, u64 bytes, | 308 | static void bitmap_set_bits(struct btrfs_block_group_cache *block_group, |
305 | u64 sectorsize) | 309 | struct btrfs_free_space *info, u64 offset, |
310 | u64 bytes) | ||
306 | { | 311 | { |
307 | unsigned long start, end; | 312 | unsigned long start, end; |
308 | unsigned long i; | 313 | unsigned long i; |
309 | 314 | ||
310 | start = offset_to_bit(info->offset, sectorsize, offset); | 315 | start = offset_to_bit(info->offset, block_group->sectorsize, offset); |
311 | end = start + bytes_to_bits(bytes, sectorsize); | 316 | end = start + bytes_to_bits(bytes, block_group->sectorsize); |
312 | BUG_ON(end > BITS_PER_BITMAP); | 317 | BUG_ON(end > BITS_PER_BITMAP); |
313 | 318 | ||
314 | for (i = start; i < end; i++) | 319 | for (i = start; i < end; i++) |
315 | set_bit(i, info->bitmap); | 320 | set_bit(i, info->bitmap); |
316 | 321 | ||
317 | info->bytes += bytes; | 322 | info->bytes += bytes; |
323 | block_group->free_space += bytes; | ||
318 | } | 324 | } |
319 | 325 | ||
320 | static int search_bitmap(struct btrfs_block_group_cache *block_group, | 326 | static int search_bitmap(struct btrfs_block_group_cache *block_group, |
@@ -414,13 +420,12 @@ again: | |||
414 | (u64)(BITS_PER_BITMAP * block_group->sectorsize) - 1; | 420 | (u64)(BITS_PER_BITMAP * block_group->sectorsize) - 1; |
415 | 421 | ||
416 | if (*offset > bitmap_info->offset && *offset + *bytes > end) { | 422 | if (*offset > bitmap_info->offset && *offset + *bytes > end) { |
417 | bitmap_clear_bits(bitmap_info, *offset, | 423 | bitmap_clear_bits(block_group, bitmap_info, *offset, |
418 | end - *offset + 1, block_group->sectorsize); | 424 | end - *offset + 1); |
419 | *bytes -= end - *offset + 1; | 425 | *bytes -= end - *offset + 1; |
420 | *offset = end + 1; | 426 | *offset = end + 1; |
421 | } else if (*offset >= bitmap_info->offset && *offset + *bytes <= end) { | 427 | } else if (*offset >= bitmap_info->offset && *offset + *bytes <= end) { |
422 | bitmap_clear_bits(bitmap_info, *offset, | 428 | bitmap_clear_bits(block_group, bitmap_info, *offset, *bytes); |
423 | *bytes, block_group->sectorsize); | ||
424 | *bytes = 0; | 429 | *bytes = 0; |
425 | } | 430 | } |
426 | 431 | ||
@@ -495,14 +500,13 @@ again: | |||
495 | (u64)(BITS_PER_BITMAP * block_group->sectorsize); | 500 | (u64)(BITS_PER_BITMAP * block_group->sectorsize); |
496 | 501 | ||
497 | if (offset >= bitmap_info->offset && offset + bytes > end) { | 502 | if (offset >= bitmap_info->offset && offset + bytes > end) { |
498 | bitmap_set_bits(bitmap_info, offset, end - offset, | 503 | bitmap_set_bits(block_group, bitmap_info, offset, |
499 | block_group->sectorsize); | 504 | end - offset); |
500 | bytes -= end - offset; | 505 | bytes -= end - offset; |
501 | offset = end; | 506 | offset = end; |
502 | added = 0; | 507 | added = 0; |
503 | } else if (offset >= bitmap_info->offset && offset + bytes <= end) { | 508 | } else if (offset >= bitmap_info->offset && offset + bytes <= end) { |
504 | bitmap_set_bits(bitmap_info, offset, bytes, | 509 | bitmap_set_bits(block_group, bitmap_info, offset, bytes); |
505 | block_group->sectorsize); | ||
506 | bytes = 0; | 510 | bytes = 0; |
507 | } else { | 511 | } else { |
508 | BUG(); | 512 | BUG(); |
@@ -870,8 +874,7 @@ u64 btrfs_find_space_for_alloc(struct btrfs_block_group_cache *block_group, | |||
870 | 874 | ||
871 | ret = offset; | 875 | ret = offset; |
872 | if (entry->bitmap) { | 876 | if (entry->bitmap) { |
873 | bitmap_clear_bits(entry, offset, bytes, | 877 | bitmap_clear_bits(block_group, entry, offset, bytes); |
874 | block_group->sectorsize); | ||
875 | if (!entry->bytes) { | 878 | if (!entry->bytes) { |
876 | unlink_free_space(block_group, entry); | 879 | unlink_free_space(block_group, entry); |
877 | kfree(entry->bitmap); | 880 | kfree(entry->bitmap); |
@@ -891,6 +894,7 @@ u64 btrfs_find_space_for_alloc(struct btrfs_block_group_cache *block_group, | |||
891 | 894 | ||
892 | out: | 895 | out: |
893 | spin_unlock(&block_group->tree_lock); | 896 | spin_unlock(&block_group->tree_lock); |
897 | |||
894 | return ret; | 898 | return ret; |
895 | } | 899 | } |
896 | 900 | ||
@@ -967,7 +971,7 @@ static u64 btrfs_alloc_from_bitmap(struct btrfs_block_group_cache *block_group, | |||
967 | goto out; | 971 | goto out; |
968 | 972 | ||
969 | ret = search_start; | 973 | ret = search_start; |
970 | bitmap_clear_bits(entry, ret, bytes, block_group->sectorsize); | 974 | bitmap_clear_bits(block_group, entry, ret, bytes); |
971 | out: | 975 | out: |
972 | spin_unlock(&cluster->lock); | 976 | spin_unlock(&cluster->lock); |
973 | spin_unlock(&block_group->tree_lock); | 977 | spin_unlock(&block_group->tree_lock); |