xref: /openbmc/linux/fs/btrfs/disk-io.c (revision eb60ceac)
1eb60ceacSChris Mason #define _XOPEN_SOURCE 500
2eb60ceacSChris Mason #include <stdio.h>
3eb60ceacSChris Mason #include <stdlib.h>
4eb60ceacSChris Mason #include <sys/types.h>
5eb60ceacSChris Mason #include <sys/stat.h>
6eb60ceacSChris Mason #include <fcntl.h>
7eb60ceacSChris Mason #include <unistd.h>
8eb60ceacSChris Mason #include "kerncompat.h"
9eb60ceacSChris Mason #include "radix-tree.h"
10eb60ceacSChris Mason #include "ctree.h"
11eb60ceacSChris Mason #include "disk-io.h"
12eb60ceacSChris Mason 
13eb60ceacSChris Mason static int allocated_blocks = 0;
14eb60ceacSChris Mason 
15eb60ceacSChris Mason struct ctree_header {
16eb60ceacSChris Mason 	u64 root_block;
17eb60ceacSChris Mason } __attribute__ ((__packed__));
18eb60ceacSChris Mason 
19eb60ceacSChris Mason static int get_free_block(struct ctree_root *root, u64 *block)
20eb60ceacSChris Mason {
21eb60ceacSChris Mason 	struct stat st;
22eb60ceacSChris Mason 	int ret;
23eb60ceacSChris Mason 
24eb60ceacSChris Mason 	st.st_size = 0;
25eb60ceacSChris Mason 	ret = fstat(root->fp, &st);
26eb60ceacSChris Mason 	if (st.st_size > sizeof(struct ctree_header)) {
27eb60ceacSChris Mason 		*block = (st.st_size -
28eb60ceacSChris Mason 			sizeof(struct ctree_header)) / CTREE_BLOCKSIZE;
29eb60ceacSChris Mason 	} else {
30eb60ceacSChris Mason 		*block = 0;
31eb60ceacSChris Mason 	}
32eb60ceacSChris Mason 	ret = ftruncate(root->fp, sizeof(struct ctree_header) + (*block + 1) *
33eb60ceacSChris Mason 			CTREE_BLOCKSIZE);
34eb60ceacSChris Mason 	return ret;
35eb60ceacSChris Mason }
36eb60ceacSChris Mason 
37eb60ceacSChris Mason struct tree_buffer *alloc_tree_block(struct ctree_root *root, u64 blocknr)
38eb60ceacSChris Mason {
39eb60ceacSChris Mason 	struct tree_buffer *buf;
40eb60ceacSChris Mason 	int ret;
41eb60ceacSChris Mason 	buf = malloc(sizeof(struct tree_buffer));
42eb60ceacSChris Mason 	if (!buf)
43eb60ceacSChris Mason 		return buf;
44eb60ceacSChris Mason 	allocated_blocks++;
45eb60ceacSChris Mason 	buf->blocknr = blocknr;
46eb60ceacSChris Mason 	buf->count = 1;
47eb60ceacSChris Mason 	radix_tree_preload(GFP_KERNEL);
48eb60ceacSChris Mason 	ret = radix_tree_insert(&root->cache_radix, blocknr, buf);
49eb60ceacSChris Mason 	radix_tree_preload_end();
50eb60ceacSChris Mason 	if (ret) {
51eb60ceacSChris Mason 		free(buf);
52eb60ceacSChris Mason 		return NULL;
53eb60ceacSChris Mason 	}
54eb60ceacSChris Mason 	return buf;
55eb60ceacSChris Mason }
56eb60ceacSChris Mason 
57eb60ceacSChris Mason struct tree_buffer *alloc_free_block(struct ctree_root *root)
58eb60ceacSChris Mason {
59eb60ceacSChris Mason 	u64 free_block;
60eb60ceacSChris Mason 	int ret;
61eb60ceacSChris Mason 	struct tree_buffer * buf;
62eb60ceacSChris Mason 	ret = get_free_block(root, &free_block);
63eb60ceacSChris Mason 	if (ret) {
64eb60ceacSChris Mason 		BUG();
65eb60ceacSChris Mason 		return NULL;
66eb60ceacSChris Mason 	}
67eb60ceacSChris Mason 	buf = alloc_tree_block(root, free_block);
68eb60ceacSChris Mason 	if (!buf)
69eb60ceacSChris Mason 		BUG();
70eb60ceacSChris Mason 	return buf;
71eb60ceacSChris Mason }
72eb60ceacSChris Mason 
73eb60ceacSChris Mason struct tree_buffer *read_tree_block(struct ctree_root *root, u64 blocknr)
74eb60ceacSChris Mason {
75eb60ceacSChris Mason 	loff_t offset = blocknr * CTREE_BLOCKSIZE + sizeof(struct ctree_header);
76eb60ceacSChris Mason 	struct tree_buffer *buf;
77eb60ceacSChris Mason 	int ret;
78eb60ceacSChris Mason 
79eb60ceacSChris Mason 	buf = radix_tree_lookup(&root->cache_radix, blocknr);
80eb60ceacSChris Mason 	if (buf) {
81eb60ceacSChris Mason 		buf->count++;
82eb60ceacSChris Mason 		if (buf->blocknr != blocknr)
83eb60ceacSChris Mason 			BUG();
84eb60ceacSChris Mason 		if (buf->blocknr != buf->node.header.blocknr)
85eb60ceacSChris Mason 			BUG();
86eb60ceacSChris Mason 		return buf;
87eb60ceacSChris Mason 	}
88eb60ceacSChris Mason 	buf = alloc_tree_block(root, blocknr);
89eb60ceacSChris Mason 	if (!buf)
90eb60ceacSChris Mason 		return NULL;
91eb60ceacSChris Mason 	ret = pread(root->fp, &buf->node, CTREE_BLOCKSIZE, offset);
92eb60ceacSChris Mason 	if (ret != CTREE_BLOCKSIZE) {
93eb60ceacSChris Mason 		free(buf);
94eb60ceacSChris Mason 		return NULL;
95eb60ceacSChris Mason 	}
96eb60ceacSChris Mason 	if (buf->blocknr != buf->node.header.blocknr)
97eb60ceacSChris Mason 		BUG();
98eb60ceacSChris Mason 	return buf;
99eb60ceacSChris Mason }
100eb60ceacSChris Mason 
101eb60ceacSChris Mason int write_tree_block(struct ctree_root *root, struct tree_buffer *buf)
102eb60ceacSChris Mason {
103eb60ceacSChris Mason 	u64 blocknr = buf->blocknr;
104eb60ceacSChris Mason 	loff_t offset = blocknr * CTREE_BLOCKSIZE + sizeof(struct ctree_header);
105eb60ceacSChris Mason 	int ret;
106eb60ceacSChris Mason 
107eb60ceacSChris Mason 	if (buf->blocknr != buf->node.header.blocknr)
108eb60ceacSChris Mason 		BUG();
109eb60ceacSChris Mason 	ret = pwrite(root->fp, &buf->node, CTREE_BLOCKSIZE, offset);
110eb60ceacSChris Mason 	if (ret != CTREE_BLOCKSIZE)
111eb60ceacSChris Mason 		return ret;
112eb60ceacSChris Mason 	if (buf == root->node)
113eb60ceacSChris Mason 		return update_root_block(root);
114eb60ceacSChris Mason 	return 0;
115eb60ceacSChris Mason }
116eb60ceacSChris Mason 
117eb60ceacSChris Mason struct ctree_root *open_ctree(char *filename)
118eb60ceacSChris Mason {
119eb60ceacSChris Mason 	struct ctree_root *root = malloc(sizeof(struct ctree_root));
120eb60ceacSChris Mason 	int fp;
121eb60ceacSChris Mason 	u64 root_block;
122eb60ceacSChris Mason 	int ret;
123eb60ceacSChris Mason 
124eb60ceacSChris Mason 	fp = open(filename, O_CREAT | O_RDWR);
125eb60ceacSChris Mason 	if (fp < 0) {
126eb60ceacSChris Mason 		free(root);
127eb60ceacSChris Mason 		return NULL;
128eb60ceacSChris Mason 	}
129eb60ceacSChris Mason 	root->fp = fp;
130eb60ceacSChris Mason 	INIT_RADIX_TREE(&root->cache_radix, GFP_KERNEL);
131eb60ceacSChris Mason 	ret = pread(fp, &root_block, sizeof(u64), 0);
132eb60ceacSChris Mason 	if (ret == sizeof(u64)) {
133eb60ceacSChris Mason 		printf("reading root node at block %lu\n", root_block);
134eb60ceacSChris Mason 		root->node = read_tree_block(root, root_block);
135eb60ceacSChris Mason 	} else
136eb60ceacSChris Mason 		root->node = NULL;
137eb60ceacSChris Mason 	return root;
138eb60ceacSChris Mason }
139eb60ceacSChris Mason 
140eb60ceacSChris Mason int close_ctree(struct ctree_root *root)
141eb60ceacSChris Mason {
142eb60ceacSChris Mason 	close(root->fp);
143eb60ceacSChris Mason 	if (root->node)
144eb60ceacSChris Mason 		tree_block_release(root, root->node);
145eb60ceacSChris Mason 	free(root);
146eb60ceacSChris Mason 	printf("on close %d blocks are allocated\n", allocated_blocks);
147eb60ceacSChris Mason 	return 0;
148eb60ceacSChris Mason }
149eb60ceacSChris Mason 
150eb60ceacSChris Mason int update_root_block(struct ctree_root *root)
151eb60ceacSChris Mason {
152eb60ceacSChris Mason 	int ret;
153eb60ceacSChris Mason 	u64 root_block = root->node->blocknr;
154eb60ceacSChris Mason 
155eb60ceacSChris Mason 	ret = pwrite(root->fp, &root_block, sizeof(u64), 0);
156eb60ceacSChris Mason 	if (ret != sizeof(u64))
157eb60ceacSChris Mason 		return ret;
158eb60ceacSChris Mason 	return 0;
159eb60ceacSChris Mason }
160eb60ceacSChris Mason 
161eb60ceacSChris Mason void tree_block_release(struct ctree_root *root, struct tree_buffer *buf)
162eb60ceacSChris Mason {
163eb60ceacSChris Mason 	buf->count--;
164eb60ceacSChris Mason 	if (buf->count == 0) {
165eb60ceacSChris Mason 		if (!radix_tree_lookup(&root->cache_radix, buf->blocknr))
166eb60ceacSChris Mason 			BUG();
167eb60ceacSChris Mason 		radix_tree_delete(&root->cache_radix, buf->blocknr);
168eb60ceacSChris Mason 		memset(buf, 0, sizeof(*buf));
169eb60ceacSChris Mason 		free(buf);
170eb60ceacSChris Mason 		BUG_ON(allocated_blocks == 0);
171eb60ceacSChris Mason 		allocated_blocks--;
172eb60ceacSChris Mason 	}
173eb60ceacSChris Mason }
174eb60ceacSChris Mason 
175