tree-defrag.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  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. #include <linux/sched.h>
  19. #include "ctree.h"
  20. #include "disk-io.h"
  21. #include "print-tree.h"
  22. #include "transaction.h"
  23. #include "locking.h"
  24. int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
  25. struct btrfs_root *root, int cache_only)
  26. {
  27. struct btrfs_path *path = NULL;
  28. struct btrfs_key key;
  29. int ret = 0;
  30. int wret;
  31. int level;
  32. int orig_level;
  33. int i;
  34. int is_extent = 0;
  35. int next_key_ret = 0;
  36. u64 last_ret = 0;
  37. if (root->fs_info->extent_root == root) {
  38. mutex_lock(&root->fs_info->alloc_mutex);
  39. is_extent = 1;
  40. }
  41. if (root->ref_cows == 0 && !is_extent)
  42. goto out;
  43. if (btrfs_test_opt(root, SSD))
  44. goto out;
  45. path = btrfs_alloc_path();
  46. if (!path)
  47. return -ENOMEM;
  48. level = btrfs_header_level(root->node);
  49. orig_level = level;
  50. if (level == 0) {
  51. goto out;
  52. }
  53. if (root->defrag_progress.objectid == 0) {
  54. struct extent_buffer *root_node;
  55. u32 nritems;
  56. root_node = btrfs_lock_root_node(root);
  57. nritems = btrfs_header_nritems(root_node);
  58. root->defrag_max.objectid = 0;
  59. /* from above we know this is not a leaf */
  60. btrfs_node_key_to_cpu(root_node, &root->defrag_max,
  61. nritems - 1);
  62. btrfs_tree_unlock(root_node);
  63. free_extent_buffer(root_node);
  64. memset(&key, 0, sizeof(key));
  65. } else {
  66. memcpy(&key, &root->defrag_progress, sizeof(key));
  67. }
  68. path->lowest_level = 1;
  69. path->keep_locks = 1;
  70. wret = btrfs_search_slot(trans, root, &key, path, 0, 1);
  71. if (wret < 0) {
  72. ret = wret;
  73. goto out;
  74. }
  75. if (!path->nodes[1]) {
  76. ret = 0;
  77. goto out;
  78. }
  79. path->slots[1] = btrfs_header_nritems(path->nodes[1]);
  80. next_key_ret = btrfs_find_next_key(root, path, &key, 1);
  81. ret = btrfs_realloc_node(trans, root,
  82. path->nodes[1], 0,
  83. cache_only, &last_ret,
  84. &root->defrag_progress);
  85. WARN_ON(ret && ret != -EAGAIN);
  86. if (next_key_ret == 0) {
  87. memcpy(&root->defrag_progress, &key, sizeof(key));
  88. ret = -EAGAIN;
  89. }
  90. for (i = 1; i < BTRFS_MAX_LEVEL; i++) {
  91. if (path->locks[i]) {
  92. btrfs_tree_unlock(path->nodes[i]);
  93. path->locks[i] = 0;
  94. }
  95. if (path->nodes[i]) {
  96. free_extent_buffer(path->nodes[i]);
  97. path->nodes[i] = NULL;
  98. }
  99. }
  100. if (is_extent)
  101. btrfs_extent_post_op(trans, root);
  102. out:
  103. if (is_extent)
  104. mutex_unlock(&root->fs_info->alloc_mutex);
  105. if (path)
  106. btrfs_free_path(path);
  107. if (ret == -EAGAIN) {
  108. if (root->defrag_max.objectid > root->defrag_progress.objectid)
  109. goto done;
  110. if (root->defrag_max.type > root->defrag_progress.type)
  111. goto done;
  112. if (root->defrag_max.offset > root->defrag_progress.offset)
  113. goto done;
  114. ret = 0;
  115. }
  116. done:
  117. if (ret != -EAGAIN) {
  118. memset(&root->defrag_progress, 0,
  119. sizeof(root->defrag_progress));
  120. }
  121. return ret;
  122. }