Btrfs: mount ro and remount support
[linux-2.6-block.git] / fs / btrfs / extent-tree.c
index e785f0a0632b79a1472b674f27ea3e7a74d1cb35..af2de30dbeac4ba89f394e62545128f554ec6ed8 100644 (file)
@@ -1794,7 +1794,7 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags,
                *space_info = found;
                return 0;
        }
-       found = kmalloc(sizeof(*found), GFP_NOFS);
+       found = kzalloc(sizeof(*found), GFP_NOFS);
        if (!found)
                return -ENOMEM;
 
@@ -1807,6 +1807,7 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags,
        found->bytes_used = bytes_used;
        found->bytes_pinned = 0;
        found->bytes_reserved = 0;
+       found->bytes_readonly = 0;
        found->full = 0;
        found->force_alloc = 0;
        *space_info = found;
@@ -1829,6 +1830,19 @@ static void set_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags)
        }
 }
 
+static void set_block_group_readonly(struct btrfs_block_group_cache *cache)
+{
+       spin_lock(&cache->space_info->lock);
+       spin_lock(&cache->lock);
+       if (!cache->ro) {
+               cache->space_info->bytes_readonly += cache->key.offset -
+                                       btrfs_block_group_used(&cache->item);
+               cache->ro = 1;
+       }
+       spin_unlock(&cache->lock);
+       spin_unlock(&cache->space_info->lock);
+}
+
 static u64 reduce_alloc_profile(struct btrfs_root *root, u64 flags)
 {
        u64 num_devices = root->fs_info->fs_devices->num_devices;
@@ -1865,7 +1879,9 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans,
        u64 thresh;
        u64 start;
        u64 num_bytes;
-       int ret = 0, waited = 0;
+       int ret = 0;
+
+       mutex_lock(&extent_root->fs_info->chunk_mutex);
 
        flags = reduce_alloc_profile(extent_root, flags);
 
@@ -1887,46 +1903,28 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans,
                goto out;
        }
 
-       thresh = div_factor(space_info->total_bytes, 6);
+       thresh = space_info->total_bytes - space_info->bytes_readonly;
+       thresh = div_factor(thresh, 6);
        if (!force &&
           (space_info->bytes_used + space_info->bytes_pinned +
            space_info->bytes_reserved + alloc_bytes) < thresh) {
                spin_unlock(&space_info->lock);
                goto out;
        }
-
        spin_unlock(&space_info->lock);
 
-       ret = mutex_trylock(&extent_root->fs_info->chunk_mutex);
-       if (!ret && !force) {
-               goto out;
-       } else if (!ret) {
-               mutex_lock(&extent_root->fs_info->chunk_mutex);
-               waited = 1;
-       }
-
-       if (waited) {
-               spin_lock(&space_info->lock);
-               if (space_info->full) {
-                       spin_unlock(&space_info->lock);
-                       goto out_unlock;
-               }
-               spin_unlock(&space_info->lock);
-       }
-
        ret = btrfs_alloc_chunk(trans, extent_root, &start, &num_bytes, flags);
        if (ret) {
 printk("space info full %Lu\n", flags);
                space_info->full = 1;
-               goto out_unlock;
+               goto out;
        }
 
        ret = btrfs_make_block_group(trans, extent_root, 0, flags,
                     BTRFS_FIRST_CHUNK_TREE_OBJECTID, start, num_bytes);
        BUG_ON(ret);
-out_unlock:
-       mutex_unlock(&extent_root->fs_info->chunk_mutex);
 out:
+       mutex_unlock(&extent_root->fs_info->chunk_mutex);
        return ret;
 }
 
@@ -1956,12 +1954,18 @@ static int update_block_group(struct btrfs_trans_handle *trans,
                if (alloc) {
                        old_val += num_bytes;
                        cache->space_info->bytes_used += num_bytes;
+                       if (cache->ro) {
+                               cache->space_info->bytes_readonly -= num_bytes;
+                               WARN_ON(1);
+                       }
                        btrfs_set_block_group_used(&cache->item, old_val);
                        spin_unlock(&cache->lock);
                        spin_unlock(&cache->space_info->lock);
                } else {
                        old_val -= num_bytes;
                        cache->space_info->bytes_used -= num_bytes;
+                       if (cache->ro)
+                               cache->space_info->bytes_readonly += num_bytes;
                        btrfs_set_block_group_used(&cache->item, old_val);
                        spin_unlock(&cache->lock);
                        spin_unlock(&cache->space_info->lock);
@@ -5560,8 +5564,7 @@ int btrfs_relocate_block_group(struct btrfs_root *root, u64 group_start)
        BUG_ON(IS_ERR(reloc_inode));
 
        __alloc_chunk_for_shrink(root, block_group, 1);
-       block_group->ro = 1;
-       block_group->space_info->total_bytes -= block_group->key.offset;
+       set_block_group_readonly(block_group);
 
        btrfs_start_delalloc_inodes(info->tree_root);
        btrfs_wait_ordered_extents(info->tree_root, 0);
@@ -5868,6 +5871,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
 
        block_group = btrfs_lookup_block_group(root->fs_info, group_start);
        BUG_ON(!block_group);
+       BUG_ON(!block_group->ro);
 
        memcpy(&key, &block_group->key, sizeof(key));
 
@@ -5881,6 +5885,11 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
        list_del(&block_group->list);
        up_write(&block_group->space_info->groups_sem);
 
+       spin_lock(&block_group->space_info->lock);
+       block_group->space_info->total_bytes -= block_group->key.offset;
+       block_group->space_info->bytes_readonly -= block_group->key.offset;
+       spin_unlock(&block_group->space_info->lock);
+
        /*
        memset(shrink_block_group, 0, sizeof(*shrink_block_group));
        kfree(shrink_block_group);