1 #include <linux/module.h> 2 #include "ctree.h" 3 #include "disk-io.h" 4 #include "transaction.h" 5 6 #define MAX_CSUM_ITEMS(r) ((((BTRFS_LEAF_DATA_SIZE(r) - \ 7 sizeof(struct btrfs_item)) / \ 8 sizeof(struct btrfs_csum_item)) - 1)) 9 int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, 10 struct btrfs_root *root, 11 u64 objectid, u64 pos, 12 u64 offset, u64 num_blocks) 13 { 14 int ret = 0; 15 struct btrfs_file_extent_item *item; 16 struct btrfs_key file_key; 17 struct btrfs_path *path; 18 19 path = btrfs_alloc_path(); 20 BUG_ON(!path); 21 btrfs_init_path(path); 22 /* 23 ret = btrfs_alloc_extent(trans, root, num_blocks, hint_block, 24 (u64)-1, &ins); 25 */ 26 BUG_ON(ret); 27 file_key.objectid = objectid; 28 file_key.offset = pos; 29 file_key.flags = 0; 30 btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY); 31 32 ret = btrfs_insert_empty_item(trans, root, path, &file_key, 33 sizeof(*item)); 34 BUG_ON(ret); 35 item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0], 36 struct btrfs_file_extent_item); 37 btrfs_set_file_extent_disk_blocknr(item, offset); 38 btrfs_set_file_extent_disk_num_blocks(item, num_blocks); 39 btrfs_set_file_extent_offset(item, 0); 40 btrfs_set_file_extent_num_blocks(item, num_blocks); 41 btrfs_set_file_extent_generation(item, trans->transid); 42 btrfs_mark_buffer_dirty(path->nodes[0]); 43 btrfs_release_path(root, path); 44 btrfs_free_path(path); 45 return 0; 46 } 47 48 struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans, 49 struct btrfs_root *root, 50 struct btrfs_path *path, 51 u64 objectid, u64 offset, 52 int cow) 53 { 54 int ret; 55 struct btrfs_key file_key; 56 struct btrfs_key found_key; 57 struct btrfs_csum_item *item; 58 struct btrfs_leaf *leaf; 59 u64 csum_offset = 0; 60 61 file_key.objectid = objectid; 62 file_key.offset = offset; 63 file_key.flags = 0; 64 btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY); 65 ret = btrfs_search_slot(trans, root, &file_key, path, 0, cow); 66 if (ret < 0) 67 goto fail; 68 leaf = btrfs_buffer_leaf(path->nodes[0]); 69 if (ret > 0) { 70 ret = 1; 71 if (path->slots[0] == 0) 72 goto fail; 73 path->slots[0]--; 74 btrfs_disk_key_to_cpu(&found_key, 75 &leaf->items[path->slots[0]].key); 76 if (btrfs_key_type(&found_key) != BTRFS_CSUM_ITEM_KEY || 77 found_key.objectid != objectid) { 78 goto fail; 79 } 80 csum_offset = (offset - found_key.offset) >> 81 root->fs_info->sb->s_blocksize_bits; 82 if (csum_offset >= 83 btrfs_item_size(leaf->items + path->slots[0]) / 84 sizeof(struct btrfs_csum_item)) { 85 goto fail; 86 } 87 } 88 item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item); 89 item += csum_offset; 90 return item; 91 fail: 92 if (ret > 0) 93 ret = -ENOENT; 94 return ERR_PTR(ret); 95 } 96 97 98 int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans, 99 struct btrfs_root *root, 100 struct btrfs_path *path, u64 objectid, 101 u64 offset, int mod) 102 { 103 int ret; 104 struct btrfs_key file_key; 105 int ins_len = mod < 0 ? -1 : 0; 106 int cow = mod != 0; 107 108 file_key.objectid = objectid; 109 file_key.offset = offset; 110 file_key.flags = 0; 111 btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY); 112 ret = btrfs_search_slot(trans, root, &file_key, path, ins_len, cow); 113 return ret; 114 } 115 116 int btrfs_csum_file_block(struct btrfs_trans_handle *trans, 117 struct btrfs_root *root, 118 u64 objectid, u64 offset, 119 char *data, size_t len) 120 { 121 int ret; 122 struct btrfs_key file_key; 123 struct btrfs_key found_key; 124 struct btrfs_path *path; 125 struct btrfs_csum_item *item; 126 struct btrfs_leaf *leaf; 127 u64 csum_offset; 128 129 path = btrfs_alloc_path(); 130 BUG_ON(!path); 131 btrfs_init_path(path); 132 133 item = btrfs_lookup_csum(trans, root, path, objectid, offset, 0); 134 if (!IS_ERR(item)) 135 goto found; 136 btrfs_release_path(root, path); 137 file_key.objectid = objectid; 138 file_key.offset = offset; 139 file_key.flags = 0; 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 BUG(); 147 } 148 if (path->slots[0] == 0) { 149 btrfs_release_path(root, path); 150 goto insert; 151 } 152 path->slots[0]--; 153 leaf = btrfs_buffer_leaf(path->nodes[0]); 154 btrfs_disk_key_to_cpu(&found_key, &leaf->items[path->slots[0]].key); 155 csum_offset = (offset - found_key.offset) >> 156 root->fs_info->sb->s_blocksize_bits; 157 if (btrfs_key_type(&found_key) != BTRFS_CSUM_ITEM_KEY || 158 found_key.objectid != objectid || 159 csum_offset >= MAX_CSUM_ITEMS(root)) { 160 btrfs_release_path(root, path); 161 goto insert; 162 } 163 if (csum_offset >= btrfs_item_size(leaf->items + path->slots[0]) / 164 sizeof(struct btrfs_csum_item)) { 165 ret = btrfs_extend_item(trans, root, path, 166 sizeof(struct btrfs_csum_item)); 167 BUG_ON(ret); 168 goto csum; 169 } 170 171 insert: 172 csum_offset = 0; 173 ret = btrfs_insert_empty_item(trans, root, path, &file_key, 174 sizeof(struct btrfs_csum_item)); 175 if (ret != 0 && ret != -EEXIST) 176 goto fail; 177 csum: 178 item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0], 179 struct btrfs_csum_item); 180 ret = 0; 181 item += csum_offset; 182 found: 183 ret = btrfs_csum_data(root, data, len, item->csum); 184 btrfs_mark_buffer_dirty(path->nodes[0]); 185 fail: 186 btrfs_release_path(root, path); 187 btrfs_free_path(path); 188 return ret; 189 } 190 191 int btrfs_csum_verify_file_block(struct btrfs_root *root, 192 u64 objectid, u64 offset, 193 char *data, size_t len) 194 { 195 int ret; 196 struct btrfs_key file_key; 197 struct btrfs_path *path; 198 struct btrfs_csum_item *item; 199 char result[BTRFS_CSUM_SIZE]; 200 201 path = btrfs_alloc_path(); 202 BUG_ON(!path); 203 btrfs_init_path(path); 204 file_key.objectid = objectid; 205 file_key.offset = offset; 206 file_key.flags = 0; 207 btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY); 208 mutex_lock(&root->fs_info->fs_mutex); 209 210 item = btrfs_lookup_csum(NULL, root, path, objectid, offset, 0); 211 if (IS_ERR(item)) { 212 ret = PTR_ERR(item); 213 goto fail; 214 } 215 216 ret = btrfs_csum_data(root, data, len, result); 217 WARN_ON(ret); 218 if (memcmp(result, item->csum, BTRFS_CSUM_SIZE)) 219 ret = 1; 220 fail: 221 btrfs_release_path(root, path); 222 btrfs_free_path(path); 223 mutex_unlock(&root->fs_info->fs_mutex); 224 return ret; 225 } 226 227