diff options
Diffstat (limited to 'fs/btrfs/transaction.c')
-rw-r--r-- | fs/btrfs/transaction.c | 81 |
1 files changed, 78 insertions, 3 deletions
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 3ed5868e7c0f..dc9865323e38 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -66,6 +66,7 @@ static int join_transaction(struct btrfs_root *root) | |||
66 | cur_trans->use_count = 1; | 66 | cur_trans->use_count = 1; |
67 | cur_trans->commit_done = 0; | 67 | cur_trans->commit_done = 0; |
68 | cur_trans->start_time = get_seconds(); | 68 | cur_trans->start_time = get_seconds(); |
69 | INIT_LIST_HEAD(&cur_trans->pending_snapshots); | ||
69 | list_add_tail(&cur_trans->list, &root->fs_info->trans_list); | 70 | list_add_tail(&cur_trans->list, &root->fs_info->trans_list); |
70 | btrfs_ordered_inode_tree_init(&cur_trans->ordered_inode_tree); | 71 | btrfs_ordered_inode_tree_init(&cur_trans->ordered_inode_tree); |
71 | extent_map_tree_init(&cur_trans->dirty_pages, | 72 | extent_map_tree_init(&cur_trans->dirty_pages, |
@@ -481,10 +482,8 @@ int btrfs_write_ordered_inodes(struct btrfs_trans_handle *trans, | |||
481 | struct inode *inode; | 482 | struct inode *inode; |
482 | u64 root_objectid = 0; | 483 | u64 root_objectid = 0; |
483 | u64 objectid = 0; | 484 | u64 objectid = 0; |
484 | u64 transid = trans->transid; | ||
485 | int ret; | 485 | int ret; |
486 | 486 | ||
487 | printk("write ordered trans %Lu\n", transid); | ||
488 | while(1) { | 487 | while(1) { |
489 | ret = btrfs_find_first_ordered_inode( | 488 | ret = btrfs_find_first_ordered_inode( |
490 | &cur_trans->ordered_inode_tree, | 489 | &cur_trans->ordered_inode_tree, |
@@ -524,7 +523,80 @@ printk("write ordered trans %Lu\n", transid); | |||
524 | mutex_lock(&root->fs_info->fs_mutex); | 523 | mutex_lock(&root->fs_info->fs_mutex); |
525 | mutex_lock(&root->fs_info->trans_mutex); | 524 | mutex_lock(&root->fs_info->trans_mutex); |
526 | } | 525 | } |
527 | printk("done write ordered trans %Lu\n", transid); | 526 | return 0; |
527 | } | ||
528 | |||
529 | static int create_pending_snapshot(struct btrfs_trans_handle *trans, | ||
530 | struct btrfs_fs_info *fs_info, | ||
531 | struct btrfs_pending_snapshot *pending) | ||
532 | { | ||
533 | struct btrfs_key key; | ||
534 | struct btrfs_root_item new_root_item; | ||
535 | struct btrfs_root *tree_root = fs_info->tree_root; | ||
536 | struct btrfs_root *root = pending->root; | ||
537 | struct extent_buffer *tmp; | ||
538 | int ret; | ||
539 | u64 objectid; | ||
540 | |||
541 | ret = btrfs_find_free_objectid(trans, tree_root, 0, &objectid); | ||
542 | if (ret) | ||
543 | goto fail; | ||
544 | |||
545 | memcpy(&new_root_item, &root->root_item, sizeof(new_root_item)); | ||
546 | |||
547 | key.objectid = objectid; | ||
548 | key.offset = 1; | ||
549 | btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); | ||
550 | |||
551 | extent_buffer_get(root->node); | ||
552 | btrfs_cow_block(trans, root, root->node, NULL, 0, &tmp); | ||
553 | free_extent_buffer(tmp); | ||
554 | |||
555 | btrfs_copy_root(trans, root, root->node, &tmp, objectid); | ||
556 | |||
557 | btrfs_set_root_bytenr(&new_root_item, tmp->start); | ||
558 | btrfs_set_root_level(&new_root_item, btrfs_header_level(tmp)); | ||
559 | ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key, | ||
560 | &new_root_item); | ||
561 | free_extent_buffer(tmp); | ||
562 | if (ret) | ||
563 | goto fail; | ||
564 | |||
565 | /* | ||
566 | * insert the directory item | ||
567 | */ | ||
568 | key.offset = (u64)-1; | ||
569 | ret = btrfs_insert_dir_item(trans, root->fs_info->tree_root, | ||
570 | pending->name, strlen(pending->name), | ||
571 | root->fs_info->sb->s_root->d_inode->i_ino, | ||
572 | &key, BTRFS_FT_DIR); | ||
573 | |||
574 | if (ret) | ||
575 | goto fail; | ||
576 | |||
577 | ret = btrfs_insert_inode_ref(trans, root->fs_info->tree_root, | ||
578 | pending->name, strlen(pending->name), objectid, | ||
579 | root->fs_info->sb->s_root->d_inode->i_ino); | ||
580 | fail: | ||
581 | return ret; | ||
582 | } | ||
583 | |||
584 | static int create_pending_snapshots(struct btrfs_trans_handle *trans, | ||
585 | struct btrfs_fs_info *fs_info) | ||
586 | { | ||
587 | struct btrfs_pending_snapshot *pending; | ||
588 | struct list_head *head = &trans->transaction->pending_snapshots; | ||
589 | int ret; | ||
590 | |||
591 | while(!list_empty(head)) { | ||
592 | pending = list_entry(head->next, | ||
593 | struct btrfs_pending_snapshot, list); | ||
594 | ret = create_pending_snapshot(trans, fs_info, pending); | ||
595 | BUG_ON(ret); | ||
596 | list_del(&pending->list); | ||
597 | kfree(pending->name); | ||
598 | kfree(pending); | ||
599 | } | ||
528 | return 0; | 600 | return 0; |
529 | } | 601 | } |
530 | 602 | ||
@@ -610,6 +682,9 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
610 | } while (cur_trans->num_writers > 1 || | 682 | } while (cur_trans->num_writers > 1 || |
611 | (cur_trans->num_joined != joined)); | 683 | (cur_trans->num_joined != joined)); |
612 | 684 | ||
685 | ret = create_pending_snapshots(trans, root->fs_info); | ||
686 | BUG_ON(ret); | ||
687 | |||
613 | WARN_ON(cur_trans != trans->transaction); | 688 | WARN_ON(cur_trans != trans->transaction); |
614 | 689 | ||
615 | ret = add_dirty_roots(trans, &root->fs_info->fs_roots_radix, | 690 | ret = add_dirty_roots(trans, &root->fs_info->fs_roots_radix, |