file-item.c revision aadfeb6e39ad6bde080cb3ab23f4da57ccb25f4a
1/* 2 * Copyright (C) 2007 Oracle. All rights reserved. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public 6 * License v2 as published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 * General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public 14 * License along with this program; if not, write to the 15 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 16 * Boston, MA 021110-1307, USA. 17 */ 18 19#include "ctree.h" 20#include "disk-io.h" 21#include "transaction.h" 22#include "print-tree.h" 23 24#define MAX_CSUM_ITEMS(r) ((((BTRFS_LEAF_DATA_SIZE(r) - \ 25 sizeof(struct btrfs_item) * 2) / \ 26 BTRFS_CRC32_SIZE) - 1)) 27int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, 28 struct btrfs_root *root, 29 u64 objectid, u64 pos, 30 u64 offset, u64 disk_num_bytes, 31 u64 num_bytes) 32{ 33 int ret = 0; 34 struct btrfs_file_extent_item *item; 35 struct btrfs_key file_key; 36 struct btrfs_path *path; 37 struct extent_buffer *leaf; 38 39 path = btrfs_alloc_path(); 40 BUG_ON(!path); 41 file_key.objectid = objectid; 42 file_key.offset = pos; 43 btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY); 44 45 ret = btrfs_insert_empty_item(trans, root, path, &file_key, 46 sizeof(*item)); 47 if (ret < 0) 48 goto out; 49 BUG_ON(ret); 50 leaf = path->nodes[0]; 51 item = btrfs_item_ptr(leaf, path->slots[0], 52 struct btrfs_file_extent_item); 53 btrfs_set_file_extent_disk_bytenr(leaf, item, offset); 54 btrfs_set_file_extent_disk_num_bytes(leaf, item, disk_num_bytes); 55 btrfs_set_file_extent_offset(leaf, item, 0); 56 btrfs_set_file_extent_num_bytes(leaf, item, num_bytes); 57 btrfs_set_file_extent_generation(leaf, item, trans->transid); 58 btrfs_set_file_extent_type(leaf, item, BTRFS_FILE_EXTENT_REG); 59 btrfs_mark_buffer_dirty(leaf); 60out: 61 btrfs_free_path(path); 62 return ret; 63} 64 65struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans, 66 struct btrfs_root *root, 67 struct btrfs_path *path, 68 u64 objectid, u64 offset, 69 int cow) 70{ 71 int ret; 72 struct btrfs_key file_key; 73 struct btrfs_key found_key; 74 struct btrfs_csum_item *item; 75 struct extent_buffer *leaf; 76 u64 csum_offset = 0; 77 int csums_in_item; 78 79 file_key.objectid = objectid; 80 file_key.offset = offset; 81 btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY); 82 ret = btrfs_search_slot(trans, root, &file_key, path, 0, cow); 83 if (ret < 0) 84 goto fail; 85 leaf = path->nodes[0]; 86 if (ret > 0) { 87 ret = 1; 88 if (path->slots[0] == 0) 89 goto fail; 90 path->slots[0]--; 91 btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); 92 if (btrfs_key_type(&found_key) != BTRFS_CSUM_ITEM_KEY || 93 found_key.objectid != objectid) { 94 goto fail; 95 } 96 csum_offset = (offset - found_key.offset) >> 97 root->fs_info->sb->s_blocksize_bits; 98 csums_in_item = btrfs_item_size_nr(leaf, path->slots[0]); 99 csums_in_item /= BTRFS_CRC32_SIZE; 100 101 if (csum_offset >= csums_in_item) { 102 ret = -EFBIG; 103 goto fail; 104 } 105 } 106 item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item); 107 item = (struct btrfs_csum_item *)((unsigned char *)item + 108 csum_offset * BTRFS_CRC32_SIZE); 109 return item; 110fail: 111 if (ret > 0) 112 ret = -ENOENT; 113 return ERR_PTR(ret); 114} 115 116 117int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans, 118 struct btrfs_root *root, 119 struct btrfs_path *path, u64 objectid, 120 u64 offset, int mod) 121{ 122 int ret; 123 struct btrfs_key file_key; 124 int ins_len = mod < 0 ? -1 : 0; 125 int cow = mod != 0; 126 127 file_key.objectid = objectid; 128 file_key.offset = offset; 129 btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY); 130 ret = btrfs_search_slot(trans, root, &file_key, path, ins_len, cow); 131 return ret; 132} 133 134int btrfs_csum_file_block(struct btrfs_trans_handle *trans, 135 struct btrfs_root *root, 136 struct inode *inode, 137 u64 objectid, u64 offset, 138 char *data, size_t len) 139{ 140 int ret; 141 struct btrfs_key file_key; 142 struct btrfs_key found_key; 143 u64 next_offset = (u64)-1; 144 int found_next = 0; 145 struct btrfs_path *path; 146 struct btrfs_csum_item *item; 147 struct extent_buffer *leaf = NULL; 148 u64 csum_offset; 149 u32 csum_result = ~(u32)0; 150 u32 nritems; 151 u32 ins_size; 152 153 path = btrfs_alloc_path(); 154 BUG_ON(!path); 155 156 file_key.objectid = objectid; 157 file_key.offset = offset; 158 btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY); 159 160 item = btrfs_lookup_csum(trans, root, path, objectid, offset, 1); 161 if (!IS_ERR(item)) { 162 leaf = path->nodes[0]; 163 goto found; 164 } 165 ret = PTR_ERR(item); 166 if (ret == -EFBIG) { 167 u32 item_size; 168 /* we found one, but it isn't big enough yet */ 169 leaf = path->nodes[0]; 170 item_size = btrfs_item_size_nr(leaf, path->slots[0]); 171 if ((item_size / BTRFS_CRC32_SIZE) >= MAX_CSUM_ITEMS(root)) { 172 /* already at max size, make a new one */ 173 goto insert; 174 } 175 } else { 176 int slot = path->slots[0] + 1; 177 /* we didn't find a csum item, insert one */ 178 nritems = btrfs_header_nritems(path->nodes[0]); 179 if (path->slots[0] >= nritems - 1) { 180 ret = btrfs_next_leaf(root, path); 181 if (ret == 1) 182 found_next = 1; 183 if (ret != 0) 184 goto insert; 185 slot = 0; 186 } 187 btrfs_item_key_to_cpu(path->nodes[0], &found_key, slot); 188 if (found_key.objectid != objectid || 189 found_key.type != BTRFS_CSUM_ITEM_KEY) { 190 found_next = 1; 191 goto insert; 192 } 193 next_offset = found_key.offset; 194 found_next = 1; 195 goto insert; 196 } 197 198 /* 199 * at this point, we know the tree has an item, but it isn't big 200 * enough yet to put our csum in. Grow it 201 */ 202 btrfs_release_path(root, path); 203 ret = btrfs_search_slot(trans, root, &file_key, path, 204 BTRFS_CRC32_SIZE, 1); 205 if (ret < 0) 206 goto fail; 207 if (ret == 0) { 208 BUG(); 209 } 210 if (path->slots[0] == 0) { 211 goto insert; 212 } 213 path->slots[0]--; 214 leaf = path->nodes[0]; 215 btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); 216 csum_offset = (offset - found_key.offset) >> 217 root->fs_info->sb->s_blocksize_bits; 218 if (btrfs_key_type(&found_key) != BTRFS_CSUM_ITEM_KEY || 219 found_key.objectid != objectid || 220 csum_offset >= MAX_CSUM_ITEMS(root)) { 221 goto insert; 222 } 223 if (csum_offset >= btrfs_item_size_nr(leaf, path->slots[0]) / 224 BTRFS_CRC32_SIZE) { 225 u32 diff = (csum_offset + 1) * BTRFS_CRC32_SIZE; 226 diff = diff - btrfs_item_size_nr(leaf, path->slots[0]); 227 if (diff != BTRFS_CRC32_SIZE) 228 goto insert; 229 ret = btrfs_extend_item(trans, root, path, diff); 230 BUG_ON(ret); 231 goto csum; 232 } 233 234insert: 235 btrfs_release_path(root, path); 236 csum_offset = 0; 237 if (found_next) { 238 u64 tmp = min((u64)i_size_read(inode), next_offset); 239 tmp -= offset & ~((u64)root->sectorsize -1); 240 tmp >>= root->fs_info->sb->s_blocksize_bits; 241 tmp = max((u64)1, tmp); 242 tmp = min(tmp, (u64)MAX_CSUM_ITEMS(root)); 243 ins_size = BTRFS_CRC32_SIZE * tmp; 244 } else { 245 ins_size = BTRFS_CRC32_SIZE; 246 } 247 ret = btrfs_insert_empty_item(trans, root, path, &file_key, 248 ins_size); 249 if (ret < 0) 250 goto fail; 251 if (ret != 0) { 252 WARN_ON(1); 253 goto fail; 254 } 255csum: 256 leaf = path->nodes[0]; 257 item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item); 258 ret = 0; 259 item = (struct btrfs_csum_item *)((unsigned char *)item + 260 csum_offset * BTRFS_CRC32_SIZE); 261found: 262 csum_result = btrfs_csum_data(root, data, csum_result, len); 263 btrfs_csum_final(csum_result, (char *)&csum_result); 264 if (csum_result == 0) { 265 printk("csum result is 0 for inode %lu offset %Lu\n", inode->i_ino, offset); 266 } 267 268 write_extent_buffer(leaf, &csum_result, (unsigned long)item, 269 BTRFS_CRC32_SIZE); 270 btrfs_mark_buffer_dirty(path->nodes[0]); 271fail: 272 btrfs_release_path(root, path); 273 btrfs_free_path(path); 274 return ret; 275} 276 277int btrfs_csum_truncate(struct btrfs_trans_handle *trans, 278 struct btrfs_root *root, struct btrfs_path *path, 279 u64 isize) 280{ 281 struct btrfs_key key; 282 struct extent_buffer *leaf = path->nodes[0]; 283 int slot = path->slots[0]; 284 int ret; 285 u32 new_item_size; 286 u64 new_item_span; 287 u64 blocks; 288 289 btrfs_item_key_to_cpu(leaf, &key, slot); 290 if (isize <= key.offset) 291 return 0; 292 new_item_span = isize - key.offset; 293 blocks = (new_item_span + root->sectorsize - 1) >> 294 root->fs_info->sb->s_blocksize_bits; 295 new_item_size = blocks * BTRFS_CRC32_SIZE; 296 if (new_item_size >= btrfs_item_size_nr(leaf, slot)) 297 return 0; 298 ret = btrfs_truncate_item(trans, root, path, new_item_size, 1); 299 BUG_ON(ret); 300 return ret; 301} 302 303