xref: /openbmc/linux/fs/btrfs/file-item.c (revision 459931eca5f4b8c9ad259d07cc1ca49afed54804)
16cbd5570SChris Mason /*
26cbd5570SChris Mason  * Copyright (C) 2007 Oracle.  All rights reserved.
36cbd5570SChris Mason  *
46cbd5570SChris Mason  * This program is free software; you can redistribute it and/or
56cbd5570SChris Mason  * modify it under the terms of the GNU General Public
66cbd5570SChris Mason  * License v2 as published by the Free Software Foundation.
76cbd5570SChris Mason  *
86cbd5570SChris Mason  * This program is distributed in the hope that it will be useful,
96cbd5570SChris Mason  * but WITHOUT ANY WARRANTY; without even the implied warranty of
106cbd5570SChris Mason  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
116cbd5570SChris Mason  * General Public License for more details.
126cbd5570SChris Mason  *
136cbd5570SChris Mason  * You should have received a copy of the GNU General Public
146cbd5570SChris Mason  * License along with this program; if not, write to the
156cbd5570SChris Mason  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
166cbd5570SChris Mason  * Boston, MA 021110-1307, USA.
176cbd5570SChris Mason  */
186cbd5570SChris Mason 
19065631f6SChris Mason #include <linux/bio.h>
20065631f6SChris Mason #include <linux/pagemap.h>
21065631f6SChris Mason #include <linux/highmem.h>
221e1d2701SChris Mason #include "ctree.h"
23dee26a9fSChris Mason #include "disk-io.h"
249f5fae2fSChris Mason #include "transaction.h"
251de037a4SChris Mason #include "print-tree.h"
261e1d2701SChris Mason 
27607d432dSJosef Bacik #define MAX_CSUM_ITEMS(r,size) ((((BTRFS_LEAF_DATA_SIZE(r) - \
28a429e513SChris Mason 				   sizeof(struct btrfs_item) * 2) / \
29607d432dSJosef Bacik 				  size) - 1))
30b18c6685SChris Mason int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
31dee26a9fSChris Mason 			     struct btrfs_root *root,
32b18c6685SChris Mason 			     u64 objectid, u64 pos,
33f2eb0a24SSage Weil 			     u64 disk_offset, u64 disk_num_bytes,
34c8b97818SChris Mason 			     u64 num_bytes, u64 offset, u64 ram_bytes,
35c8b97818SChris Mason 			     u8 compression, u8 encryption, u16 other_encoding)
369f5fae2fSChris Mason {
37dee26a9fSChris Mason 	int ret = 0;
38dee26a9fSChris Mason 	struct btrfs_file_extent_item *item;
39dee26a9fSChris Mason 	struct btrfs_key file_key;
405caf2a00SChris Mason 	struct btrfs_path *path;
415f39d397SChris Mason 	struct extent_buffer *leaf;
42dee26a9fSChris Mason 
435caf2a00SChris Mason 	path = btrfs_alloc_path();
445caf2a00SChris Mason 	BUG_ON(!path);
45dee26a9fSChris Mason 	file_key.objectid = objectid;
46b18c6685SChris Mason 	file_key.offset = pos;
47dee26a9fSChris Mason 	btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY);
48dee26a9fSChris Mason 
495caf2a00SChris Mason 	ret = btrfs_insert_empty_item(trans, root, path, &file_key,
50dee26a9fSChris Mason 				      sizeof(*item));
5154aa1f4dSChris Mason 	if (ret < 0)
5254aa1f4dSChris Mason 		goto out;
539773a788SChris Mason 	BUG_ON(ret);
545f39d397SChris Mason 	leaf = path->nodes[0];
555f39d397SChris Mason 	item = btrfs_item_ptr(leaf, path->slots[0],
56dee26a9fSChris Mason 			      struct btrfs_file_extent_item);
57f2eb0a24SSage Weil 	btrfs_set_file_extent_disk_bytenr(leaf, item, disk_offset);
58db94535dSChris Mason 	btrfs_set_file_extent_disk_num_bytes(leaf, item, disk_num_bytes);
59f2eb0a24SSage Weil 	btrfs_set_file_extent_offset(leaf, item, offset);
60db94535dSChris Mason 	btrfs_set_file_extent_num_bytes(leaf, item, num_bytes);
61c8b97818SChris Mason 	btrfs_set_file_extent_ram_bytes(leaf, item, ram_bytes);
625f39d397SChris Mason 	btrfs_set_file_extent_generation(leaf, item, trans->transid);
635f39d397SChris Mason 	btrfs_set_file_extent_type(leaf, item, BTRFS_FILE_EXTENT_REG);
64c8b97818SChris Mason 	btrfs_set_file_extent_compression(leaf, item, compression);
65c8b97818SChris Mason 	btrfs_set_file_extent_encryption(leaf, item, encryption);
66c8b97818SChris Mason 	btrfs_set_file_extent_other_encoding(leaf, item, other_encoding);
67c8b97818SChris Mason 
685f39d397SChris Mason 	btrfs_mark_buffer_dirty(leaf);
6954aa1f4dSChris Mason out:
705caf2a00SChris Mason 	btrfs_free_path(path);
7154aa1f4dSChris Mason 	return ret;
729f5fae2fSChris Mason }
73dee26a9fSChris Mason 
74b18c6685SChris Mason struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans,
75b18c6685SChris Mason 					  struct btrfs_root *root,
766567e837SChris Mason 					  struct btrfs_path *path,
77d20f7043SChris Mason 					  u64 bytenr, int cow)
786567e837SChris Mason {
796567e837SChris Mason 	int ret;
806567e837SChris Mason 	struct btrfs_key file_key;
816567e837SChris Mason 	struct btrfs_key found_key;
826567e837SChris Mason 	struct btrfs_csum_item *item;
835f39d397SChris Mason 	struct extent_buffer *leaf;
846567e837SChris Mason 	u64 csum_offset = 0;
85607d432dSJosef Bacik 	u16 csum_size =
86607d432dSJosef Bacik 		btrfs_super_csum_size(&root->fs_info->super_copy);
87a429e513SChris Mason 	int csums_in_item;
886567e837SChris Mason 
89d20f7043SChris Mason 	file_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
90d20f7043SChris Mason 	file_key.offset = bytenr;
91d20f7043SChris Mason 	btrfs_set_key_type(&file_key, BTRFS_EXTENT_CSUM_KEY);
92b18c6685SChris Mason 	ret = btrfs_search_slot(trans, root, &file_key, path, 0, cow);
936567e837SChris Mason 	if (ret < 0)
946567e837SChris Mason 		goto fail;
955f39d397SChris Mason 	leaf = path->nodes[0];
966567e837SChris Mason 	if (ret > 0) {
976567e837SChris Mason 		ret = 1;
9870b2befdSChris Mason 		if (path->slots[0] == 0)
996567e837SChris Mason 			goto fail;
1006567e837SChris Mason 		path->slots[0]--;
1015f39d397SChris Mason 		btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
102d20f7043SChris Mason 		if (btrfs_key_type(&found_key) != BTRFS_EXTENT_CSUM_KEY)
1036567e837SChris Mason 			goto fail;
104d20f7043SChris Mason 
105d20f7043SChris Mason 		csum_offset = (bytenr - found_key.offset) >>
1066567e837SChris Mason 				root->fs_info->sb->s_blocksize_bits;
1075f39d397SChris Mason 		csums_in_item = btrfs_item_size_nr(leaf, path->slots[0]);
108607d432dSJosef Bacik 		csums_in_item /= csum_size;
109a429e513SChris Mason 
110a429e513SChris Mason 		if (csum_offset >= csums_in_item) {
111a429e513SChris Mason 			ret = -EFBIG;
1126567e837SChris Mason 			goto fail;
1136567e837SChris Mason 		}
1146567e837SChris Mason 	}
1156567e837SChris Mason 	item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item);
116509659cdSChris Mason 	item = (struct btrfs_csum_item *)((unsigned char *)item +
117607d432dSJosef Bacik 					  csum_offset * csum_size);
1186567e837SChris Mason 	return item;
1196567e837SChris Mason fail:
1206567e837SChris Mason 	if (ret > 0)
121b18c6685SChris Mason 		ret = -ENOENT;
1226567e837SChris Mason 	return ERR_PTR(ret);
1236567e837SChris Mason }
1246567e837SChris Mason 
1256567e837SChris Mason 
126dee26a9fSChris Mason int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
127dee26a9fSChris Mason 			     struct btrfs_root *root,
128dee26a9fSChris Mason 			     struct btrfs_path *path, u64 objectid,
1299773a788SChris Mason 			     u64 offset, int mod)
130dee26a9fSChris Mason {
131dee26a9fSChris Mason 	int ret;
132dee26a9fSChris Mason 	struct btrfs_key file_key;
133dee26a9fSChris Mason 	int ins_len = mod < 0 ? -1 : 0;
134dee26a9fSChris Mason 	int cow = mod != 0;
135dee26a9fSChris Mason 
136dee26a9fSChris Mason 	file_key.objectid = objectid;
13770b2befdSChris Mason 	file_key.offset = offset;
138dee26a9fSChris Mason 	btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY);
139dee26a9fSChris Mason 	ret = btrfs_search_slot(trans, root, &file_key, path, ins_len, cow);
140dee26a9fSChris Mason 	return ret;
141dee26a9fSChris Mason }
142f254e52cSChris Mason 
14361b49440SChris Mason int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode,
144d20f7043SChris Mason 			  struct bio *bio, u32 *dst)
14561b49440SChris Mason {
14661b49440SChris Mason 	u32 sum;
14761b49440SChris Mason 	struct bio_vec *bvec = bio->bi_io_vec;
14861b49440SChris Mason 	int bio_index = 0;
14961b49440SChris Mason 	u64 offset;
15061b49440SChris Mason 	u64 item_start_offset = 0;
15161b49440SChris Mason 	u64 item_last_offset = 0;
152d20f7043SChris Mason 	u64 disk_bytenr;
15361b49440SChris Mason 	u32 diff;
154607d432dSJosef Bacik 	u16 csum_size =
155607d432dSJosef Bacik 		btrfs_super_csum_size(&root->fs_info->super_copy);
15661b49440SChris Mason 	int ret;
15761b49440SChris Mason 	struct btrfs_path *path;
15861b49440SChris Mason 	struct btrfs_csum_item *item = NULL;
15961b49440SChris Mason 	struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
16061b49440SChris Mason 
16161b49440SChris Mason 	path = btrfs_alloc_path();
1624d1b5fb4SChris Mason 	if (bio->bi_size > PAGE_CACHE_SIZE * 8)
1634d1b5fb4SChris Mason 		path->reada = 2;
16461b49440SChris Mason 
16561b49440SChris Mason 	WARN_ON(bio->bi_vcnt <= 0);
16661b49440SChris Mason 
167d20f7043SChris Mason 	disk_bytenr = (u64)bio->bi_sector << 9;
16861b49440SChris Mason 	while(bio_index < bio->bi_vcnt) {
16961b49440SChris Mason 		offset = page_offset(bvec->bv_page) + bvec->bv_offset;
170d20f7043SChris Mason 		ret = btrfs_find_ordered_sum(inode, offset, disk_bytenr, &sum);
17161b49440SChris Mason 		if (ret == 0)
17261b49440SChris Mason 			goto found;
17361b49440SChris Mason 
174d20f7043SChris Mason 		if (!item || disk_bytenr < item_start_offset ||
175d20f7043SChris Mason 		    disk_bytenr >= item_last_offset) {
17661b49440SChris Mason 			struct btrfs_key found_key;
17761b49440SChris Mason 			u32 item_size;
17861b49440SChris Mason 
17961b49440SChris Mason 			if (item)
18061b49440SChris Mason 				btrfs_release_path(root, path);
181d20f7043SChris Mason 			item = btrfs_lookup_csum(NULL, root->fs_info->csum_root,
182d20f7043SChris Mason 						 path, disk_bytenr, 0);
18361b49440SChris Mason 			if (IS_ERR(item)) {
18461b49440SChris Mason 				ret = PTR_ERR(item);
18561b49440SChris Mason 				if (ret == -ENOENT || ret == -EFBIG)
18661b49440SChris Mason 					ret = 0;
18761b49440SChris Mason 				sum = 0;
18861b49440SChris Mason 				printk("no csum found for inode %lu start "
18961b49440SChris Mason 				       "%llu\n", inode->i_ino,
19061b49440SChris Mason 				       (unsigned long long)offset);
1916dab8157SChris Mason 				item = NULL;
19239be25cdSChris Mason 				btrfs_release_path(root, path);
19361b49440SChris Mason 				goto found;
19461b49440SChris Mason 			}
19561b49440SChris Mason 			btrfs_item_key_to_cpu(path->nodes[0], &found_key,
19661b49440SChris Mason 					      path->slots[0]);
19761b49440SChris Mason 
19861b49440SChris Mason 			item_start_offset = found_key.offset;
19961b49440SChris Mason 			item_size = btrfs_item_size_nr(path->nodes[0],
20061b49440SChris Mason 						       path->slots[0]);
20161b49440SChris Mason 			item_last_offset = item_start_offset +
202607d432dSJosef Bacik 				(item_size / csum_size) *
20361b49440SChris Mason 				root->sectorsize;
20461b49440SChris Mason 			item = btrfs_item_ptr(path->nodes[0], path->slots[0],
20561b49440SChris Mason 					      struct btrfs_csum_item);
20661b49440SChris Mason 		}
20761b49440SChris Mason 		/*
20861b49440SChris Mason 		 * this byte range must be able to fit inside
20961b49440SChris Mason 		 * a single leaf so it will also fit inside a u32
21061b49440SChris Mason 		 */
211d20f7043SChris Mason 		diff = disk_bytenr - item_start_offset;
21261b49440SChris Mason 		diff = diff / root->sectorsize;
213607d432dSJosef Bacik 		diff = diff * csum_size;
21461b49440SChris Mason 
21561b49440SChris Mason 		read_extent_buffer(path->nodes[0], &sum,
2163de9d6b6SChris Mason 				   ((unsigned long)item) + diff,
217607d432dSJosef Bacik 				   csum_size);
21861b49440SChris Mason found:
219d20f7043SChris Mason 		if (dst)
220d20f7043SChris Mason 			*dst++ = sum;
221d20f7043SChris Mason 		else
22261b49440SChris Mason 			set_state_private(io_tree, offset, sum);
223d20f7043SChris Mason 		disk_bytenr += bvec->bv_len;
22461b49440SChris Mason 		bio_index++;
22561b49440SChris Mason 		bvec++;
22661b49440SChris Mason 	}
22761b49440SChris Mason 	btrfs_free_path(path);
22861b49440SChris Mason 	return 0;
22961b49440SChris Mason }
23061b49440SChris Mason 
2313edf7d33SChris Mason int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode,
232d20f7043SChris Mason 		       struct bio *bio, u64 file_start, int contig)
233e015640fSChris Mason {
234e6dcd2dcSChris Mason 	struct btrfs_ordered_sum *sums;
235e6dcd2dcSChris Mason 	struct btrfs_sector_sum *sector_sum;
2363edf7d33SChris Mason 	struct btrfs_ordered_extent *ordered;
237e015640fSChris Mason 	char *data;
238e015640fSChris Mason 	struct bio_vec *bvec = bio->bi_io_vec;
239e015640fSChris Mason 	int bio_index = 0;
2403edf7d33SChris Mason 	unsigned long total_bytes = 0;
2413edf7d33SChris Mason 	unsigned long this_sum_bytes = 0;
2423edf7d33SChris Mason 	u64 offset;
243d20f7043SChris Mason 	u64 disk_bytenr;
244e015640fSChris Mason 
245e6dcd2dcSChris Mason 	WARN_ON(bio->bi_vcnt <= 0);
246e6dcd2dcSChris Mason 	sums = kzalloc(btrfs_ordered_sum_size(root, bio->bi_size), GFP_NOFS);
247e015640fSChris Mason 	if (!sums)
248e015640fSChris Mason 		return -ENOMEM;
2493edf7d33SChris Mason 
250ed98b56aSChris Mason 	sector_sum = sums->sums;
251d20f7043SChris Mason 	disk_bytenr = (u64)bio->bi_sector << 9;
252e6dcd2dcSChris Mason 	sums->len = bio->bi_size;
253e6dcd2dcSChris Mason 	INIT_LIST_HEAD(&sums->list);
254d20f7043SChris Mason 
255d20f7043SChris Mason 	if (contig)
256d20f7043SChris Mason 		offset = file_start;
257d20f7043SChris Mason 	else
258d20f7043SChris Mason 		offset = page_offset(bvec->bv_page) + bvec->bv_offset;
259d20f7043SChris Mason 
260d20f7043SChris Mason 	ordered = btrfs_lookup_ordered_extent(inode, offset);
2613edf7d33SChris Mason 	BUG_ON(!ordered);
262d20f7043SChris Mason 	sums->bytenr = ordered->start;
263e015640fSChris Mason 
264e015640fSChris Mason 	while(bio_index < bio->bi_vcnt) {
265d20f7043SChris Mason 		if (!contig)
2663edf7d33SChris Mason 			offset = page_offset(bvec->bv_page) + bvec->bv_offset;
267d20f7043SChris Mason 
268d20f7043SChris Mason 		if (!contig && (offset >= ordered->file_offset + ordered->len ||
269d20f7043SChris Mason 		    offset < ordered->file_offset)) {
2703edf7d33SChris Mason 			unsigned long bytes_left;
2713edf7d33SChris Mason 			sums->len = this_sum_bytes;
2723edf7d33SChris Mason 			this_sum_bytes = 0;
2733edf7d33SChris Mason 			btrfs_add_ordered_sum(inode, ordered, sums);
2743edf7d33SChris Mason 			btrfs_put_ordered_extent(ordered);
2753edf7d33SChris Mason 
2763edf7d33SChris Mason 			bytes_left = bio->bi_size - total_bytes;
2773edf7d33SChris Mason 
2783edf7d33SChris Mason 			sums = kzalloc(btrfs_ordered_sum_size(root, bytes_left),
2793edf7d33SChris Mason 				       GFP_NOFS);
2803edf7d33SChris Mason 			BUG_ON(!sums);
281ed98b56aSChris Mason 			sector_sum = sums->sums;
2823edf7d33SChris Mason 			sums->len = bytes_left;
283d20f7043SChris Mason 			ordered = btrfs_lookup_ordered_extent(inode, offset);
2843edf7d33SChris Mason 			BUG_ON(!ordered);
285d20f7043SChris Mason 			sums->bytenr = ordered->start;
2863edf7d33SChris Mason 		}
2873edf7d33SChris Mason 
288e015640fSChris Mason 		data = kmap_atomic(bvec->bv_page, KM_USER0);
289e6dcd2dcSChris Mason 		sector_sum->sum = ~(u32)0;
290e6dcd2dcSChris Mason 		sector_sum->sum = btrfs_csum_data(root,
291e6dcd2dcSChris Mason 						  data + bvec->bv_offset,
292e6dcd2dcSChris Mason 						  sector_sum->sum,
293e6dcd2dcSChris Mason 						  bvec->bv_len);
294e015640fSChris Mason 		kunmap_atomic(data, KM_USER0);
295e6dcd2dcSChris Mason 		btrfs_csum_final(sector_sum->sum,
296e6dcd2dcSChris Mason 				 (char *)&sector_sum->sum);
297d20f7043SChris Mason 		sector_sum->bytenr = disk_bytenr;
298ed98b56aSChris Mason 
299e6dcd2dcSChris Mason 		sector_sum++;
300e015640fSChris Mason 		bio_index++;
3013edf7d33SChris Mason 		total_bytes += bvec->bv_len;
3023edf7d33SChris Mason 		this_sum_bytes += bvec->bv_len;
303d20f7043SChris Mason 		disk_bytenr += bvec->bv_len;
304d20f7043SChris Mason 		offset += bvec->bv_len;
305e015640fSChris Mason 		bvec++;
306e015640fSChris Mason 	}
307ed98b56aSChris Mason 	this_sum_bytes = 0;
3083edf7d33SChris Mason 	btrfs_add_ordered_sum(inode, ordered, sums);
3093edf7d33SChris Mason 	btrfs_put_ordered_extent(ordered);
310e015640fSChris Mason 	return 0;
311e015640fSChris Mason }
312e015640fSChris Mason 
313*459931ecSChris Mason /*
314*459931ecSChris Mason  * helper function for csum removal, this expects the
315*459931ecSChris Mason  * key to describe the csum pointed to by the path, and it expects
316*459931ecSChris Mason  * the csum to overlap the range [bytenr, len]
317*459931ecSChris Mason  *
318*459931ecSChris Mason  * The csum should not be entirely contained in the range and the
319*459931ecSChris Mason  * range should not be entirely contained in the csum.
320*459931ecSChris Mason  *
321*459931ecSChris Mason  * This calls btrfs_truncate_item with the correct args based on the
322*459931ecSChris Mason  * overlap, and fixes up the key as required.
323*459931ecSChris Mason  */
324*459931ecSChris Mason static noinline int truncate_one_csum(struct btrfs_trans_handle *trans,
325*459931ecSChris Mason 				      struct btrfs_root *root,
326*459931ecSChris Mason 				      struct btrfs_path *path,
327*459931ecSChris Mason 				      struct btrfs_key *key,
328*459931ecSChris Mason 				      u64 bytenr, u64 len)
329*459931ecSChris Mason {
330*459931ecSChris Mason 	struct extent_buffer *leaf;
331*459931ecSChris Mason 	u16 csum_size =
332*459931ecSChris Mason 		btrfs_super_csum_size(&root->fs_info->super_copy);
333*459931ecSChris Mason 	u64 csum_end;
334*459931ecSChris Mason 	u64 end_byte = bytenr + len;
335*459931ecSChris Mason 	u32 blocksize_bits = root->fs_info->sb->s_blocksize_bits;
336*459931ecSChris Mason 	int ret;
337*459931ecSChris Mason 
338*459931ecSChris Mason 	leaf = path->nodes[0];
339*459931ecSChris Mason 	csum_end = btrfs_item_size_nr(leaf, path->slots[0]) / csum_size;
340*459931ecSChris Mason 	csum_end <<= root->fs_info->sb->s_blocksize_bits;
341*459931ecSChris Mason 	csum_end += key->offset;
342*459931ecSChris Mason 
343*459931ecSChris Mason 	if (key->offset < bytenr && csum_end <= end_byte) {
344*459931ecSChris Mason 		/*
345*459931ecSChris Mason 		 *         [ bytenr - len ]
346*459931ecSChris Mason 		 *         [   ]
347*459931ecSChris Mason 		 *   [csum     ]
348*459931ecSChris Mason 		 *   A simple truncate off the end of the item
349*459931ecSChris Mason 		 */
350*459931ecSChris Mason 		u32 new_size = (bytenr - key->offset) >> blocksize_bits;
351*459931ecSChris Mason 		new_size *= csum_size;
352*459931ecSChris Mason 		ret = btrfs_truncate_item(trans, root, path, new_size, 1);
353*459931ecSChris Mason 		BUG_ON(ret);
354*459931ecSChris Mason 	} else if (key->offset >= bytenr && csum_end > end_byte &&
355*459931ecSChris Mason 		   end_byte > key->offset) {
356*459931ecSChris Mason 		/*
357*459931ecSChris Mason 		 *         [ bytenr - len ]
358*459931ecSChris Mason 		 *                 [ ]
359*459931ecSChris Mason 		 *                 [csum     ]
360*459931ecSChris Mason 		 * we need to truncate from the beginning of the csum
361*459931ecSChris Mason 		 */
362*459931ecSChris Mason 		u32 new_size = (csum_end - end_byte) >> blocksize_bits;
363*459931ecSChris Mason 		new_size *= csum_size;
364*459931ecSChris Mason 
365*459931ecSChris Mason 		ret = btrfs_truncate_item(trans, root, path, new_size, 0);
366*459931ecSChris Mason 		BUG_ON(ret);
367*459931ecSChris Mason 
368*459931ecSChris Mason 		key->offset = end_byte;
369*459931ecSChris Mason 		ret = btrfs_set_item_key_safe(trans, root, path, key);
370*459931ecSChris Mason 		BUG_ON(ret);
371*459931ecSChris Mason 	} else {
372*459931ecSChris Mason 		BUG();
373*459931ecSChris Mason 	}
374*459931ecSChris Mason 	return 0;
375*459931ecSChris Mason }
376*459931ecSChris Mason 
377*459931ecSChris Mason /*
378*459931ecSChris Mason  * deletes the csum items from the csum tree for a given
379*459931ecSChris Mason  * range of bytes.
380*459931ecSChris Mason  */
381*459931ecSChris Mason int btrfs_del_csums(struct btrfs_trans_handle *trans,
382*459931ecSChris Mason 		    struct btrfs_root *root, u64 bytenr, u64 len)
383*459931ecSChris Mason {
384*459931ecSChris Mason 	struct btrfs_path *path;
385*459931ecSChris Mason 	struct btrfs_key key;
386*459931ecSChris Mason 	u64 end_byte = bytenr + len;
387*459931ecSChris Mason 	u64 csum_end;
388*459931ecSChris Mason 	struct extent_buffer *leaf;
389*459931ecSChris Mason 	int ret;
390*459931ecSChris Mason 	u16 csum_size =
391*459931ecSChris Mason 		btrfs_super_csum_size(&root->fs_info->super_copy);
392*459931ecSChris Mason 	int blocksize_bits = root->fs_info->sb->s_blocksize_bits;
393*459931ecSChris Mason 
394*459931ecSChris Mason 	root = root->fs_info->csum_root;
395*459931ecSChris Mason 
396*459931ecSChris Mason 	path = btrfs_alloc_path();
397*459931ecSChris Mason 
398*459931ecSChris Mason 	while(1) {
399*459931ecSChris Mason 		key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
400*459931ecSChris Mason 		key.offset = end_byte - 1;
401*459931ecSChris Mason 		key.type = BTRFS_EXTENT_CSUM_KEY;
402*459931ecSChris Mason 
403*459931ecSChris Mason 		ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
404*459931ecSChris Mason 		if (ret > 0) {
405*459931ecSChris Mason 			if (path->slots[0] == 0)
406*459931ecSChris Mason 				goto out;
407*459931ecSChris Mason 			path->slots[0]--;
408*459931ecSChris Mason 		}
409*459931ecSChris Mason 		leaf = path->nodes[0];
410*459931ecSChris Mason 		btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
411*459931ecSChris Mason 
412*459931ecSChris Mason 		if (key.objectid != BTRFS_EXTENT_CSUM_OBJECTID ||
413*459931ecSChris Mason 		    key.type != BTRFS_EXTENT_CSUM_KEY) {
414*459931ecSChris Mason 			break;
415*459931ecSChris Mason 		}
416*459931ecSChris Mason 
417*459931ecSChris Mason 		if (key.offset >= end_byte)
418*459931ecSChris Mason 			break;
419*459931ecSChris Mason 
420*459931ecSChris Mason 		csum_end = btrfs_item_size_nr(leaf, path->slots[0]) / csum_size;
421*459931ecSChris Mason 		csum_end <<= blocksize_bits;
422*459931ecSChris Mason 		csum_end += key.offset;
423*459931ecSChris Mason 
424*459931ecSChris Mason 		/* this csum ends before we start, we're done */
425*459931ecSChris Mason 		if (csum_end <= bytenr)
426*459931ecSChris Mason 			break;
427*459931ecSChris Mason 
428*459931ecSChris Mason 		/* delete the entire item, it is inside our range */
429*459931ecSChris Mason 		if (key.offset >= bytenr && csum_end <= end_byte) {
430*459931ecSChris Mason 			ret = btrfs_del_item(trans, root, path);
431*459931ecSChris Mason 			BUG_ON(ret);
432*459931ecSChris Mason 		} else if (key.offset < bytenr && csum_end > end_byte) {
433*459931ecSChris Mason 			unsigned long offset;
434*459931ecSChris Mason 			unsigned long shift_len;
435*459931ecSChris Mason 			unsigned long item_offset;
436*459931ecSChris Mason 			/*
437*459931ecSChris Mason 			 *        [ bytenr - len ]
438*459931ecSChris Mason 			 *     [csum                ]
439*459931ecSChris Mason 			 *
440*459931ecSChris Mason 			 * Our bytes are in the middle of the csum,
441*459931ecSChris Mason 			 * we need to split this item and insert a new one.
442*459931ecSChris Mason 			 *
443*459931ecSChris Mason 			 * But we can't drop the path because the
444*459931ecSChris Mason 			 * csum could change, get removed, extended etc.
445*459931ecSChris Mason 			 *
446*459931ecSChris Mason 			 * The trick here is the max size of a csum item leaves
447*459931ecSChris Mason 			 * enough room in the tree block for a single
448*459931ecSChris Mason 			 * item header.  So, we split the item in place,
449*459931ecSChris Mason 			 * adding a new header pointing to the existing
450*459931ecSChris Mason 			 * bytes.  Then we loop around again and we have
451*459931ecSChris Mason 			 * a nicely formed csum item that we can neatly
452*459931ecSChris Mason 			 * truncate.
453*459931ecSChris Mason 			 */
454*459931ecSChris Mason 			offset = (bytenr - key.offset) >> blocksize_bits;
455*459931ecSChris Mason 			offset *= csum_size;
456*459931ecSChris Mason 
457*459931ecSChris Mason 			shift_len = (len >> blocksize_bits) * csum_size;
458*459931ecSChris Mason 
459*459931ecSChris Mason 			item_offset = btrfs_item_ptr_offset(leaf,
460*459931ecSChris Mason 							    path->slots[0]);
461*459931ecSChris Mason 
462*459931ecSChris Mason 			memset_extent_buffer(leaf, 0, item_offset + offset,
463*459931ecSChris Mason 					     shift_len);
464*459931ecSChris Mason 			key.offset = bytenr;
465*459931ecSChris Mason 
466*459931ecSChris Mason 			/*
467*459931ecSChris Mason 			 * btrfs_split_item returns -EAGAIN when the
468*459931ecSChris Mason 			 * item changed size or key
469*459931ecSChris Mason 			 */
470*459931ecSChris Mason 			ret = btrfs_split_item(trans, root, path, &key, offset);
471*459931ecSChris Mason 			BUG_ON(ret && ret != -EAGAIN);
472*459931ecSChris Mason 
473*459931ecSChris Mason 			key.offset = end_byte - 1;
474*459931ecSChris Mason 		} else {
475*459931ecSChris Mason 			ret = truncate_one_csum(trans, root, path,
476*459931ecSChris Mason 						&key, bytenr, len);
477*459931ecSChris Mason 			BUG_ON(ret);
478*459931ecSChris Mason 		}
479*459931ecSChris Mason 		btrfs_release_path(root, path);
480*459931ecSChris Mason 	}
481*459931ecSChris Mason out:
482*459931ecSChris Mason 	btrfs_free_path(path);
483*459931ecSChris Mason 	return 0;
484*459931ecSChris Mason }
485*459931ecSChris Mason 
486065631f6SChris Mason int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
487d20f7043SChris Mason 			   struct btrfs_root *root,
488e6dcd2dcSChris Mason 			   struct btrfs_ordered_sum *sums)
489f254e52cSChris Mason {
490d20f7043SChris Mason 	u64 bytenr;
491f254e52cSChris Mason 	int ret;
492f254e52cSChris Mason 	struct btrfs_key file_key;
4936567e837SChris Mason 	struct btrfs_key found_key;
494065631f6SChris Mason 	u64 next_offset;
495e6dcd2dcSChris Mason 	u64 total_bytes = 0;
496065631f6SChris Mason 	int found_next;
4975caf2a00SChris Mason 	struct btrfs_path *path;
498f254e52cSChris Mason 	struct btrfs_csum_item *item;
499065631f6SChris Mason 	struct btrfs_csum_item *item_end;
500ff79f819SChris Mason 	struct extent_buffer *leaf = NULL;
5016567e837SChris Mason 	u64 csum_offset;
502e6dcd2dcSChris Mason 	struct btrfs_sector_sum *sector_sum;
503f578d4bdSChris Mason 	u32 nritems;
504f578d4bdSChris Mason 	u32 ins_size;
5056e92f5e6SChris Mason 	char *eb_map;
5066e92f5e6SChris Mason 	char *eb_token;
5076e92f5e6SChris Mason 	unsigned long map_len;
5086e92f5e6SChris Mason 	unsigned long map_start;
509607d432dSJosef Bacik 	u16 csum_size =
510607d432dSJosef Bacik 		btrfs_super_csum_size(&root->fs_info->super_copy);
5116e92f5e6SChris Mason 
5125caf2a00SChris Mason 	path = btrfs_alloc_path();
5135caf2a00SChris Mason 	BUG_ON(!path);
514ed98b56aSChris Mason 	sector_sum = sums->sums;
515065631f6SChris Mason again:
516065631f6SChris Mason 	next_offset = (u64)-1;
517065631f6SChris Mason 	found_next = 0;
518d20f7043SChris Mason 	file_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
519d20f7043SChris Mason 	file_key.offset = sector_sum->bytenr;
520d20f7043SChris Mason 	bytenr = sector_sum->bytenr;
521d20f7043SChris Mason 	btrfs_set_key_type(&file_key, BTRFS_EXTENT_CSUM_KEY);
522a429e513SChris Mason 
523d20f7043SChris Mason 	item = btrfs_lookup_csum(trans, root, path, sector_sum->bytenr, 1);
524ff79f819SChris Mason 	if (!IS_ERR(item)) {
525ff79f819SChris Mason 		leaf = path->nodes[0];
526639cb586SChris Mason 		ret = 0;
527a429e513SChris Mason 		goto found;
528ff79f819SChris Mason 	}
529a429e513SChris Mason 	ret = PTR_ERR(item);
530a429e513SChris Mason 	if (ret == -EFBIG) {
531a429e513SChris Mason 		u32 item_size;
532a429e513SChris Mason 		/* we found one, but it isn't big enough yet */
5335f39d397SChris Mason 		leaf = path->nodes[0];
5345f39d397SChris Mason 		item_size = btrfs_item_size_nr(leaf, path->slots[0]);
535607d432dSJosef Bacik 		if ((item_size / csum_size) >=
536607d432dSJosef Bacik 		    MAX_CSUM_ITEMS(root, csum_size)) {
537a429e513SChris Mason 			/* already at max size, make a new one */
538a429e513SChris Mason 			goto insert;
539a429e513SChris Mason 		}
540a429e513SChris Mason 	} else {
541f578d4bdSChris Mason 		int slot = path->slots[0] + 1;
542a429e513SChris Mason 		/* we didn't find a csum item, insert one */
543f578d4bdSChris Mason 		nritems = btrfs_header_nritems(path->nodes[0]);
544f578d4bdSChris Mason 		if (path->slots[0] >= nritems - 1) {
545f578d4bdSChris Mason 			ret = btrfs_next_leaf(root, path);
546b56baf5bSYan 			if (ret == 1)
547f578d4bdSChris Mason 				found_next = 1;
548b56baf5bSYan 			if (ret != 0)
549f578d4bdSChris Mason 				goto insert;
550b56baf5bSYan 			slot = 0;
551f578d4bdSChris Mason 		}
552f578d4bdSChris Mason 		btrfs_item_key_to_cpu(path->nodes[0], &found_key, slot);
553d20f7043SChris Mason 		if (found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID ||
554d20f7043SChris Mason 		    found_key.type != BTRFS_EXTENT_CSUM_KEY) {
555f578d4bdSChris Mason 			found_next = 1;
556f578d4bdSChris Mason 			goto insert;
557f578d4bdSChris Mason 		}
558f578d4bdSChris Mason 		next_offset = found_key.offset;
559f578d4bdSChris Mason 		found_next = 1;
560a429e513SChris Mason 		goto insert;
561a429e513SChris Mason 	}
562a429e513SChris Mason 
563a429e513SChris Mason 	/*
564a429e513SChris Mason 	 * at this point, we know the tree has an item, but it isn't big
565a429e513SChris Mason 	 * enough yet to put our csum in.  Grow it
566a429e513SChris Mason 	 */
567a429e513SChris Mason 	btrfs_release_path(root, path);
5686567e837SChris Mason 	ret = btrfs_search_slot(trans, root, &file_key, path,
569607d432dSJosef Bacik 				csum_size, 1);
5706567e837SChris Mason 	if (ret < 0)
57153863232SChris Mason 		goto fail_unlock;
572*459931ecSChris Mason 
573*459931ecSChris Mason 	if (ret > 0) {
574*459931ecSChris Mason 		if (path->slots[0] == 0)
5756567e837SChris Mason 			goto insert;
5766567e837SChris Mason 		path->slots[0]--;
577*459931ecSChris Mason 	}
578*459931ecSChris Mason 
5795f39d397SChris Mason 	leaf = path->nodes[0];
5805f39d397SChris Mason 	btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
581d20f7043SChris Mason 	csum_offset = (bytenr - found_key.offset) >>
5826567e837SChris Mason 			root->fs_info->sb->s_blocksize_bits;
583*459931ecSChris Mason 
584d20f7043SChris Mason 	if (btrfs_key_type(&found_key) != BTRFS_EXTENT_CSUM_KEY ||
585d20f7043SChris Mason 	    found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID ||
586607d432dSJosef Bacik 	    csum_offset >= MAX_CSUM_ITEMS(root, csum_size)) {
5876567e837SChris Mason 		goto insert;
5886567e837SChris Mason 	}
589*459931ecSChris Mason 
5905f39d397SChris Mason 	if (csum_offset >= btrfs_item_size_nr(leaf, path->slots[0]) /
591607d432dSJosef Bacik 	    csum_size) {
592607d432dSJosef Bacik 		u32 diff = (csum_offset + 1) * csum_size;
593*459931ecSChris Mason 
594*459931ecSChris Mason 		/*
595*459931ecSChris Mason 		 * is the item big enough already?  we dropped our lock
596*459931ecSChris Mason 		 * before and need to recheck
597*459931ecSChris Mason 		 */
598*459931ecSChris Mason 		if (diff < btrfs_item_size_nr(leaf, path->slots[0]))
599*459931ecSChris Mason 			goto csum;
600*459931ecSChris Mason 
6015f39d397SChris Mason 		diff = diff - btrfs_item_size_nr(leaf, path->slots[0]);
602*459931ecSChris Mason 		if (diff != csum_size) {
6033a686375SChris Mason 			goto insert;
604*459931ecSChris Mason 		}
605*459931ecSChris Mason 
606a429e513SChris Mason 		ret = btrfs_extend_item(trans, root, path, diff);
6076567e837SChris Mason 		BUG_ON(ret);
6086567e837SChris Mason 		goto csum;
6096567e837SChris Mason 	}
6106567e837SChris Mason 
6116567e837SChris Mason insert:
612a429e513SChris Mason 	btrfs_release_path(root, path);
6136567e837SChris Mason 	csum_offset = 0;
614f578d4bdSChris Mason 	if (found_next) {
615d20f7043SChris Mason 		u64 tmp = total_bytes + root->sectorsize;
616d20f7043SChris Mason 		u64 next_sector = sector_sum->bytenr;
617d20f7043SChris Mason 		struct btrfs_sector_sum *next = sector_sum + 1;
618d20f7043SChris Mason 
619d20f7043SChris Mason 		while(tmp < sums->len) {
620d20f7043SChris Mason 			if (next_sector + root->sectorsize != next->bytenr)
621d20f7043SChris Mason 				break;
622d20f7043SChris Mason 			tmp += root->sectorsize;
623d20f7043SChris Mason 			next_sector = next->bytenr;
624d20f7043SChris Mason 			next++;
625d20f7043SChris Mason 		}
626d20f7043SChris Mason 		tmp = min(tmp, next_offset - file_key.offset);
627f578d4bdSChris Mason 		tmp >>= root->fs_info->sb->s_blocksize_bits;
628f578d4bdSChris Mason 		tmp = max((u64)1, tmp);
629607d432dSJosef Bacik 		tmp = min(tmp, (u64)MAX_CSUM_ITEMS(root, csum_size));
630607d432dSJosef Bacik 		ins_size = csum_size * tmp;
631f578d4bdSChris Mason 	} else {
632607d432dSJosef Bacik 		ins_size = csum_size;
633f578d4bdSChris Mason 	}
6345caf2a00SChris Mason 	ret = btrfs_insert_empty_item(trans, root, path, &file_key,
635f578d4bdSChris Mason 				      ins_size);
63654aa1f4dSChris Mason 	if (ret < 0)
63753863232SChris Mason 		goto fail_unlock;
638a429e513SChris Mason 	if (ret != 0) {
639a429e513SChris Mason 		WARN_ON(1);
64053863232SChris Mason 		goto fail_unlock;
641a429e513SChris Mason 	}
6426567e837SChris Mason csum:
6435f39d397SChris Mason 	leaf = path->nodes[0];
6445f39d397SChris Mason 	item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item);
645f254e52cSChris Mason 	ret = 0;
646509659cdSChris Mason 	item = (struct btrfs_csum_item *)((unsigned char *)item +
647607d432dSJosef Bacik 					  csum_offset * csum_size);
648b18c6685SChris Mason found:
649065631f6SChris Mason 	item_end = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item);
650065631f6SChris Mason 	item_end = (struct btrfs_csum_item *)((unsigned char *)item_end +
651065631f6SChris Mason 				      btrfs_item_size_nr(leaf, path->slots[0]));
6526e92f5e6SChris Mason 	eb_token = NULL;
65353863232SChris Mason 	cond_resched();
654e6dcd2dcSChris Mason next_sector:
655aadfeb6eSChris Mason 
6566e92f5e6SChris Mason 	if (!eb_token ||
657607d432dSJosef Bacik 	   (unsigned long)item + csum_size >= map_start + map_len) {
6586e92f5e6SChris Mason 		int err;
6596e92f5e6SChris Mason 
6606e92f5e6SChris Mason 		if (eb_token)
661eb20978fSChris Mason 			unmap_extent_buffer(leaf, eb_token, KM_USER1);
6626e92f5e6SChris Mason 		eb_token = NULL;
6636e92f5e6SChris Mason 		err = map_private_extent_buffer(leaf, (unsigned long)item,
664607d432dSJosef Bacik 						csum_size,
6656e92f5e6SChris Mason 						&eb_token, &eb_map,
666eb20978fSChris Mason 						&map_start, &map_len, KM_USER1);
6676e92f5e6SChris Mason 		if (err)
6686e92f5e6SChris Mason 			eb_token = NULL;
6696e92f5e6SChris Mason 	}
6706e92f5e6SChris Mason 	if (eb_token) {
6716e92f5e6SChris Mason 		memcpy(eb_token + ((unsigned long)item & (PAGE_CACHE_SIZE - 1)),
672607d432dSJosef Bacik 		       &sector_sum->sum, csum_size);
6736e92f5e6SChris Mason 	} else {
674e6dcd2dcSChris Mason 		write_extent_buffer(leaf, &sector_sum->sum,
675607d432dSJosef Bacik 				    (unsigned long)item, csum_size);
6766e92f5e6SChris Mason 	}
6777f3c74fbSChris Mason 
678e6dcd2dcSChris Mason 	total_bytes += root->sectorsize;
679e6dcd2dcSChris Mason 	sector_sum++;
680e6dcd2dcSChris Mason 	if (total_bytes < sums->len) {
6816e92f5e6SChris Mason 		item = (struct btrfs_csum_item *)((char *)item +
682607d432dSJosef Bacik 						  csum_size);
683d20f7043SChris Mason 		if (item < item_end && bytenr + PAGE_CACHE_SIZE ==
684d20f7043SChris Mason 		    sector_sum->bytenr) {
685d20f7043SChris Mason 			bytenr = sector_sum->bytenr;
686e6dcd2dcSChris Mason 			goto next_sector;
687065631f6SChris Mason 		}
6882e1a992eSChris Mason 	}
6896e92f5e6SChris Mason 	if (eb_token) {
690eb20978fSChris Mason 		unmap_extent_buffer(leaf, eb_token, KM_USER1);
6916e92f5e6SChris Mason 		eb_token = NULL;
6926e92f5e6SChris Mason 	}
6935caf2a00SChris Mason 	btrfs_mark_buffer_dirty(path->nodes[0]);
69453863232SChris Mason 	cond_resched();
695e6dcd2dcSChris Mason 	if (total_bytes < sums->len) {
6965caf2a00SChris Mason 		btrfs_release_path(root, path);
697065631f6SChris Mason 		goto again;
698065631f6SChris Mason 	}
69953863232SChris Mason out:
7005caf2a00SChris Mason 	btrfs_free_path(path);
701f254e52cSChris Mason 	return ret;
70253863232SChris Mason 
70353863232SChris Mason fail_unlock:
70453863232SChris Mason 	goto out;
705f254e52cSChris Mason }
706