aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/extent-tree.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r--fs/btrfs/extent-tree.c45
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 */
350void 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
340static u64 div_factor(u64 num, int factor) 361static 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:
6320int btrfs_free_block_groups(struct btrfs_fs_info *info) 6341int 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