Blame view
fs/btrfs/tree-defrag.c
3.52 KB
6702ed490
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
/* * Copyright (C) 2007 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #include <linux/sched.h> #include "ctree.h" #include "disk-io.h" #include "print-tree.h" #include "transaction.h" |
e7a84565b
|
24 |
#include "locking.h" |
6702ed490
|
25 |
|
d397712bc
|
26 27 |
/* defrag all the leaves in a given btree. If cache_only == 1, don't read * things from disk, otherwise read all the leaves and try to get key order to |
d352ac681
|
28 29 |
* better reflect disk order */ |
d397712bc
|
30 |
|
6702ed490
|
31 32 33 34 |
int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, struct btrfs_root *root, int cache_only) { struct btrfs_path *path = NULL; |
e7a84565b
|
35 |
struct btrfs_key key; |
6702ed490
|
36 37 38 |
int ret = 0; int wret; int level; |
e9d0b13b5
|
39 |
int is_extent = 0; |
e7a84565b
|
40 |
int next_key_ret = 0; |
e9d0b13b5
|
41 |
u64 last_ret = 0; |
3f157a2fd
|
42 43 44 45 |
u64 min_trans = 0; if (cache_only) goto out; |
e9d0b13b5
|
46 |
|
e7a84565b
|
47 |
if (root->fs_info->extent_root == root) { |
1b1e2135d
|
48 49 50 51 52 |
/* * there's recursion here right now in the tree locking, * we can't defrag the extent root without deadlock */ goto out; |
e7a84565b
|
53 |
} |
925baeddc
|
54 |
|
e9d0b13b5
|
55 |
if (root->ref_cows == 0 && !is_extent) |
6702ed490
|
56 |
goto out; |
5f39d397d
|
57 |
|
9afbb0b75
|
58 59 |
if (btrfs_test_opt(root, SSD)) goto out; |
6702ed490
|
60 61 62 |
path = btrfs_alloc_path(); if (!path) return -ENOMEM; |
5f39d397d
|
63 |
level = btrfs_header_level(root->node); |
0f1ebbd15
|
64 |
|
d397712bc
|
65 |
if (level == 0) |
6702ed490
|
66 |
goto out; |
d397712bc
|
67 |
|
6702ed490
|
68 |
if (root->defrag_progress.objectid == 0) { |
e7a84565b
|
69 |
struct extent_buffer *root_node; |
0ef3e66b6
|
70 |
u32 nritems; |
e7a84565b
|
71 |
root_node = btrfs_lock_root_node(root); |
b4ce94de9
|
72 |
btrfs_set_lock_blocking(root_node); |
e7a84565b
|
73 |
nritems = btrfs_header_nritems(root_node); |
0ef3e66b6
|
74 75 |
root->defrag_max.objectid = 0; /* from above we know this is not a leaf */ |
e7a84565b
|
76 |
btrfs_node_key_to_cpu(root_node, &root->defrag_max, |
0ef3e66b6
|
77 |
nritems - 1); |
e7a84565b
|
78 79 80 |
btrfs_tree_unlock(root_node); free_extent_buffer(root_node); memset(&key, 0, sizeof(key)); |
6702ed490
|
81 |
} else { |
e7a84565b
|
82 |
memcpy(&key, &root->defrag_progress, sizeof(key)); |
6702ed490
|
83 |
} |
e7a84565b
|
84 |
path->keep_locks = 1; |
3f157a2fd
|
85 86 |
if (cache_only) min_trans = root->defrag_trans_start; |
e02119d5a
|
87 88 |
ret = btrfs_search_forward(root, &key, NULL, path, cache_only, min_trans); |
3f157a2fd
|
89 90 91 92 93 94 |
if (ret < 0) goto out; if (ret > 0) { ret = 0; goto out; } |
b3b4aa74b
|
95 |
btrfs_release_path(path); |
e7a84565b
|
96 |
wret = btrfs_search_slot(trans, root, &key, path, 0, 1); |
6702ed490
|
97 |
|
e7a84565b
|
98 99 100 101 102 103 104 105 106 |
if (wret < 0) { ret = wret; goto out; } if (!path->nodes[1]) { ret = 0; goto out; } path->slots[1] = btrfs_header_nritems(path->nodes[1]); |
3f157a2fd
|
107 108 |
next_key_ret = btrfs_find_next_key(root, path, &key, 1, cache_only, min_trans); |
e7a84565b
|
109 110 111 112 |
ret = btrfs_realloc_node(trans, root, path->nodes[1], 0, cache_only, &last_ret, &root->defrag_progress); |
8929ecfa5
|
113 114 115 116 |
if (ret) { WARN_ON(ret == -EAGAIN); goto out; } |
e7a84565b
|
117 118 119 |
if (next_key_ret == 0) { memcpy(&root->defrag_progress, &key, sizeof(key)); ret = -EAGAIN; |
6702ed490
|
120 |
} |
6702ed490
|
121 122 123 |
out: if (path) btrfs_free_path(path); |
0ef3e66b6
|
124 125 126 127 128 129 130 131 132 133 |
if (ret == -EAGAIN) { if (root->defrag_max.objectid > root->defrag_progress.objectid) goto done; if (root->defrag_max.type > root->defrag_progress.type) goto done; if (root->defrag_max.offset > root->defrag_progress.offset) goto done; ret = 0; } done: |
6702ed490
|
134 135 136 |
if (ret != -EAGAIN) { memset(&root->defrag_progress, 0, sizeof(root->defrag_progress)); |
3f157a2fd
|
137 |
root->defrag_trans_start = trans->transid; |
6702ed490
|
138 139 140 |
} return ret; } |