Btrfs: mount ro and remount support

This patch adds mount ro and remount support. The main
changes in patch are: adding btrfs_remount and related
helper function; splitting the transaction related code
out of close_ctree into btrfs_commit_super; updating
allocator to properly handle read only block group.

Signed-off-by: Yan Zheng <zheng.yan@oracle.com>

diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index e785f0a..af2de30 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -1794,7 +1794,7 @@
 		*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 @@
 	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_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 @@
 	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 @@
 		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 @@
 		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 @@
 	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 @@
 
 	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 @@
 	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);