History

Merge git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable

* git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable: Btrfs: Clear space_info full when adding new devices Btrfs: Fix locking around adding new space_info

Linus Torvalds committed 17 years ago

Commit fe2fd6c2 parents a8e7d49 913d9523 files · +59 −3Browse files

Unified · Split

3 files
  1. fs/btrfs/ctree.h +9 −0
  2. fs/btrfs/extent-tree.c +42 −3
  3. fs/btrfs/volumes.c +8 −0
fs/btrfs/ctree.h+9−0
@@ -784,7 +784,14 @@ struct btrfs_fs_info { · 783 unmodified lines
784784 struct list_head dirty_cowonly_roots;
785785
786786 struct btrfs_fs_devices *fs_devices;
787+
788+ /*
789+ * the space_info list is almost entirely read only. It only changes
790+ * when we add a new raid type to the FS, and that happens
791+ * very rarely. RCU is used to protect it.
792+ */
787793 struct list_head space_info;
794+
788795 spinlock_t delalloc_lock;
789796 spinlock_t new_trans_lock;
790797 u64 delalloc_bytes;
@@ -1797,6 +1804,8 @@ int btrfs_cleanup_reloc_trees(struct btrfs_root *root); · 1006 unmodified lines
17971804 int btrfs_reloc_clone_csums(struct inode *inode, u64 file_pos, u64 len);
17981805 u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags);
17991806 void btrfs_set_inode_space_info(struct btrfs_root *root, struct inode *ionde);
1807+void btrfs_clear_space_info_full(struct btrfs_fs_info *info);
1808+
18001809 int btrfs_check_metadata_free_space(struct btrfs_root *root);
18011810 int btrfs_check_data_free_space(struct btrfs_root *root, struct inode *inode,
18021811 u64 bytes);
fs/btrfs/extent-tree.c+42−3
@@ -20,6 +20,7 @@ · 19 unmodified lines
2020 #include <linux/writeback.h>
2121 #include <linux/blkdev.h>
2222 #include <linux/sort.h>
23+#include <linux/rcupdate.h>
2324 #include "compat.h"
2425 #include "hash.h"
2526 #include "crc32c.h"
@@ -330,13 +331,33 @@ static struct btrfs_space_info *__find_space_info(struct btrfs_fs_info *info, · 304 unmodified lines
330331 {
331332 struct list_head *head = &info->space_info;
332333 struct btrfs_space_info *found;
333− list_for_each_entry(found, head, list) {
334− if (found->flags == flags)
334+
335+ rcu_read_lock();
336+ list_for_each_entry_rcu(found, head, list) {
337+ if (found->flags == flags) {
338+ rcu_read_unlock();
335339 return found;
340+ }
336341 }
342+ rcu_read_unlock();
337343 return NULL;
338344 }
339345
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+
340361 static u64 div_factor(u64 num, int factor)
341362 {
342363 if (factor == 10)
@@ -1903,7 +1924,6 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags, · 1560 unmodified lines
19031924 if (!found)
19041925 return -ENOMEM;
19051926
1906− list_add(&found->list, &info->space_info);
19071927 INIT_LIST_HEAD(&found->block_groups);
19081928 init_rwsem(&found->groups_sem);
19091929 spin_lock_init(&found->lock);
@@ -1917,6 +1937,7 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags, · 7 unmodified lines
19171937 found->full = 0;
19181938 found->force_alloc = 0;
19191939 *space_info = found;
1940+ list_add_rcu(&found->list, &info->space_info);
19201941 return 0;
19211942 }
19221943
@@ -6320,6 +6341,7 @@ out: · 4397 unmodified lines
63206341 int btrfs_free_block_groups(struct btrfs_fs_info *info)
63216342 {
63226343 struct btrfs_block_group_cache *block_group;
6344+ struct btrfs_space_info *space_info;
63236345 struct rb_node *n;
63246346
63256347 spin_lock(&info->block_group_cache_lock);
@@ -6341,6 +6363,23 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info) · 15 unmodified lines
63416363 spin_lock(&info->block_group_cache_lock);
63426364 }
63436365 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+ }
63446383 return 0;
63456384 }
63466385
fs/btrfs/volumes.c+8−0
@@ -1374,6 +1374,12 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path) · 1373 unmodified lines
13741374 ret = btrfs_add_device(trans, root, device);
13751375 }
13761376
1377+ /*
1378+ * we've got more storage, clear any full flags on the space
1379+ * infos
1380+ */
1381+ btrfs_clear_space_info_full(root->fs_info);
1382+
13771383 unlock_chunks(root);
13781384 btrfs_commit_transaction(trans, root);
13791385
@@ -1459,6 +1465,8 @@ static int __btrfs_grow_device(struct btrfs_trans_handle *trans, · 79 unmodified lines
14591465 device->fs_devices->total_rw_bytes += diff;
14601466
14611467 device->total_bytes = new_size;
1468+ btrfs_clear_space_info_full(device->dev_root->fs_info);
1469+
14621470 return btrfs_update_device(trans, device);
14631471 }
14641472