aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/file-item.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/file-item.c')
-rw-r--r--fs/btrfs/file-item.c111
1 files changed, 104 insertions, 7 deletions
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c
index d9fd7f4d3794..93d42d650820 100644
--- a/fs/btrfs/file-item.c
+++ b/fs/btrfs/file-item.c
@@ -3,6 +3,9 @@
3#include "disk-io.h" 3#include "disk-io.h"
4#include "transaction.h" 4#include "transaction.h"
5 5
6#define MAX_CSUM_ITEMS(r) ((((BTRFS_LEAF_DATA_SIZE(r) - \
7 sizeof(struct btrfs_item)) / \
8 sizeof(struct btrfs_csum_item)) - 1))
6int btrfs_alloc_file_extent(struct btrfs_trans_handle *trans, 9int btrfs_alloc_file_extent(struct btrfs_trans_handle *trans,
7 struct btrfs_root *root, 10 struct btrfs_root *root,
8 u64 objectid, u64 offset, 11 u64 objectid, u64 offset,
@@ -43,6 +46,54 @@ int btrfs_alloc_file_extent(struct btrfs_trans_handle *trans,
43 return 0; 46 return 0;
44} 47}
45 48
49static struct btrfs_csum_item *__lookup_csum_item(struct btrfs_root *root,
50 struct btrfs_path *path,
51 u64 objectid, u64 offset)
52{
53 int ret;
54 struct btrfs_key file_key;
55 struct btrfs_key found_key;
56 struct btrfs_csum_item *item;
57 struct btrfs_leaf *leaf;
58 u64 csum_offset = 0;
59
60 file_key.objectid = objectid;
61 file_key.offset = offset;
62 file_key.flags = 0;
63 btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY);
64 ret = btrfs_search_slot(NULL, root, &file_key, path, 0, 0);
65 if (ret < 0)
66 goto fail;
67 leaf = btrfs_buffer_leaf(path->nodes[0]);
68 if (ret > 0) {
69 ret = 1;
70 if (path->slots[0] == 0)
71 goto fail;
72 path->slots[0]--;
73 btrfs_disk_key_to_cpu(&found_key,
74 &leaf->items[path->slots[0]].key);
75 if (btrfs_key_type(&found_key) != BTRFS_CSUM_ITEM_KEY ||
76 found_key.objectid != objectid) {
77 goto fail;
78 }
79 csum_offset = (offset - found_key.offset) >>
80 root->fs_info->sb->s_blocksize_bits;
81 if (csum_offset >=
82 btrfs_item_size(leaf->items + path->slots[0]) /
83 sizeof(struct btrfs_csum_item)) {
84 goto fail;
85 }
86 }
87 item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item);
88 item += csum_offset;
89 return item;
90fail:
91 if (ret > 0)
92 ret = -EIO;
93 return ERR_PTR(ret);
94}
95
96
46int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans, 97int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
47 struct btrfs_root *root, 98 struct btrfs_root *root,
48 struct btrfs_path *path, u64 objectid, 99 struct btrfs_path *path, u64 objectid,
@@ -52,11 +103,16 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
52 struct btrfs_key file_key; 103 struct btrfs_key file_key;
53 int ins_len = mod < 0 ? -1 : 0; 104 int ins_len = mod < 0 ? -1 : 0;
54 int cow = mod != 0; 105 int cow = mod != 0;
106 struct btrfs_csum_item *csum_item;
55 107
108 csum_item = __lookup_csum_item(root, path, objectid, offset);
109 if (IS_ERR(csum_item))
110 return PTR_ERR(csum_item);
56 file_key.objectid = objectid; 111 file_key.objectid = objectid;
57 file_key.offset = offset; 112 file_key.offset = btrfs_csum_extent_offset(csum_item);
58 file_key.flags = 0; 113 file_key.flags = 0;
59 btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY); 114 btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY);
115 btrfs_release_path(root, path);
60 ret = btrfs_search_slot(trans, root, &file_key, path, ins_len, cow); 116 ret = btrfs_search_slot(trans, root, &file_key, path, ins_len, cow);
61 return ret; 117 return ret;
62} 118}
@@ -64,12 +120,16 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
64int btrfs_csum_file_block(struct btrfs_trans_handle *trans, 120int btrfs_csum_file_block(struct btrfs_trans_handle *trans,
65 struct btrfs_root *root, 121 struct btrfs_root *root,
66 u64 objectid, u64 offset, 122 u64 objectid, u64 offset,
123 u64 extent_offset,
67 char *data, size_t len) 124 char *data, size_t len)
68{ 125{
69 int ret; 126 int ret;
70 struct btrfs_key file_key; 127 struct btrfs_key file_key;
128 struct btrfs_key found_key;
71 struct btrfs_path *path; 129 struct btrfs_path *path;
72 struct btrfs_csum_item *item; 130 struct btrfs_csum_item *item;
131 struct btrfs_leaf *leaf;
132 u64 csum_offset;
73 133
74 path = btrfs_alloc_path(); 134 path = btrfs_alloc_path();
75 BUG_ON(!path); 135 BUG_ON(!path);
@@ -78,14 +138,50 @@ int btrfs_csum_file_block(struct btrfs_trans_handle *trans,
78 file_key.offset = offset; 138 file_key.offset = offset;
79 file_key.flags = 0; 139 file_key.flags = 0;
80 btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY); 140 btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY);
141 ret = btrfs_search_slot(trans, root, &file_key, path,
142 sizeof(struct btrfs_csum_item), 1);
143 if (ret < 0)
144 goto fail;
145 if (ret == 0) {
146 csum_offset = 0;
147 goto csum;
148 }
149 if (path->slots[0] == 0) {
150 btrfs_release_path(root, path);
151 goto insert;
152 }
153 path->slots[0]--;
154 leaf = btrfs_buffer_leaf(path->nodes[0]);
155 btrfs_disk_key_to_cpu(&found_key, &leaf->items[path->slots[0]].key);
156 csum_offset = (offset - found_key.offset) >>
157 root->fs_info->sb->s_blocksize_bits;
158 if (btrfs_key_type(&found_key) != BTRFS_CSUM_ITEM_KEY ||
159 found_key.objectid != objectid ||
160 csum_offset >= MAX_CSUM_ITEMS(root)) {
161 btrfs_release_path(root, path);
162 goto insert;
163 }
164 if (csum_offset >= btrfs_item_size(leaf->items + path->slots[0]) /
165 sizeof(struct btrfs_csum_item)) {
166 ret = btrfs_extend_item(trans, root, path,
167 sizeof(struct btrfs_csum_item));
168 BUG_ON(ret);
169 goto csum;
170 }
171
172insert:
173 csum_offset = 0;
81 ret = btrfs_insert_empty_item(trans, root, path, &file_key, 174 ret = btrfs_insert_empty_item(trans, root, path, &file_key,
82 BTRFS_CSUM_SIZE); 175 sizeof(struct btrfs_csum_item));
83 if (ret != 0 && ret != -EEXIST) 176 if (ret != 0 && ret != -EEXIST)
84 goto fail; 177 goto fail;
178csum:
85 item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0], 179 item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0],
86 struct btrfs_csum_item); 180 struct btrfs_csum_item);
87 ret = 0; 181 ret = 0;
182 item += csum_offset;
88 ret = btrfs_csum_data(root, data, len, item->csum); 183 ret = btrfs_csum_data(root, data, len, item->csum);
184 btrfs_set_csum_extent_offset(item, extent_offset);
89 btrfs_mark_buffer_dirty(path->nodes[0]); 185 btrfs_mark_buffer_dirty(path->nodes[0]);
90fail: 186fail:
91 btrfs_release_path(root, path); 187 btrfs_release_path(root, path);
@@ -111,12 +207,13 @@ int btrfs_csum_verify_file_block(struct btrfs_root *root,
111 file_key.flags = 0; 207 file_key.flags = 0;
112 btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY); 208 btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY);
113 mutex_lock(&root->fs_info->fs_mutex); 209 mutex_lock(&root->fs_info->fs_mutex);
114 ret = btrfs_search_slot(NULL, root, &file_key, path, 0, 0); 210
115 if (ret) 211 item = __lookup_csum_item(root, path, objectid, offset);
212 if (IS_ERR(item)) {
213 ret = PTR_ERR(item);
116 goto fail; 214 goto fail;
117 item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0], 215 }
118 struct btrfs_csum_item); 216
119 ret = 0;
120 ret = btrfs_csum_data(root, data, len, result); 217 ret = btrfs_csum_data(root, data, len, result);
121 WARN_ON(ret); 218 WARN_ON(ret);
122 if (memcmp(result, item->csum, BTRFS_CSUM_SIZE)) 219 if (memcmp(result, item->csum, BTRFS_CSUM_SIZE))