aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/ctree.h1
-rw-r--r--fs/btrfs/extent_map.c45
-rw-r--r--fs/btrfs/file.c78
-rw-r--r--fs/btrfs/inode.c15
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 */
1172int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end); 1172int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end);
1173int btrfs_check_file(struct btrfs_root *root, struct inode *inode);
1173extern struct file_operations btrfs_file_operations; 1174extern struct file_operations btrfs_file_operations;
1174int btrfs_drop_extents(struct btrfs_trans_handle *trans, 1175int 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
206static struct rb_node *__tree_search(struct rb_root *root, u64 offset, 206static 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 }
359found:
333 atomic_inc(&em->refs); 360 atomic_inc(&em->refs);
334out: 361out:
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
382int 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 }
450out:
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);