file-item.c revision 84f54cfa78c81991e087309a9b379f25f1ffdb10
1#include <linux/module.h>
2#include "ctree.h"
3#include "disk-io.h"
4#include "transaction.h"
5#include "print-tree.h"
6
7#define MAX_CSUM_ITEMS(r) ((((BTRFS_LEAF_DATA_SIZE(r) - \
8			       sizeof(struct btrfs_item) * 2) / \
9			       BTRFS_CRC32_SIZE) - 1))
10int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
11			       struct btrfs_root *root,
12			       u64 objectid, u64 pos,
13			       u64 offset, u64 disk_num_blocks,
14			       u64 num_blocks)
15{
16	int ret = 0;
17	struct btrfs_file_extent_item *item;
18	struct btrfs_key file_key;
19	struct btrfs_path *path;
20
21	path = btrfs_alloc_path();
22	BUG_ON(!path);
23	btrfs_init_path(path);
24	file_key.objectid = objectid;
25	file_key.offset = pos;
26	file_key.flags = 0;
27	btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY);
28
29	ret = btrfs_insert_empty_item(trans, root, path, &file_key,
30				      sizeof(*item));
31	if (ret) {
32printk("failed to insert %Lu %Lu ret %d\n", objectid, pos, ret);
33btrfs_print_leaf(root, btrfs_buffer_leaf(path->nodes[0]));
34	}
35	BUG_ON(ret);
36	item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0],
37			      struct btrfs_file_extent_item);
38	btrfs_set_file_extent_disk_blocknr(item, offset);
39	btrfs_set_file_extent_disk_num_blocks(item, disk_num_blocks);
40	btrfs_set_file_extent_offset(item, 0);
41	btrfs_set_file_extent_num_blocks(item, num_blocks);
42	btrfs_set_file_extent_generation(item, trans->transid);
43	btrfs_set_file_extent_type(item, BTRFS_FILE_EXTENT_REG);
44	btrfs_mark_buffer_dirty(path->nodes[0]);
45
46	btrfs_release_path(root, path);
47	btrfs_free_path(path);
48	return 0;
49}
50
51struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans,
52					  struct btrfs_root *root,
53					  struct btrfs_path *path,
54					  u64 objectid, u64 offset,
55					  int cow)
56{
57	int ret;
58	struct btrfs_key file_key;
59	struct btrfs_key found_key;
60	struct btrfs_csum_item *item;
61	struct btrfs_leaf *leaf;
62	u64 csum_offset = 0;
63	int csums_in_item;
64
65	file_key.objectid = objectid;
66	file_key.offset = offset;
67	file_key.flags = 0;
68	btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY);
69	ret = btrfs_search_slot(trans, root, &file_key, path, 0, cow);
70	if (ret < 0)
71		goto fail;
72	leaf = btrfs_buffer_leaf(path->nodes[0]);
73	if (ret > 0) {
74		ret = 1;
75		if (path->slots[0] == 0)
76			goto fail;
77		path->slots[0]--;
78		btrfs_disk_key_to_cpu(&found_key,
79				      &leaf->items[path->slots[0]].key);
80		if (btrfs_key_type(&found_key) != BTRFS_CSUM_ITEM_KEY ||
81		    found_key.objectid != objectid) {
82			goto fail;
83		}
84		csum_offset = (offset - found_key.offset) >>
85				root->fs_info->sb->s_blocksize_bits;
86		csums_in_item = btrfs_item_size(leaf->items + path->slots[0]);
87		csums_in_item /= BTRFS_CRC32_SIZE;
88
89		if (csum_offset >= csums_in_item) {
90			ret = -EFBIG;
91			goto fail;
92		}
93	}
94	item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item);
95	item = (struct btrfs_csum_item *)((unsigned char *)item +
96					  csum_offset * BTRFS_CRC32_SIZE);
97	return item;
98fail:
99	if (ret > 0)
100		ret = -ENOENT;
101	return ERR_PTR(ret);
102}
103
104
105int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
106			     struct btrfs_root *root,
107			     struct btrfs_path *path, u64 objectid,
108			     u64 offset, int mod)
109{
110	int ret;
111	struct btrfs_key file_key;
112	int ins_len = mod < 0 ? -1 : 0;
113	int cow = mod != 0;
114
115	file_key.objectid = objectid;
116	file_key.offset = offset;
117	file_key.flags = 0;
118	btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY);
119	ret = btrfs_search_slot(trans, root, &file_key, path, ins_len, cow);
120	return ret;
121}
122
123int btrfs_csum_file_block(struct btrfs_trans_handle *trans,
124			  struct btrfs_root *root,
125			  u64 objectid, u64 offset,
126			  char *data, size_t len)
127{
128	int ret;
129	struct btrfs_key file_key;
130	struct btrfs_key found_key;
131	struct btrfs_path *path;
132	struct btrfs_csum_item *item;
133	struct btrfs_leaf *leaf;
134	u64 csum_offset;
135
136	path = btrfs_alloc_path();
137	BUG_ON(!path);
138
139	file_key.objectid = objectid;
140	file_key.offset = offset;
141	file_key.flags = 0;
142	btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY);
143
144	item = btrfs_lookup_csum(trans, root, path, objectid, offset, 1);
145	if (!IS_ERR(item))
146		goto found;
147	ret = PTR_ERR(item);
148	if (ret == -EFBIG) {
149		u32 item_size;
150		/* we found one, but it isn't big enough yet */
151		leaf = btrfs_buffer_leaf(path->nodes[0]);
152		item_size = btrfs_item_size(leaf->items + path->slots[0]);
153		if ((item_size / BTRFS_CRC32_SIZE) >= MAX_CSUM_ITEMS(root)) {
154			/* already at max size, make a new one */
155			goto insert;
156		}
157	} else {
158		/* we didn't find a csum item, insert one */
159		goto insert;
160	}
161
162	/*
163	 * at this point, we know the tree has an item, but it isn't big
164	 * enough yet to put our csum in.  Grow it
165	 */
166	btrfs_release_path(root, path);
167	ret = btrfs_search_slot(trans, root, &file_key, path,
168				BTRFS_CRC32_SIZE, 1);
169	if (ret < 0)
170		goto fail;
171	if (ret == 0) {
172		BUG();
173	}
174	if (path->slots[0] == 0) {
175		goto insert;
176	}
177	path->slots[0]--;
178	leaf = btrfs_buffer_leaf(path->nodes[0]);
179	btrfs_disk_key_to_cpu(&found_key, &leaf->items[path->slots[0]].key);
180	csum_offset = (offset - found_key.offset) >>
181			root->fs_info->sb->s_blocksize_bits;
182	if (btrfs_key_type(&found_key) != BTRFS_CSUM_ITEM_KEY ||
183	    found_key.objectid != objectid ||
184	    csum_offset >= MAX_CSUM_ITEMS(root)) {
185		goto insert;
186	}
187	if (csum_offset >= btrfs_item_size(leaf->items + path->slots[0]) /
188	    BTRFS_CRC32_SIZE) {
189		u32 diff = (csum_offset + 1) * BTRFS_CRC32_SIZE;
190		diff = diff - btrfs_item_size(leaf->items + path->slots[0]);
191		if (diff != BTRFS_CRC32_SIZE)
192			goto insert;
193		ret = btrfs_extend_item(trans, root, path, diff);
194		BUG_ON(ret);
195		goto csum;
196	}
197
198insert:
199	btrfs_release_path(root, path);
200	csum_offset = 0;
201	ret = btrfs_insert_empty_item(trans, root, path, &file_key,
202				      BTRFS_CRC32_SIZE);
203	if (ret != 0) {
204		printk("at insert for %Lu %u %Lu ret is %d\n", file_key.objectid, file_key.flags, file_key.offset, ret);
205		WARN_ON(1);
206		goto fail;
207	}
208csum:
209	item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0],
210			      struct btrfs_csum_item);
211	ret = 0;
212	item = (struct btrfs_csum_item *)((unsigned char *)item +
213					  csum_offset * BTRFS_CRC32_SIZE);
214found:
215	btrfs_check_bounds(&item->csum, BTRFS_CRC32_SIZE,
216			   path->nodes[0]->b_data,
217			   root->fs_info->sb->s_blocksize);
218	ret = btrfs_csum_data(root, data, len, &item->csum);
219	btrfs_mark_buffer_dirty(path->nodes[0]);
220fail:
221	btrfs_release_path(root, path);
222	btrfs_free_path(path);
223	return ret;
224}
225
226int btrfs_csum_truncate(struct btrfs_trans_handle *trans,
227			struct btrfs_root *root, struct btrfs_path *path,
228			u64 isize)
229{
230	struct btrfs_key key;
231	struct btrfs_leaf *leaf = btrfs_buffer_leaf(path->nodes[0]);
232	int slot = path->slots[0];
233	int ret;
234	u32 new_item_size;
235	u64 new_item_span;
236	u64 blocks;
237
238	btrfs_disk_key_to_cpu(&key, &leaf->items[slot].key);
239	if (isize <= key.offset)
240		return 0;
241	new_item_span = isize - key.offset;
242	blocks = (new_item_span + root->blocksize - 1) >>
243		root->fs_info->sb->s_blocksize_bits;
244	new_item_size = blocks * BTRFS_CRC32_SIZE;
245	if (new_item_size >= btrfs_item_size(leaf->items + slot))
246		return 0;
247	ret = btrfs_truncate_item(trans, root, path, new_item_size);
248	BUG_ON(ret);
249	return ret;
250}
251
252int btrfs_csum_verify_file_block(struct btrfs_root *root,
253				 u64 objectid, u64 offset,
254				 char *data, size_t len)
255{
256	int ret;
257	struct btrfs_key file_key;
258	struct btrfs_path *path;
259	struct btrfs_csum_item *item;
260	char result[BTRFS_CRC32_SIZE];
261
262	path = btrfs_alloc_path();
263	BUG_ON(!path);
264	btrfs_init_path(path);
265	file_key.objectid = objectid;
266	file_key.offset = offset;
267	file_key.flags = 0;
268	btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY);
269	mutex_lock(&root->fs_info->fs_mutex);
270
271	item = btrfs_lookup_csum(NULL, root, path, objectid, offset, 0);
272	if (IS_ERR(item)) {
273		ret = PTR_ERR(item);
274		/* a csum that isn't present is a preallocated region. */
275		if (ret == -ENOENT || ret == -EFBIG)
276			ret = -ENOENT;
277		goto fail;
278	}
279
280	ret = btrfs_csum_data(root, data, len, result);
281	WARN_ON(ret);
282	if (memcmp(result, &item->csum, BTRFS_CRC32_SIZE))
283		ret = 1;
284fail:
285	btrfs_release_path(root, path);
286	btrfs_free_path(path);
287	mutex_unlock(&root->fs_info->fs_mutex);
288	return ret;
289}
290
291