diff options
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/ctree.h | 1 | ||||
-rw-r--r-- | fs/btrfs/extent_map.c | 45 | ||||
-rw-r--r-- | fs/btrfs/file.c | 78 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 15 |
4 files changed, 126 insertions, 13 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 7a588ba2b747..b9f2975b55c9 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -1170,6 +1170,7 @@ int btrfs_update_inode(struct btrfs_trans_handle *trans, | |||
1170 | struct inode *inode); | 1170 | struct inode *inode); |
1171 | /* file.c */ | 1171 | /* file.c */ |
1172 | int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end); | 1172 | int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end); |
1173 | int btrfs_check_file(struct btrfs_root *root, struct inode *inode); | ||
1173 | extern struct file_operations btrfs_file_operations; | 1174 | extern struct file_operations btrfs_file_operations; |
1174 | int btrfs_drop_extents(struct btrfs_trans_handle *trans, | 1175 | int btrfs_drop_extents(struct btrfs_trans_handle *trans, |
1175 | struct btrfs_root *root, struct inode *inode, | 1176 | struct btrfs_root *root, struct inode *inode, |
diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c index 485cf0719b3c..010a287fbd71 100644 --- a/fs/btrfs/extent_map.c +++ b/fs/btrfs/extent_map.c | |||
@@ -204,10 +204,12 @@ static struct rb_node *tree_insert(struct rb_root *root, u64 offset, | |||
204 | } | 204 | } |
205 | 205 | ||
206 | static struct rb_node *__tree_search(struct rb_root *root, u64 offset, | 206 | static struct rb_node *__tree_search(struct rb_root *root, u64 offset, |
207 | struct rb_node **prev_ret) | 207 | struct rb_node **prev_ret, |
208 | struct rb_node **next_ret) | ||
208 | { | 209 | { |
209 | struct rb_node * n = root->rb_node; | 210 | struct rb_node * n = root->rb_node; |
210 | struct rb_node *prev = NULL; | 211 | struct rb_node *prev = NULL; |
212 | struct rb_node *orig_prev = NULL; | ||
211 | struct tree_entry *entry; | 213 | struct tree_entry *entry; |
212 | struct tree_entry *prev_entry = NULL; | 214 | struct tree_entry *prev_entry = NULL; |
213 | 215 | ||
@@ -223,13 +225,25 @@ static struct rb_node *__tree_search(struct rb_root *root, u64 offset, | |||
223 | else | 225 | else |
224 | return n; | 226 | return n; |
225 | } | 227 | } |
226 | if (!prev_ret) | 228 | |
227 | return NULL; | 229 | if (prev_ret) { |
228 | while(prev && offset > prev_entry->end) { | 230 | orig_prev = prev; |
229 | prev = rb_next(prev); | 231 | while(prev && offset > prev_entry->end) { |
232 | prev = rb_next(prev); | ||
233 | prev_entry = rb_entry(prev, struct tree_entry, rb_node); | ||
234 | } | ||
235 | *prev_ret = prev; | ||
236 | prev = orig_prev; | ||
237 | } | ||
238 | |||
239 | if (next_ret) { | ||
230 | prev_entry = rb_entry(prev, struct tree_entry, rb_node); | 240 | prev_entry = rb_entry(prev, struct tree_entry, rb_node); |
241 | while(prev && offset < prev_entry->start) { | ||
242 | prev = rb_prev(prev); | ||
243 | prev_entry = rb_entry(prev, struct tree_entry, rb_node); | ||
244 | } | ||
245 | *next_ret = prev; | ||
231 | } | 246 | } |
232 | *prev_ret = prev; | ||
233 | return NULL; | 247 | return NULL; |
234 | } | 248 | } |
235 | 249 | ||
@@ -237,7 +251,7 @@ static inline struct rb_node *tree_search(struct rb_root *root, u64 offset) | |||
237 | { | 251 | { |
238 | struct rb_node *prev; | 252 | struct rb_node *prev; |
239 | struct rb_node *ret; | 253 | struct rb_node *ret; |
240 | ret = __tree_search(root, offset, &prev); | 254 | ret = __tree_search(root, offset, &prev, NULL); |
241 | if (!ret) | 255 | if (!ret) |
242 | return prev; | 256 | return prev; |
243 | return ret; | 257 | return ret; |
@@ -248,7 +262,7 @@ static int tree_delete(struct rb_root *root, u64 offset) | |||
248 | struct rb_node *node; | 262 | struct rb_node *node; |
249 | struct tree_entry *entry; | 263 | struct tree_entry *entry; |
250 | 264 | ||
251 | node = __tree_search(root, offset, NULL); | 265 | node = __tree_search(root, offset, NULL, NULL); |
252 | if (!node) | 266 | if (!node) |
253 | return -ENOENT; | 267 | return -ENOENT; |
254 | entry = rb_entry(node, struct tree_entry, rb_node); | 268 | entry = rb_entry(node, struct tree_entry, rb_node); |
@@ -314,9 +328,21 @@ struct extent_map *lookup_extent_mapping(struct extent_map_tree *tree, | |||
314 | { | 328 | { |
315 | struct extent_map *em; | 329 | struct extent_map *em; |
316 | struct rb_node *rb_node; | 330 | struct rb_node *rb_node; |
331 | struct rb_node *prev = NULL; | ||
332 | struct rb_node *next = NULL; | ||
317 | 333 | ||
318 | read_lock_irq(&tree->lock); | 334 | read_lock_irq(&tree->lock); |
319 | rb_node = tree_search(&tree->map, start); | 335 | rb_node = __tree_search(&tree->map, start, &prev, &next); |
336 | if (!rb_node && prev) { | ||
337 | em = rb_entry(prev, struct extent_map, rb_node); | ||
338 | if (em->start <= end && em->end >= start) | ||
339 | goto found; | ||
340 | } | ||
341 | if (!rb_node && next) { | ||
342 | em = rb_entry(next, struct extent_map, rb_node); | ||
343 | if (em->start <= end && em->end >= start) | ||
344 | goto found; | ||
345 | } | ||
320 | if (!rb_node) { | 346 | if (!rb_node) { |
321 | em = NULL; | 347 | em = NULL; |
322 | goto out; | 348 | goto out; |
@@ -330,6 +356,7 @@ struct extent_map *lookup_extent_mapping(struct extent_map_tree *tree, | |||
330 | em = NULL; | 356 | em = NULL; |
331 | goto out; | 357 | goto out; |
332 | } | 358 | } |
359 | found: | ||
333 | atomic_inc(&em->refs); | 360 | atomic_inc(&em->refs); |
334 | out: | 361 | out: |
335 | read_unlock_irq(&tree->lock); | 362 | read_unlock_irq(&tree->lock); |
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 897242e87fa7..1cd8c908811e 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
@@ -278,7 +278,7 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans, | |||
278 | u64 hole_size; | 278 | u64 hole_size; |
279 | u64 mask = root->sectorsize - 1; | 279 | u64 mask = root->sectorsize - 1; |
280 | last_pos_in_file = (isize + mask) & ~mask; | 280 | last_pos_in_file = (isize + mask) & ~mask; |
281 | hole_size = (start_pos - last_pos_in_file + mask) & ~mask; | 281 | hole_size = (end_pos - last_pos_in_file + mask) & ~mask; |
282 | 282 | ||
283 | if (last_pos_in_file < start_pos) { | 283 | if (last_pos_in_file < start_pos) { |
284 | err = btrfs_drop_extents(trans, root, inode, | 284 | err = btrfs_drop_extents(trans, root, inode, |
@@ -293,6 +293,7 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans, | |||
293 | inode->i_ino, | 293 | inode->i_ino, |
294 | last_pos_in_file, | 294 | last_pos_in_file, |
295 | 0, 0, hole_size); | 295 | 0, 0, hole_size); |
296 | btrfs_check_file(root, inode); | ||
296 | } | 297 | } |
297 | if (err) | 298 | if (err) |
298 | goto failed; | 299 | goto failed; |
@@ -378,6 +379,80 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end) | |||
378 | return 0; | 379 | return 0; |
379 | } | 380 | } |
380 | 381 | ||
382 | int btrfs_check_file(struct btrfs_root *root, struct inode *inode) | ||
383 | { | ||
384 | return 0; | ||
385 | #if 0 | ||
386 | struct btrfs_path *path; | ||
387 | struct btrfs_key found_key; | ||
388 | struct extent_buffer *leaf; | ||
389 | struct btrfs_file_extent_item *extent; | ||
390 | u64 last_offset = 0; | ||
391 | int nritems; | ||
392 | int slot; | ||
393 | int found_type; | ||
394 | int ret; | ||
395 | int err = 0; | ||
396 | u64 extent_end = 0; | ||
397 | |||
398 | path = btrfs_alloc_path(); | ||
399 | ret = btrfs_lookup_file_extent(NULL, root, path, inode->i_ino, | ||
400 | last_offset, 0); | ||
401 | while(1) { | ||
402 | nritems = btrfs_header_nritems(path->nodes[0]); | ||
403 | if (path->slots[0] >= nritems) { | ||
404 | ret = btrfs_next_leaf(root, path); | ||
405 | if (ret) | ||
406 | goto out; | ||
407 | nritems = btrfs_header_nritems(path->nodes[0]); | ||
408 | } | ||
409 | slot = path->slots[0]; | ||
410 | leaf = path->nodes[0]; | ||
411 | btrfs_item_key_to_cpu(leaf, &found_key, slot); | ||
412 | if (found_key.objectid != inode->i_ino) | ||
413 | break; | ||
414 | if (found_key.type != BTRFS_EXTENT_DATA_KEY) | ||
415 | goto out; | ||
416 | |||
417 | if (found_key.offset != last_offset) { | ||
418 | WARN_ON(1); | ||
419 | btrfs_print_leaf(root, leaf); | ||
420 | printk("inode %lu found offset %Lu expected %Lu\n", | ||
421 | inode->i_ino, found_key.offset, last_offset); | ||
422 | err = 1; | ||
423 | goto out; | ||
424 | } | ||
425 | extent = btrfs_item_ptr(leaf, slot, | ||
426 | struct btrfs_file_extent_item); | ||
427 | found_type = btrfs_file_extent_type(leaf, extent); | ||
428 | if (found_type == BTRFS_FILE_EXTENT_REG) { | ||
429 | extent_end = found_key.offset + | ||
430 | btrfs_file_extent_num_bytes(leaf, extent); | ||
431 | } else if (found_type == BTRFS_FILE_EXTENT_INLINE) { | ||
432 | struct btrfs_item *item; | ||
433 | item = btrfs_item_nr(leaf, slot); | ||
434 | extent_end = found_key.offset + | ||
435 | btrfs_file_extent_inline_len(leaf, item); | ||
436 | extent_end = (extent_end + root->sectorsize - 1) & | ||
437 | ~((u64)root->sectorsize -1 ); | ||
438 | } | ||
439 | last_offset = extent_end; | ||
440 | path->slots[0]++; | ||
441 | } | ||
442 | if (last_offset < inode->i_size) { | ||
443 | WARN_ON(1); | ||
444 | btrfs_print_leaf(root, leaf); | ||
445 | printk("inode %lu found offset %Lu size %Lu\n", inode->i_ino, | ||
446 | last_offset, inode->i_size); | ||
447 | err = 1; | ||
448 | |||
449 | } | ||
450 | out: | ||
451 | btrfs_free_path(path); | ||
452 | return err; | ||
453 | #endif | ||
454 | } | ||
455 | |||
381 | /* | 456 | /* |
382 | * this is very complex, but the basic idea is to drop all extents | 457 | * this is very complex, but the basic idea is to drop all extents |
383 | * in the range start - end. hint_block is filled in with a block number | 458 | * in the range start - end. hint_block is filled in with a block number |
@@ -436,6 +511,7 @@ next_slot: | |||
436 | slot = path->slots[0]; | 511 | slot = path->slots[0]; |
437 | ret = 0; | 512 | ret = 0; |
438 | btrfs_item_key_to_cpu(leaf, &key, slot); | 513 | btrfs_item_key_to_cpu(leaf, &key, slot); |
514 | |||
439 | if (key.offset >= end || key.objectid != inode->i_ino) { | 515 | if (key.offset >= end || key.objectid != inode->i_ino) { |
440 | goto out; | 516 | goto out; |
441 | } | 517 | } |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 51fc06dc4a5d..67005480e139 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -133,6 +133,7 @@ static int cow_file_range(struct inode *inode, u64 start, u64 end) | |||
133 | ret = btrfs_insert_file_extent(trans, root, inode->i_ino, | 133 | ret = btrfs_insert_file_extent(trans, root, inode->i_ino, |
134 | start, ins.objectid, ins.offset, | 134 | start, ins.objectid, ins.offset, |
135 | ins.offset); | 135 | ins.offset); |
136 | btrfs_check_file(root, inode); | ||
136 | num_bytes -= cur_alloc_size; | 137 | num_bytes -= cur_alloc_size; |
137 | alloc_hint = ins.objectid + ins.offset; | 138 | alloc_hint = ins.objectid + ins.offset; |
138 | start += cur_alloc_size; | 139 | start += cur_alloc_size; |
@@ -965,12 +966,18 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
965 | u64 mask = root->sectorsize - 1; | 966 | u64 mask = root->sectorsize - 1; |
966 | u64 pos = (inode->i_size + mask) & ~mask; | 967 | u64 pos = (inode->i_size + mask) & ~mask; |
967 | u64 block_end = attr->ia_size | mask; | 968 | u64 block_end = attr->ia_size | mask; |
969 | u64 hole_start; | ||
968 | u64 hole_size; | 970 | u64 hole_size; |
969 | u64 alloc_hint = 0; | 971 | u64 alloc_hint = 0; |
970 | 972 | ||
971 | if (attr->ia_size <= pos) | 973 | if (attr->ia_size <= pos) |
972 | goto out; | 974 | goto out; |
973 | 975 | ||
976 | if (pos != inode->i_size) | ||
977 | hole_start = pos + root->sectorsize; | ||
978 | else | ||
979 | hole_start = pos; | ||
980 | |||
974 | mutex_lock(&root->fs_info->fs_mutex); | 981 | mutex_lock(&root->fs_info->fs_mutex); |
975 | err = btrfs_check_free_space(root, 1, 0); | 982 | err = btrfs_check_free_space(root, 1, 0); |
976 | mutex_unlock(&root->fs_info->fs_mutex); | 983 | mutex_unlock(&root->fs_info->fs_mutex); |
@@ -980,19 +987,21 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
980 | btrfs_truncate_page(inode->i_mapping, inode->i_size); | 987 | btrfs_truncate_page(inode->i_mapping, inode->i_size); |
981 | 988 | ||
982 | lock_extent(em_tree, pos, block_end, GFP_NOFS); | 989 | lock_extent(em_tree, pos, block_end, GFP_NOFS); |
983 | hole_size = (attr->ia_size - pos + mask) & ~mask; | 990 | hole_size = block_end - hole_start; |
984 | 991 | ||
985 | mutex_lock(&root->fs_info->fs_mutex); | 992 | mutex_lock(&root->fs_info->fs_mutex); |
986 | trans = btrfs_start_transaction(root, 1); | 993 | trans = btrfs_start_transaction(root, 1); |
987 | btrfs_set_trans_block_group(trans, inode); | 994 | btrfs_set_trans_block_group(trans, inode); |
988 | err = btrfs_drop_extents(trans, root, inode, | 995 | err = btrfs_drop_extents(trans, root, inode, |
989 | pos, pos + hole_size, pos, | 996 | pos, block_end, pos, |
990 | &alloc_hint); | 997 | &alloc_hint); |
991 | 998 | ||
992 | if (alloc_hint != EXTENT_MAP_INLINE) { | 999 | if (alloc_hint != EXTENT_MAP_INLINE) { |
993 | err = btrfs_insert_file_extent(trans, root, | 1000 | err = btrfs_insert_file_extent(trans, root, |
994 | inode->i_ino, | 1001 | inode->i_ino, |
995 | pos, 0, 0, hole_size); | 1002 | hole_start, 0, 0, |
1003 | hole_size); | ||
1004 | btrfs_check_file(root, inode); | ||
996 | } | 1005 | } |
997 | btrfs_end_transaction(trans, root); | 1006 | btrfs_end_transaction(trans, root); |
998 | mutex_unlock(&root->fs_info->fs_mutex); | 1007 | mutex_unlock(&root->fs_info->fs_mutex); |