aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/transaction.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/transaction.c')
-rw-r--r--fs/btrfs/transaction.c63
1 files changed, 38 insertions, 25 deletions
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 0f494fe365cb..498626470a04 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -213,10 +213,7 @@ static int wait_for_commit(struct btrfs_root *root,
213 213
214struct dirty_root { 214struct dirty_root {
215 struct list_head list; 215 struct list_head list;
216 struct btrfs_key snap_key;
217 struct buffer_head *commit_root;
218 struct btrfs_root *root; 216 struct btrfs_root *root;
219 int free_on_drop;
220}; 217};
221 218
222int btrfs_add_dead_root(struct btrfs_root *root, struct list_head *dead_list) 219int btrfs_add_dead_root(struct btrfs_root *root, struct list_head *dead_list)
@@ -226,10 +223,7 @@ int btrfs_add_dead_root(struct btrfs_root *root, struct list_head *dead_list)
226 dirty = kmalloc(sizeof(*dirty), GFP_NOFS); 223 dirty = kmalloc(sizeof(*dirty), GFP_NOFS);
227 if (!dirty) 224 if (!dirty)
228 return -ENOMEM; 225 return -ENOMEM;
229 memcpy(&dirty->snap_key, &root->root_key, sizeof(root->root_key));
230 dirty->commit_root = root->node;
231 dirty->root = root; 226 dirty->root = root;
232 dirty->free_on_drop = 1;
233 list_add(&dirty->list, dead_list); 227 list_add(&dirty->list, dead_list);
234 return 0; 228 return 0;
235} 229}
@@ -241,7 +235,6 @@ static int add_dirty_roots(struct btrfs_trans_handle *trans,
241 struct dirty_root *dirty; 235 struct dirty_root *dirty;
242 struct btrfs_root *gang[8]; 236 struct btrfs_root *gang[8];
243 struct btrfs_root *root; 237 struct btrfs_root *root;
244 struct btrfs_root_item tmp_item;
245 int i; 238 int i;
246 int ret; 239 int ret;
247 int err = 0; 240 int err = 0;
@@ -267,13 +260,16 @@ static int add_dirty_roots(struct btrfs_trans_handle *trans,
267 } 260 }
268 dirty = kmalloc(sizeof(*dirty), GFP_NOFS); 261 dirty = kmalloc(sizeof(*dirty), GFP_NOFS);
269 BUG_ON(!dirty); 262 BUG_ON(!dirty);
270 memcpy(&dirty->snap_key, &root->root_key, 263 dirty->root = kmalloc(sizeof(*dirty->root), GFP_NOFS);
271 sizeof(root->root_key)); 264 BUG_ON(!dirty->root);
272 dirty->commit_root = root->commit_root; 265
266 memset(&root->root_item.drop_progress, 0,
267 sizeof(struct btrfs_disk_key));
268 root->root_item.drop_level = 0;
269
270 memcpy(dirty->root, root, sizeof(*root));
271 dirty->root->node = root->commit_root;
273 root->commit_root = NULL; 272 root->commit_root = NULL;
274 dirty->root = root;
275 dirty->free_on_drop = 0;
276 memcpy(&tmp_item, &root->root_item, sizeof(tmp_item));
277 273
278 root->root_key.offset = root->fs_info->generation; 274 root->root_key.offset = root->fs_info->generation;
279 btrfs_set_root_blocknr(&root->root_item, 275 btrfs_set_root_blocknr(&root->root_item,
@@ -283,17 +279,21 @@ static int add_dirty_roots(struct btrfs_trans_handle *trans,
283 &root->root_item); 279 &root->root_item);
284 if (err) 280 if (err)
285 break; 281 break;
286 refs = btrfs_root_refs(&tmp_item); 282
287 btrfs_set_root_refs(&tmp_item, refs - 1); 283 refs = btrfs_root_refs(&dirty->root->root_item);
284 btrfs_set_root_refs(&dirty->root->root_item, refs - 1);
288 err = btrfs_update_root(trans, root->fs_info->tree_root, 285 err = btrfs_update_root(trans, root->fs_info->tree_root,
289 &dirty->snap_key, 286 &dirty->root->root_key,
290 &tmp_item); 287 &dirty->root->root_item);
291 288
292 BUG_ON(err); 289 BUG_ON(err);
293 if (refs == 1) 290 if (refs == 1) {
294 list_add(&dirty->list, list); 291 list_add(&dirty->list, list);
295 else 292 } else {
293 WARN_ON(1);
294 kfree(dirty->root);
296 kfree(dirty); 295 kfree(dirty);
296 }
297 } 297 }
298 } 298 }
299 return err; 299 return err;
@@ -305,23 +305,36 @@ static int drop_dirty_roots(struct btrfs_root *tree_root,
305 struct dirty_root *dirty; 305 struct dirty_root *dirty;
306 struct btrfs_trans_handle *trans; 306 struct btrfs_trans_handle *trans;
307 int ret = 0; 307 int ret = 0;
308 int err;
309
308 while(!list_empty(list)) { 310 while(!list_empty(list)) {
309 mutex_lock(&tree_root->fs_info->fs_mutex); 311 mutex_lock(&tree_root->fs_info->fs_mutex);
310 dirty = list_entry(list->next, struct dirty_root, list); 312 dirty = list_entry(list->next, struct dirty_root, list);
311 list_del_init(&dirty->list); 313 list_del_init(&dirty->list);
312 314
313 trans = btrfs_start_transaction(tree_root, 1); 315 while(1) {
314 ret = btrfs_drop_snapshot(trans, dirty->root, 316 trans = btrfs_start_transaction(tree_root, 1);
315 dirty->commit_root); 317 ret = btrfs_drop_snapshot(trans, dirty->root);
318 if (ret != -EAGAIN) {
319 break;
320 }
321 err = btrfs_update_root(trans,
322 tree_root,
323 &dirty->root->root_key,
324 &dirty->root->root_item);
325 if (err)
326 ret = err;
327 ret = btrfs_end_transaction(trans, tree_root);
328 BUG_ON(ret);
329 }
316 BUG_ON(ret); 330 BUG_ON(ret);
317 ret = btrfs_del_root(trans, tree_root, &dirty->snap_key); 331 ret = btrfs_del_root(trans, tree_root, &dirty->root->root_key);
318 if (ret) 332 if (ret)
319 break; 333 break;
320 ret = btrfs_end_transaction(trans, tree_root); 334 ret = btrfs_end_transaction(trans, tree_root);
321 BUG_ON(ret); 335 BUG_ON(ret);
322 336
323 if (dirty->free_on_drop) 337 kfree(dirty->root);
324 kfree(dirty->root);
325 kfree(dirty); 338 kfree(dirty);
326 mutex_unlock(&tree_root->fs_info->fs_mutex); 339 mutex_unlock(&tree_root->fs_info->fs_mutex);
327 btrfs_btree_balance_dirty(tree_root); 340 btrfs_btree_balance_dirty(tree_root);