diff options
author | Miao Xie <miaox@cn.fujitsu.com> | 2012-05-24 06:58:27 -0400 |
---|---|---|
committer | Josef Bacik <josef@redhat.com> | 2012-05-30 10:23:38 -0400 |
commit | 762f2263260d576504aeb23d20f90120acdb025f (patch) | |
tree | 9f6e426d359faf438775df1d1cc5a59a4924478f /fs/btrfs/file.c | |
parent | 2adcac1a7331d93a17285804819caa96070b231f (diff) |
Btrfs: fix the same inode id problem when doing auto defragment
Two files in the different subvolumes may have the same inode id, so
The rb-tree which is used to manage the defragment object must take it
into account. This patch fix this problem.
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
Diffstat (limited to 'fs/btrfs/file.c')
-rw-r--r-- | fs/btrfs/file.c | 49 |
1 files changed, 39 insertions, 10 deletions
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index c9005f216975..2e63cdc2b093 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
@@ -65,6 +65,21 @@ struct inode_defrag { | |||
65 | int cycled; | 65 | int cycled; |
66 | }; | 66 | }; |
67 | 67 | ||
68 | static int __compare_inode_defrag(struct inode_defrag *defrag1, | ||
69 | struct inode_defrag *defrag2) | ||
70 | { | ||
71 | if (defrag1->root > defrag2->root) | ||
72 | return 1; | ||
73 | else if (defrag1->root < defrag2->root) | ||
74 | return -1; | ||
75 | else if (defrag1->ino > defrag2->ino) | ||
76 | return 1; | ||
77 | else if (defrag1->ino < defrag2->ino) | ||
78 | return -1; | ||
79 | else | ||
80 | return 0; | ||
81 | } | ||
82 | |||
68 | /* pop a record for an inode into the defrag tree. The lock | 83 | /* pop a record for an inode into the defrag tree. The lock |
69 | * must be held already | 84 | * must be held already |
70 | * | 85 | * |
@@ -81,15 +96,17 @@ static void __btrfs_add_inode_defrag(struct inode *inode, | |||
81 | struct inode_defrag *entry; | 96 | struct inode_defrag *entry; |
82 | struct rb_node **p; | 97 | struct rb_node **p; |
83 | struct rb_node *parent = NULL; | 98 | struct rb_node *parent = NULL; |
99 | int ret; | ||
84 | 100 | ||
85 | p = &root->fs_info->defrag_inodes.rb_node; | 101 | p = &root->fs_info->defrag_inodes.rb_node; |
86 | while (*p) { | 102 | while (*p) { |
87 | parent = *p; | 103 | parent = *p; |
88 | entry = rb_entry(parent, struct inode_defrag, rb_node); | 104 | entry = rb_entry(parent, struct inode_defrag, rb_node); |
89 | 105 | ||
90 | if (defrag->ino < entry->ino) | 106 | ret = __compare_inode_defrag(defrag, entry); |
107 | if (ret < 0) | ||
91 | p = &parent->rb_left; | 108 | p = &parent->rb_left; |
92 | else if (defrag->ino > entry->ino) | 109 | else if (ret > 0) |
93 | p = &parent->rb_right; | 110 | p = &parent->rb_right; |
94 | else { | 111 | else { |
95 | /* if we're reinserting an entry for | 112 | /* if we're reinserting an entry for |
@@ -159,28 +176,35 @@ int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans, | |||
159 | /* | 176 | /* |
160 | * must be called with the defrag_inodes lock held | 177 | * must be called with the defrag_inodes lock held |
161 | */ | 178 | */ |
162 | struct inode_defrag *btrfs_find_defrag_inode(struct btrfs_fs_info *info, u64 ino, | 179 | struct inode_defrag *btrfs_find_defrag_inode(struct btrfs_fs_info *info, |
180 | u64 root, u64 ino, | ||
163 | struct rb_node **next) | 181 | struct rb_node **next) |
164 | { | 182 | { |
165 | struct inode_defrag *entry = NULL; | 183 | struct inode_defrag *entry = NULL; |
184 | struct inode_defrag tmp; | ||
166 | struct rb_node *p; | 185 | struct rb_node *p; |
167 | struct rb_node *parent = NULL; | 186 | struct rb_node *parent = NULL; |
187 | int ret; | ||
188 | |||
189 | tmp.ino = ino; | ||
190 | tmp.root = root; | ||
168 | 191 | ||
169 | p = info->defrag_inodes.rb_node; | 192 | p = info->defrag_inodes.rb_node; |
170 | while (p) { | 193 | while (p) { |
171 | parent = p; | 194 | parent = p; |
172 | entry = rb_entry(parent, struct inode_defrag, rb_node); | 195 | entry = rb_entry(parent, struct inode_defrag, rb_node); |
173 | 196 | ||
174 | if (ino < entry->ino) | 197 | ret = __compare_inode_defrag(&tmp, entry); |
198 | if (ret < 0) | ||
175 | p = parent->rb_left; | 199 | p = parent->rb_left; |
176 | else if (ino > entry->ino) | 200 | else if (ret > 0) |
177 | p = parent->rb_right; | 201 | p = parent->rb_right; |
178 | else | 202 | else |
179 | return entry; | 203 | return entry; |
180 | } | 204 | } |
181 | 205 | ||
182 | if (next) { | 206 | if (next) { |
183 | while (parent && ino > entry->ino) { | 207 | while (parent && __compare_inode_defrag(&tmp, entry) > 0) { |
184 | parent = rb_next(parent); | 208 | parent = rb_next(parent); |
185 | entry = rb_entry(parent, struct inode_defrag, rb_node); | 209 | entry = rb_entry(parent, struct inode_defrag, rb_node); |
186 | } | 210 | } |
@@ -202,6 +226,7 @@ int btrfs_run_defrag_inodes(struct btrfs_fs_info *fs_info) | |||
202 | struct btrfs_key key; | 226 | struct btrfs_key key; |
203 | struct btrfs_ioctl_defrag_range_args range; | 227 | struct btrfs_ioctl_defrag_range_args range; |
204 | u64 first_ino = 0; | 228 | u64 first_ino = 0; |
229 | u64 root_objectid = 0; | ||
205 | int num_defrag; | 230 | int num_defrag; |
206 | int defrag_batch = 1024; | 231 | int defrag_batch = 1024; |
207 | 232 | ||
@@ -214,11 +239,14 @@ int btrfs_run_defrag_inodes(struct btrfs_fs_info *fs_info) | |||
214 | n = NULL; | 239 | n = NULL; |
215 | 240 | ||
216 | /* find an inode to defrag */ | 241 | /* find an inode to defrag */ |
217 | defrag = btrfs_find_defrag_inode(fs_info, first_ino, &n); | 242 | defrag = btrfs_find_defrag_inode(fs_info, root_objectid, |
243 | first_ino, &n); | ||
218 | if (!defrag) { | 244 | if (!defrag) { |
219 | if (n) | 245 | if (n) { |
220 | defrag = rb_entry(n, struct inode_defrag, rb_node); | 246 | defrag = rb_entry(n, struct inode_defrag, |
221 | else if (first_ino) { | 247 | rb_node); |
248 | } else if (root_objectid || first_ino) { | ||
249 | root_objectid = 0; | ||
222 | first_ino = 0; | 250 | first_ino = 0; |
223 | continue; | 251 | continue; |
224 | } else { | 252 | } else { |
@@ -228,6 +256,7 @@ int btrfs_run_defrag_inodes(struct btrfs_fs_info *fs_info) | |||
228 | 256 | ||
229 | /* remove it from the rbtree */ | 257 | /* remove it from the rbtree */ |
230 | first_ino = defrag->ino + 1; | 258 | first_ino = defrag->ino + 1; |
259 | root_objectid = defrag->root; | ||
231 | rb_erase(&defrag->rb_node, &fs_info->defrag_inodes); | 260 | rb_erase(&defrag->rb_node, &fs_info->defrag_inodes); |
232 | 261 | ||
233 | if (btrfs_fs_closing(fs_info)) | 262 | if (btrfs_fs_closing(fs_info)) |