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
This commit is contained in:
commit
fe2fd6cc34
|
@ -784,7 +784,14 @@ struct btrfs_fs_info {
|
|||
struct list_head dirty_cowonly_roots;
|
||||
|
||||
struct btrfs_fs_devices *fs_devices;
|
||||
|
||||
/*
|
||||
* the space_info list is almost entirely read only. It only changes
|
||||
* when we add a new raid type to the FS, and that happens
|
||||
* very rarely. RCU is used to protect it.
|
||||
*/
|
||||
struct list_head space_info;
|
||||
|
||||
spinlock_t delalloc_lock;
|
||||
spinlock_t new_trans_lock;
|
||||
u64 delalloc_bytes;
|
||||
|
@ -1797,6 +1804,8 @@ int btrfs_cleanup_reloc_trees(struct btrfs_root *root);
|
|||
int btrfs_reloc_clone_csums(struct inode *inode, u64 file_pos, u64 len);
|
||||
u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags);
|
||||
void btrfs_set_inode_space_info(struct btrfs_root *root, struct inode *ionde);
|
||||
void btrfs_clear_space_info_full(struct btrfs_fs_info *info);
|
||||
|
||||
int btrfs_check_metadata_free_space(struct btrfs_root *root);
|
||||
int btrfs_check_data_free_space(struct btrfs_root *root, struct inode *inode,
|
||||
u64 bytes);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/writeback.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/sort.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include "compat.h"
|
||||
#include "hash.h"
|
||||
#include "crc32c.h"
|
||||
|
@ -330,13 +331,33 @@ static struct btrfs_space_info *__find_space_info(struct btrfs_fs_info *info,
|
|||
{
|
||||
struct list_head *head = &info->space_info;
|
||||
struct btrfs_space_info *found;
|
||||
list_for_each_entry(found, head, list) {
|
||||
if (found->flags == flags)
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(found, head, list) {
|
||||
if (found->flags == flags) {
|
||||
rcu_read_unlock();
|
||||
return found;
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* after adding space to the filesystem, we need to clear the full flags
|
||||
* on all the space infos.
|
||||
*/
|
||||
void btrfs_clear_space_info_full(struct btrfs_fs_info *info)
|
||||
{
|
||||
struct list_head *head = &info->space_info;
|
||||
struct btrfs_space_info *found;
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(found, head, list)
|
||||
found->full = 0;
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static u64 div_factor(u64 num, int factor)
|
||||
{
|
||||
if (factor == 10)
|
||||
|
@ -1903,7 +1924,6 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags,
|
|||
if (!found)
|
||||
return -ENOMEM;
|
||||
|
||||
list_add(&found->list, &info->space_info);
|
||||
INIT_LIST_HEAD(&found->block_groups);
|
||||
init_rwsem(&found->groups_sem);
|
||||
spin_lock_init(&found->lock);
|
||||
|
@ -1917,6 +1937,7 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags,
|
|||
found->full = 0;
|
||||
found->force_alloc = 0;
|
||||
*space_info = found;
|
||||
list_add_rcu(&found->list, &info->space_info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -6320,6 +6341,7 @@ out:
|
|||
int btrfs_free_block_groups(struct btrfs_fs_info *info)
|
||||
{
|
||||
struct btrfs_block_group_cache *block_group;
|
||||
struct btrfs_space_info *space_info;
|
||||
struct rb_node *n;
|
||||
|
||||
spin_lock(&info->block_group_cache_lock);
|
||||
|
@ -6341,6 +6363,23 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
|
|||
spin_lock(&info->block_group_cache_lock);
|
||||
}
|
||||
spin_unlock(&info->block_group_cache_lock);
|
||||
|
||||
/* now that all the block groups are freed, go through and
|
||||
* free all the space_info structs. This is only called during
|
||||
* the final stages of unmount, and so we know nobody is
|
||||
* using them. We call synchronize_rcu() once before we start,
|
||||
* just to be on the safe side.
|
||||
*/
|
||||
synchronize_rcu();
|
||||
|
||||
while(!list_empty(&info->space_info)) {
|
||||
space_info = list_entry(info->space_info.next,
|
||||
struct btrfs_space_info,
|
||||
list);
|
||||
|
||||
list_del(&space_info->list);
|
||||
kfree(space_info);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1374,6 +1374,12 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
|
|||
ret = btrfs_add_device(trans, root, device);
|
||||
}
|
||||
|
||||
/*
|
||||
* we've got more storage, clear any full flags on the space
|
||||
* infos
|
||||
*/
|
||||
btrfs_clear_space_info_full(root->fs_info);
|
||||
|
||||
unlock_chunks(root);
|
||||
btrfs_commit_transaction(trans, root);
|
||||
|
||||
|
@ -1459,6 +1465,8 @@ static int __btrfs_grow_device(struct btrfs_trans_handle *trans,
|
|||
device->fs_devices->total_rw_bytes += diff;
|
||||
|
||||
device->total_bytes = new_size;
|
||||
btrfs_clear_space_info_full(device->dev_root->fs_info);
|
||||
|
||||
return btrfs_update_device(trans, device);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue