diff options
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r-- | fs/btrfs/extent-tree.c | 45 |
1 files changed, 42 insertions, 3 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 9abf81f71c46..fefe83ad2059 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/writeback.h> | 20 | #include <linux/writeback.h> |
21 | #include <linux/blkdev.h> | 21 | #include <linux/blkdev.h> |
22 | #include <linux/sort.h> | 22 | #include <linux/sort.h> |
23 | #include <linux/rcupdate.h> | ||
23 | #include "compat.h" | 24 | #include "compat.h" |
24 | #include "hash.h" | 25 | #include "hash.h" |
25 | #include "crc32c.h" | 26 | #include "crc32c.h" |
@@ -330,13 +331,33 @@ static struct btrfs_space_info *__find_space_info(struct btrfs_fs_info *info, | |||
330 | { | 331 | { |
331 | struct list_head *head = &info->space_info; | 332 | struct list_head *head = &info->space_info; |
332 | struct btrfs_space_info *found; | 333 | struct btrfs_space_info *found; |
333 | list_for_each_entry(found, head, list) { | 334 | |
334 | if (found->flags == flags) | 335 | rcu_read_lock(); |
336 | list_for_each_entry_rcu(found, head, list) { | ||
337 | if (found->flags == flags) { | ||
338 | rcu_read_unlock(); | ||
335 | return found; | 339 | return found; |
340 | } | ||
336 | } | 341 | } |
342 | rcu_read_unlock(); | ||
337 | return NULL; | 343 | return NULL; |
338 | } | 344 | } |
339 | 345 | ||
346 | /* | ||
347 | * after adding space to the filesystem, we need to clear the full flags | ||
348 | * on all the space infos. | ||
349 | */ | ||
350 | void btrfs_clear_space_info_full(struct btrfs_fs_info *info) | ||
351 | { | ||
352 | struct list_head *head = &info->space_info; | ||
353 | struct btrfs_space_info *found; | ||
354 | |||
355 | rcu_read_lock(); | ||
356 | list_for_each_entry_rcu(found, head, list) | ||
357 | found->full = 0; | ||
358 | rcu_read_unlock(); | ||
359 | } | ||
360 | |||
340 | static u64 div_factor(u64 num, int factor) | 361 | static u64 div_factor(u64 num, int factor) |
341 | { | 362 | { |
342 | if (factor == 10) | 363 | if (factor == 10) |
@@ -1903,7 +1924,6 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags, | |||
1903 | if (!found) | 1924 | if (!found) |
1904 | return -ENOMEM; | 1925 | return -ENOMEM; |
1905 | 1926 | ||
1906 | list_add(&found->list, &info->space_info); | ||
1907 | INIT_LIST_HEAD(&found->block_groups); | 1927 | INIT_LIST_HEAD(&found->block_groups); |
1908 | init_rwsem(&found->groups_sem); | 1928 | init_rwsem(&found->groups_sem); |
1909 | spin_lock_init(&found->lock); | 1929 | spin_lock_init(&found->lock); |
@@ -1917,6 +1937,7 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags, | |||
1917 | found->full = 0; | 1937 | found->full = 0; |
1918 | found->force_alloc = 0; | 1938 | found->force_alloc = 0; |
1919 | *space_info = found; | 1939 | *space_info = found; |
1940 | list_add_rcu(&found->list, &info->space_info); | ||
1920 | return 0; | 1941 | return 0; |
1921 | } | 1942 | } |
1922 | 1943 | ||
@@ -6320,6 +6341,7 @@ out: | |||
6320 | int btrfs_free_block_groups(struct btrfs_fs_info *info) | 6341 | int btrfs_free_block_groups(struct btrfs_fs_info *info) |
6321 | { | 6342 | { |
6322 | struct btrfs_block_group_cache *block_group; | 6343 | struct btrfs_block_group_cache *block_group; |
6344 | struct btrfs_space_info *space_info; | ||
6323 | struct rb_node *n; | 6345 | struct rb_node *n; |
6324 | 6346 | ||
6325 | spin_lock(&info->block_group_cache_lock); | 6347 | spin_lock(&info->block_group_cache_lock); |
@@ -6341,6 +6363,23 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info) | |||
6341 | spin_lock(&info->block_group_cache_lock); | 6363 | spin_lock(&info->block_group_cache_lock); |
6342 | } | 6364 | } |
6343 | spin_unlock(&info->block_group_cache_lock); | 6365 | spin_unlock(&info->block_group_cache_lock); |
6366 | |||
6367 | /* now that all the block groups are freed, go through and | ||
6368 | * free all the space_info structs. This is only called during | ||
6369 | * the final stages of unmount, and so we know nobody is | ||
6370 | * using them. We call synchronize_rcu() once before we start, | ||
6371 | * just to be on the safe side. | ||
6372 | */ | ||
6373 | synchronize_rcu(); | ||
6374 | |||
6375 | while(!list_empty(&info->space_info)) { | ||
6376 | space_info = list_entry(info->space_info.next, | ||
6377 | struct btrfs_space_info, | ||
6378 | list); | ||
6379 | |||
6380 | list_del(&space_info->list); | ||
6381 | kfree(space_info); | ||
6382 | } | ||
6344 | return 0; | 6383 | return 0; |
6345 | } | 6384 | } |
6346 | 6385 | ||