xref: /openbmc/linux/fs/btrfs/disk-io.c (revision e20d96d6)
1e20d96d6SChris Mason #include <linux/module.h>
2e20d96d6SChris Mason #include <linux/fs.h>
3eb60ceacSChris Mason #include "ctree.h"
4eb60ceacSChris Mason #include "disk-io.h"
5e089f05cSChris Mason #include "transaction.h"
6eb60ceacSChris Mason 
7e20d96d6SChris Mason static int check_tree_block(struct btrfs_root *root, struct buffer_head *buf)
8eb60ceacSChris Mason {
9e20d96d6SChris Mason 	struct btrfs_node *node = btrfs_buffer_node(buf);
10e20d96d6SChris Mason 	if (buf->b_blocknr != btrfs_header_blocknr(&node->header))
119a8dd150SChris Mason 		BUG();
12e20d96d6SChris Mason 	if (root->node && btrfs_header_parentid(&node->header) !=
13e20d96d6SChris Mason 	    btrfs_header_parentid(btrfs_buffer_header(root->node)))
149a8dd150SChris Mason 		BUG();
159a8dd150SChris Mason 	return 0;
16eb60ceacSChris Mason }
17eb60ceacSChris Mason 
18e20d96d6SChris Mason struct buffer_head *alloc_tree_block(struct btrfs_root *root, u64 blocknr)
19ed2ff2cbSChris Mason {
20e20d96d6SChris Mason 	return sb_getblk(root->fs_info->sb, blocknr);
21ed2ff2cbSChris Mason }
22ed2ff2cbSChris Mason 
23e20d96d6SChris Mason struct buffer_head *find_tree_block(struct btrfs_root *root, u64 blocknr)
24eb60ceacSChris Mason {
25e20d96d6SChris Mason 	return sb_getblk(root->fs_info->sb, blocknr);
26e20d96d6SChris Mason }
27123abc88SChris Mason 
28e20d96d6SChris Mason struct buffer_head *read_tree_block(struct btrfs_root *root, u64 blocknr)
29e20d96d6SChris Mason {
30e20d96d6SChris Mason 	struct buffer_head *buf = sb_bread(root->fs_info->sb, blocknr);
31e20d96d6SChris Mason 
32eb60ceacSChris Mason 	if (!buf)
33eb60ceacSChris Mason 		return buf;
349a8dd150SChris Mason 	if (check_tree_block(root, buf))
35cfaa7295SChris Mason 		BUG();
36eb60ceacSChris Mason 	return buf;
37eb60ceacSChris Mason }
38eb60ceacSChris Mason 
39e089f05cSChris Mason int dirty_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
40e20d96d6SChris Mason 		     struct buffer_head *buf)
41ed2ff2cbSChris Mason {
42e20d96d6SChris Mason 	mark_buffer_dirty(buf);
43ed2ff2cbSChris Mason 	return 0;
44ed2ff2cbSChris Mason }
45ed2ff2cbSChris Mason 
46e089f05cSChris Mason int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
47e20d96d6SChris Mason 		     struct buffer_head *buf)
48ed2ff2cbSChris Mason {
49e20d96d6SChris Mason 	clear_buffer_dirty(buf);
50ed2ff2cbSChris Mason 	return 0;
51ed2ff2cbSChris Mason }
52ed2ff2cbSChris Mason 
53e089f05cSChris Mason int write_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
54e20d96d6SChris Mason 		     struct buffer_head *buf)
55eb60ceacSChris Mason {
56e20d96d6SChris Mason 	mark_buffer_dirty(buf);
57eb60ceacSChris Mason 	return 0;
58eb60ceacSChris Mason }
59eb60ceacSChris Mason 
60e089f05cSChris Mason static int __commit_transaction(struct btrfs_trans_handle *trans, struct
61e089f05cSChris Mason 				btrfs_root *root)
62ed2ff2cbSChris Mason {
63e20d96d6SChris Mason 	filemap_write_and_wait(root->fs_info->sb->s_bdev->bd_inode->i_mapping);
64e20d96d6SChris Mason 	return 0;
65ed2ff2cbSChris Mason }
66ed2ff2cbSChris Mason 
679f5fae2fSChris Mason static int commit_tree_roots(struct btrfs_trans_handle *trans,
689f5fae2fSChris Mason 			     struct btrfs_fs_info *fs_info)
693768f368SChris Mason {
703768f368SChris Mason 	int ret;
713768f368SChris Mason 	u64 old_extent_block;
729f5fae2fSChris Mason 	struct btrfs_root *tree_root = fs_info->tree_root;
739f5fae2fSChris Mason 	struct btrfs_root *extent_root = fs_info->extent_root;
749f5fae2fSChris Mason 	struct btrfs_root *inode_root = fs_info->inode_root;
753768f368SChris Mason 
769f5fae2fSChris Mason 	btrfs_set_root_blocknr(&inode_root->root_item,
77e20d96d6SChris Mason 			       inode_root->node->b_blocknr);
789f5fae2fSChris Mason 	ret = btrfs_update_root(trans, tree_root,
799f5fae2fSChris Mason 				&inode_root->root_key,
809f5fae2fSChris Mason 				&inode_root->root_item);
819f5fae2fSChris Mason 	BUG_ON(ret);
823768f368SChris Mason 	while(1) {
833768f368SChris Mason 		old_extent_block = btrfs_root_blocknr(&extent_root->root_item);
84e20d96d6SChris Mason 		if (old_extent_block == extent_root->node->b_blocknr)
853768f368SChris Mason 			break;
863768f368SChris Mason 		btrfs_set_root_blocknr(&extent_root->root_item,
87e20d96d6SChris Mason 				       extent_root->node->b_blocknr);
88e089f05cSChris Mason 		ret = btrfs_update_root(trans, tree_root,
893768f368SChris Mason 					&extent_root->root_key,
903768f368SChris Mason 					&extent_root->root_item);
913768f368SChris Mason 		BUG_ON(ret);
923768f368SChris Mason 	}
933768f368SChris Mason 	return 0;
943768f368SChris Mason }
953768f368SChris Mason 
96e089f05cSChris Mason int btrfs_commit_transaction(struct btrfs_trans_handle *trans, struct
97e089f05cSChris Mason 			     btrfs_root *root, struct btrfs_super_block *s)
98ed2ff2cbSChris Mason {
99a28ec197SChris Mason 	int ret = 0;
100e20d96d6SChris Mason 	struct buffer_head *snap = root->commit_root;
1013768f368SChris Mason 	struct btrfs_key snap_key;
102a28ec197SChris Mason 
1033768f368SChris Mason 	if (root->commit_root == root->node)
1043768f368SChris Mason 		return 0;
1053768f368SChris Mason 
1063768f368SChris Mason 	memcpy(&snap_key, &root->root_key, sizeof(snap_key));
1073768f368SChris Mason 	root->root_key.offset++;
1083768f368SChris Mason 
109e20d96d6SChris Mason 	btrfs_set_root_blocknr(&root->root_item, root->node->b_blocknr);
1109f5fae2fSChris Mason 	ret = btrfs_insert_root(trans, root->fs_info->tree_root,
1119f5fae2fSChris Mason 				&root->root_key, &root->root_item);
1123768f368SChris Mason 	BUG_ON(ret);
1133768f368SChris Mason 
1149f5fae2fSChris Mason 	ret = commit_tree_roots(trans, root->fs_info);
1159f5fae2fSChris Mason 	BUG_ON(ret);
1169f5fae2fSChris Mason 
1179f5fae2fSChris Mason 	ret = __commit_transaction(trans, root);
1183768f368SChris Mason 	BUG_ON(ret);
1193768f368SChris Mason 
120e089f05cSChris Mason 	write_ctree_super(trans, root, s);
1219f5fae2fSChris Mason 	btrfs_finish_extent_commit(trans, root->fs_info->extent_root);
1229f5fae2fSChris Mason 	btrfs_finish_extent_commit(trans, root->fs_info->tree_root);
1233768f368SChris Mason 
124a28ec197SChris Mason 	root->commit_root = root->node;
125e20d96d6SChris Mason 	get_bh(root->node);
126e089f05cSChris Mason 	ret = btrfs_drop_snapshot(trans, root, snap);
127a28ec197SChris Mason 	BUG_ON(ret);
1283768f368SChris Mason 
1299f5fae2fSChris Mason 	ret = btrfs_del_root(trans, root->fs_info->tree_root, &snap_key);
1303768f368SChris Mason 	BUG_ON(ret);
131293ffd5fSChris Mason 	root->fs_info->generation = root->root_key.offset + 1;
1323768f368SChris Mason 
133ed2ff2cbSChris Mason 	return ret;
134ed2ff2cbSChris Mason }
135ed2ff2cbSChris Mason 
136123abc88SChris Mason static int __setup_root(struct btrfs_super_block *super,
1379f5fae2fSChris Mason 			struct btrfs_root *root,
1389f5fae2fSChris Mason 			struct btrfs_fs_info *fs_info,
139e20d96d6SChris Mason 			u64 objectid)
140d97e63b6SChris Mason {
141cfaa7295SChris Mason 	root->node = NULL;
142a28ec197SChris Mason 	root->commit_root = NULL;
143123abc88SChris Mason 	root->blocksize = btrfs_super_blocksize(super);
144123abc88SChris Mason 	root->ref_cows = 0;
1459f5fae2fSChris Mason 	root->fs_info = fs_info;
1463768f368SChris Mason 	memset(&root->root_key, 0, sizeof(root->root_key));
1473768f368SChris Mason 	memset(&root->root_item, 0, sizeof(root->root_item));
1483768f368SChris Mason 	return 0;
1493768f368SChris Mason }
1503768f368SChris Mason 
151123abc88SChris Mason static int find_and_setup_root(struct btrfs_super_block *super,
1529f5fae2fSChris Mason 			       struct btrfs_root *tree_root,
1539f5fae2fSChris Mason 			       struct btrfs_fs_info *fs_info,
1549f5fae2fSChris Mason 			       u64 objectid,
155e20d96d6SChris Mason 			       struct btrfs_root *root)
1563768f368SChris Mason {
1573768f368SChris Mason 	int ret;
1583768f368SChris Mason 
159e20d96d6SChris Mason 	__setup_root(super, root, fs_info, objectid);
1603768f368SChris Mason 	ret = btrfs_find_last_root(tree_root, objectid,
1613768f368SChris Mason 				   &root->root_item, &root->root_key);
1623768f368SChris Mason 	BUG_ON(ret);
1633768f368SChris Mason 
1643768f368SChris Mason 	root->node = read_tree_block(root,
1653768f368SChris Mason 				     btrfs_root_blocknr(&root->root_item));
1663768f368SChris Mason 	BUG_ON(!root->node);
167d97e63b6SChris Mason 	return 0;
168d97e63b6SChris Mason }
169d97e63b6SChris Mason 
170e20d96d6SChris Mason struct btrfs_root *open_ctree(struct super_block *sb,
171e20d96d6SChris Mason 			      struct buffer_head *sb_buffer,
172e20d96d6SChris Mason 			      struct btrfs_super_block *disk_super)
173eb60ceacSChris Mason {
174e20d96d6SChris Mason 	struct btrfs_root *root = kmalloc(sizeof(struct btrfs_root),
175e20d96d6SChris Mason 					  GFP_NOFS);
176e20d96d6SChris Mason 	struct btrfs_root *extent_root = kmalloc(sizeof(struct btrfs_root),
177e20d96d6SChris Mason 						 GFP_NOFS);
178e20d96d6SChris Mason 	struct btrfs_root *tree_root = kmalloc(sizeof(struct btrfs_root),
179e20d96d6SChris Mason 					       GFP_NOFS);
180e20d96d6SChris Mason 	struct btrfs_root *inode_root = kmalloc(sizeof(struct btrfs_root),
181e20d96d6SChris Mason 						GFP_NOFS);
182e20d96d6SChris Mason 	struct btrfs_fs_info *fs_info = kmalloc(sizeof(*fs_info),
183e20d96d6SChris Mason 						GFP_NOFS);
184eb60ceacSChris Mason 	int ret;
185eb60ceacSChris Mason 
186e20d96d6SChris Mason 	/* FIXME: don't be stupid */
187e20d96d6SChris Mason 	if (!btrfs_super_root(disk_super))
188e20d96d6SChris Mason 		return NULL;
1899f5fae2fSChris Mason 	INIT_RADIX_TREE(&fs_info->pinned_radix, GFP_KERNEL);
1909f5fae2fSChris Mason 	fs_info->running_transaction = NULL;
1919f5fae2fSChris Mason 	fs_info->fs_root = root;
1929f5fae2fSChris Mason 	fs_info->tree_root = tree_root;
1939f5fae2fSChris Mason 	fs_info->extent_root = extent_root;
1949f5fae2fSChris Mason 	fs_info->inode_root = inode_root;
1959f5fae2fSChris Mason 	fs_info->last_inode_alloc = 0;
1969f5fae2fSChris Mason 	fs_info->last_inode_alloc_dirid = 0;
197e20d96d6SChris Mason 	fs_info->disk_super = disk_super;
198e20d96d6SChris Mason 	fs_info->sb_buffer = sb_buffer;
199e20d96d6SChris Mason 	fs_info->sb = sb;
2009f5fae2fSChris Mason 	memset(&fs_info->current_insert, 0, sizeof(fs_info->current_insert));
2019f5fae2fSChris Mason 	memset(&fs_info->last_insert, 0, sizeof(fs_info->last_insert));
2023768f368SChris Mason 
203e20d96d6SChris Mason 	__setup_root(disk_super, tree_root, fs_info, BTRFS_ROOT_TREE_OBJECTID);
204e20d96d6SChris Mason 	tree_root->node = read_tree_block(tree_root,
205e20d96d6SChris Mason 					  btrfs_super_root(disk_super));
2063768f368SChris Mason 	BUG_ON(!tree_root->node);
2073768f368SChris Mason 
208e20d96d6SChris Mason 	ret = find_and_setup_root(disk_super, tree_root, fs_info,
209e20d96d6SChris Mason 				  BTRFS_EXTENT_TREE_OBJECTID, extent_root);
2103768f368SChris Mason 	BUG_ON(ret);
2113768f368SChris Mason 
212e20d96d6SChris Mason 	ret = find_and_setup_root(disk_super, tree_root, fs_info,
213e20d96d6SChris Mason 				  BTRFS_INODE_MAP_OBJECTID, inode_root);
2149f5fae2fSChris Mason 	BUG_ON(ret);
2159f5fae2fSChris Mason 
216e20d96d6SChris Mason 	ret = find_and_setup_root(disk_super, tree_root, fs_info,
217e20d96d6SChris Mason 				  BTRFS_FS_TREE_OBJECTID, root);
2183768f368SChris Mason 	BUG_ON(ret);
2193768f368SChris Mason 
220a28ec197SChris Mason 	root->commit_root = root->node;
221e20d96d6SChris Mason 	get_bh(root->node);
2223768f368SChris Mason 	root->ref_cows = 1;
223293ffd5fSChris Mason 	root->fs_info->generation = root->root_key.offset + 1;
224eb60ceacSChris Mason 	return root;
225eb60ceacSChris Mason }
226eb60ceacSChris Mason 
227e089f05cSChris Mason int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root
228e089f05cSChris Mason 		      *root, struct btrfs_super_block *s)
229cfaa7295SChris Mason {
230e20d96d6SChris Mason 	return 0;
231e20d96d6SChris Mason #if 0
232cfaa7295SChris Mason 	int ret;
233e20d96d6SChris Mason 	btrfs_set_super_root(s, root->fs_info->tree_root->node->b_blocknr);
234e20d96d6SChris Mason 
2359f5fae2fSChris Mason 	ret = pwrite(root->fs_info->fp, s, sizeof(*s),
236123abc88SChris Mason 		     BTRFS_SUPER_INFO_OFFSET);
237cfaa7295SChris Mason 	if (ret != sizeof(*s)) {
238cfaa7295SChris Mason 		fprintf(stderr, "failed to write new super block err %d\n", ret);
239cfaa7295SChris Mason 		return ret;
240cfaa7295SChris Mason 	}
241cfaa7295SChris Mason 	return 0;
242e20d96d6SChris Mason #endif
243cfaa7295SChris Mason }
244cfaa7295SChris Mason 
245234b63a0SChris Mason static int drop_cache(struct btrfs_root *root)
246ed2ff2cbSChris Mason {
247e20d96d6SChris Mason 	return 0;
248e20d96d6SChris Mason #if 0
2499f5fae2fSChris Mason 	while(!list_empty(&root->fs_info->cache)) {
250e20d96d6SChris Mason 		struct buffer_head *b = list_entry(root->fs_info->cache.next,
251e20d96d6SChris Mason 						    struct buffer_head,
2529f5fae2fSChris Mason 						    cache);
253ed2ff2cbSChris Mason 		list_del_init(&b->cache);
254234b63a0SChris Mason 		btrfs_block_release(root, b);
255ed2ff2cbSChris Mason 	}
256ed2ff2cbSChris Mason 	return 0;
257e20d96d6SChris Mason #endif
258ed2ff2cbSChris Mason }
259e20d96d6SChris Mason 
260e20d96d6SChris Mason int close_ctree(struct btrfs_root *root)
261eb60ceacSChris Mason {
2623768f368SChris Mason 	int ret;
263e089f05cSChris Mason 	struct btrfs_trans_handle *trans;
264e089f05cSChris Mason 
2659f5fae2fSChris Mason 	trans = root->fs_info->running_transaction;
266e20d96d6SChris Mason 	btrfs_commit_transaction(trans, root, root->fs_info->disk_super);
2679f5fae2fSChris Mason 	ret = commit_tree_roots(trans, root->fs_info);
2689f5fae2fSChris Mason 	BUG_ON(ret);
2699f5fae2fSChris Mason 	ret = __commit_transaction(trans, root);
2703768f368SChris Mason 	BUG_ON(ret);
271e20d96d6SChris Mason 	write_ctree_super(trans, root, root->fs_info->disk_super);
272ed2ff2cbSChris Mason 	drop_cache(root);
273ed2ff2cbSChris Mason 
274eb60ceacSChris Mason 	if (root->node)
275234b63a0SChris Mason 		btrfs_block_release(root, root->node);
2769f5fae2fSChris Mason 	if (root->fs_info->extent_root->node)
2779f5fae2fSChris Mason 		btrfs_block_release(root->fs_info->extent_root,
2789f5fae2fSChris Mason 				    root->fs_info->extent_root->node);
2799f5fae2fSChris Mason 	if (root->fs_info->inode_root->node)
2809f5fae2fSChris Mason 		btrfs_block_release(root->fs_info->inode_root,
2819f5fae2fSChris Mason 				    root->fs_info->inode_root->node);
2829f5fae2fSChris Mason 	if (root->fs_info->tree_root->node)
2839f5fae2fSChris Mason 		btrfs_block_release(root->fs_info->tree_root,
2849f5fae2fSChris Mason 				    root->fs_info->tree_root->node);
285234b63a0SChris Mason 	btrfs_block_release(root, root->commit_root);
286e20d96d6SChris Mason 	btrfs_block_release(root, root->fs_info->sb_buffer);
287e20d96d6SChris Mason 	kfree(root->fs_info->extent_root);
288e20d96d6SChris Mason 	kfree(root->fs_info->inode_root);
289e20d96d6SChris Mason 	kfree(root->fs_info->tree_root);
290e20d96d6SChris Mason 	kfree(root->fs_info);
291e20d96d6SChris Mason 	kfree(root);
292eb60ceacSChris Mason 	return 0;
293eb60ceacSChris Mason }
294eb60ceacSChris Mason 
295e20d96d6SChris Mason void btrfs_block_release(struct btrfs_root *root, struct buffer_head *buf)
296eb60ceacSChris Mason {
297e20d96d6SChris Mason 	brelse(buf);
298eb60ceacSChris Mason }
299eb60ceacSChris Mason 
300