diff options
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/ctree.h | 24 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 391 | ||||
-rw-r--r-- | fs/btrfs/disk-io.h | 1 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 11 | ||||
-rw-r--r-- | fs/btrfs/file.c | 11 | ||||
-rw-r--r-- | fs/btrfs/super.c | 84 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 3 |
7 files changed, 523 insertions, 2 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 0995f4f68d7a..72195378bef9 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -295,6 +295,14 @@ static inline unsigned long btrfs_chunk_item_size(int num_stripes) | |||
295 | #define BTRFS_FSID_SIZE 16 | 295 | #define BTRFS_FSID_SIZE 16 |
296 | #define BTRFS_HEADER_FLAG_WRITTEN (1ULL << 0) | 296 | #define BTRFS_HEADER_FLAG_WRITTEN (1ULL << 0) |
297 | #define BTRFS_HEADER_FLAG_RELOC (1ULL << 1) | 297 | #define BTRFS_HEADER_FLAG_RELOC (1ULL << 1) |
298 | |||
299 | /* | ||
300 | * File system states | ||
301 | */ | ||
302 | |||
303 | /* Errors detected */ | ||
304 | #define BTRFS_SUPER_FLAG_ERROR (1ULL << 2) | ||
305 | |||
298 | #define BTRFS_SUPER_FLAG_SEEDING (1ULL << 32) | 306 | #define BTRFS_SUPER_FLAG_SEEDING (1ULL << 32) |
299 | #define BTRFS_SUPER_FLAG_METADUMP (1ULL << 33) | 307 | #define BTRFS_SUPER_FLAG_METADUMP (1ULL << 33) |
300 | 308 | ||
@@ -1058,6 +1066,9 @@ struct btrfs_fs_info { | |||
1058 | unsigned metadata_ratio; | 1066 | unsigned metadata_ratio; |
1059 | 1067 | ||
1060 | void *bdev_holder; | 1068 | void *bdev_holder; |
1069 | |||
1070 | /* filesystem state */ | ||
1071 | u64 fs_state; | ||
1061 | }; | 1072 | }; |
1062 | 1073 | ||
1063 | /* | 1074 | /* |
@@ -2203,6 +2214,11 @@ int btrfs_set_block_group_rw(struct btrfs_root *root, | |||
2203 | struct btrfs_block_group_cache *cache); | 2214 | struct btrfs_block_group_cache *cache); |
2204 | void btrfs_put_block_group_cache(struct btrfs_fs_info *info); | 2215 | void btrfs_put_block_group_cache(struct btrfs_fs_info *info); |
2205 | u64 btrfs_account_ro_block_groups_free_space(struct btrfs_space_info *sinfo); | 2216 | u64 btrfs_account_ro_block_groups_free_space(struct btrfs_space_info *sinfo); |
2217 | int btrfs_error_unpin_extent_range(struct btrfs_root *root, | ||
2218 | u64 start, u64 end); | ||
2219 | int btrfs_error_discard_extent(struct btrfs_root *root, u64 bytenr, | ||
2220 | u64 num_bytes); | ||
2221 | |||
2206 | /* ctree.c */ | 2222 | /* ctree.c */ |
2207 | int btrfs_bin_search(struct extent_buffer *eb, struct btrfs_key *key, | 2223 | int btrfs_bin_search(struct extent_buffer *eb, struct btrfs_key *key, |
2208 | int level, int *slot); | 2224 | int level, int *slot); |
@@ -2556,6 +2572,14 @@ ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size); | |||
2556 | /* super.c */ | 2572 | /* super.c */ |
2557 | int btrfs_parse_options(struct btrfs_root *root, char *options); | 2573 | int btrfs_parse_options(struct btrfs_root *root, char *options); |
2558 | int btrfs_sync_fs(struct super_block *sb, int wait); | 2574 | int btrfs_sync_fs(struct super_block *sb, int wait); |
2575 | void __btrfs_std_error(struct btrfs_fs_info *fs_info, const char *function, | ||
2576 | unsigned int line, int errno); | ||
2577 | |||
2578 | #define btrfs_std_error(fs_info, errno) \ | ||
2579 | do { \ | ||
2580 | if ((errno)) \ | ||
2581 | __btrfs_std_error((fs_info), __func__, __LINE__, (errno));\ | ||
2582 | } while (0) | ||
2559 | 2583 | ||
2560 | /* acl.c */ | 2584 | /* acl.c */ |
2561 | #ifdef CONFIG_BTRFS_FS_POSIX_ACL | 2585 | #ifdef CONFIG_BTRFS_FS_POSIX_ACL |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 9b1dd4138072..1a3af9e8e0c4 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -44,6 +44,20 @@ | |||
44 | static struct extent_io_ops btree_extent_io_ops; | 44 | static struct extent_io_ops btree_extent_io_ops; |
45 | static void end_workqueue_fn(struct btrfs_work *work); | 45 | static void end_workqueue_fn(struct btrfs_work *work); |
46 | static void free_fs_root(struct btrfs_root *root); | 46 | static void free_fs_root(struct btrfs_root *root); |
47 | static void btrfs_check_super_valid(struct btrfs_fs_info *fs_info, | ||
48 | int read_only); | ||
49 | static int btrfs_destroy_ordered_operations(struct btrfs_root *root); | ||
50 | static int btrfs_destroy_ordered_extents(struct btrfs_root *root); | ||
51 | static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans, | ||
52 | struct btrfs_root *root); | ||
53 | static int btrfs_destroy_pending_snapshots(struct btrfs_transaction *t); | ||
54 | static int btrfs_destroy_delalloc_inodes(struct btrfs_root *root); | ||
55 | static int btrfs_destroy_marked_extents(struct btrfs_root *root, | ||
56 | struct extent_io_tree *dirty_pages, | ||
57 | int mark); | ||
58 | static int btrfs_destroy_pinned_extent(struct btrfs_root *root, | ||
59 | struct extent_io_tree *pinned_extents); | ||
60 | static int btrfs_cleanup_transaction(struct btrfs_root *root); | ||
47 | 61 | ||
48 | /* | 62 | /* |
49 | * end_io_wq structs are used to do processing in task context when an IO is | 63 | * end_io_wq structs are used to do processing in task context when an IO is |
@@ -1738,6 +1752,11 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
1738 | if (!btrfs_super_root(disk_super)) | 1752 | if (!btrfs_super_root(disk_super)) |
1739 | goto fail_iput; | 1753 | goto fail_iput; |
1740 | 1754 | ||
1755 | /* check FS state, whether FS is broken. */ | ||
1756 | fs_info->fs_state |= btrfs_super_flags(disk_super); | ||
1757 | |||
1758 | btrfs_check_super_valid(fs_info, sb->s_flags & MS_RDONLY); | ||
1759 | |||
1741 | ret = btrfs_parse_options(tree_root, options); | 1760 | ret = btrfs_parse_options(tree_root, options); |
1742 | if (ret) { | 1761 | if (ret) { |
1743 | err = ret; | 1762 | err = ret; |
@@ -1968,7 +1987,9 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
1968 | btrfs_set_opt(fs_info->mount_opt, SSD); | 1987 | btrfs_set_opt(fs_info->mount_opt, SSD); |
1969 | } | 1988 | } |
1970 | 1989 | ||
1971 | if (btrfs_super_log_root(disk_super) != 0) { | 1990 | /* do not make disk changes in broken FS */ |
1991 | if (btrfs_super_log_root(disk_super) != 0 && | ||
1992 | !(fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR)) { | ||
1972 | u64 bytenr = btrfs_super_log_root(disk_super); | 1993 | u64 bytenr = btrfs_super_log_root(disk_super); |
1973 | 1994 | ||
1974 | if (fs_devices->rw_devices == 0) { | 1995 | if (fs_devices->rw_devices == 0) { |
@@ -2464,8 +2485,28 @@ int close_ctree(struct btrfs_root *root) | |||
2464 | smp_mb(); | 2485 | smp_mb(); |
2465 | 2486 | ||
2466 | btrfs_put_block_group_cache(fs_info); | 2487 | btrfs_put_block_group_cache(fs_info); |
2488 | |||
2489 | /* | ||
2490 | * Here come 2 situations when btrfs is broken to flip readonly: | ||
2491 | * | ||
2492 | * 1. when btrfs flips readonly somewhere else before | ||
2493 | * btrfs_commit_super, sb->s_flags has MS_RDONLY flag, | ||
2494 | * and btrfs will skip to write sb directly to keep | ||
2495 | * ERROR state on disk. | ||
2496 | * | ||
2497 | * 2. when btrfs flips readonly just in btrfs_commit_super, | ||
2498 | * and in such case, btrfs cannnot write sb via btrfs_commit_super, | ||
2499 | * and since fs_state has been set BTRFS_SUPER_FLAG_ERROR flag, | ||
2500 | * btrfs will cleanup all FS resources first and write sb then. | ||
2501 | */ | ||
2467 | if (!(fs_info->sb->s_flags & MS_RDONLY)) { | 2502 | if (!(fs_info->sb->s_flags & MS_RDONLY)) { |
2468 | ret = btrfs_commit_super(root); | 2503 | ret = btrfs_commit_super(root); |
2504 | if (ret) | ||
2505 | printk(KERN_ERR "btrfs: commit super ret %d\n", ret); | ||
2506 | } | ||
2507 | |||
2508 | if (fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) { | ||
2509 | ret = btrfs_error_commit_super(root); | ||
2469 | if (ret) | 2510 | if (ret) |
2470 | printk(KERN_ERR "btrfs: commit super ret %d\n", ret); | 2511 | printk(KERN_ERR "btrfs: commit super ret %d\n", ret); |
2471 | } | 2512 | } |
@@ -2641,6 +2682,352 @@ out: | |||
2641 | return 0; | 2682 | return 0; |
2642 | } | 2683 | } |
2643 | 2684 | ||
2685 | static void btrfs_check_super_valid(struct btrfs_fs_info *fs_info, | ||
2686 | int read_only) | ||
2687 | { | ||
2688 | if (read_only) | ||
2689 | return; | ||
2690 | |||
2691 | if (fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) | ||
2692 | printk(KERN_WARNING "warning: mount fs with errors, " | ||
2693 | "running btrfsck is recommended\n"); | ||
2694 | } | ||
2695 | |||
2696 | int btrfs_error_commit_super(struct btrfs_root *root) | ||
2697 | { | ||
2698 | int ret; | ||
2699 | |||
2700 | mutex_lock(&root->fs_info->cleaner_mutex); | ||
2701 | btrfs_run_delayed_iputs(root); | ||
2702 | mutex_unlock(&root->fs_info->cleaner_mutex); | ||
2703 | |||
2704 | down_write(&root->fs_info->cleanup_work_sem); | ||
2705 | up_write(&root->fs_info->cleanup_work_sem); | ||
2706 | |||
2707 | /* cleanup FS via transaction */ | ||
2708 | btrfs_cleanup_transaction(root); | ||
2709 | |||
2710 | ret = write_ctree_super(NULL, root, 0); | ||
2711 | |||
2712 | return ret; | ||
2713 | } | ||
2714 | |||
2715 | static int btrfs_destroy_ordered_operations(struct btrfs_root *root) | ||
2716 | { | ||
2717 | struct btrfs_inode *btrfs_inode; | ||
2718 | struct list_head splice; | ||
2719 | |||
2720 | INIT_LIST_HEAD(&splice); | ||
2721 | |||
2722 | mutex_lock(&root->fs_info->ordered_operations_mutex); | ||
2723 | spin_lock(&root->fs_info->ordered_extent_lock); | ||
2724 | |||
2725 | list_splice_init(&root->fs_info->ordered_operations, &splice); | ||
2726 | while (!list_empty(&splice)) { | ||
2727 | btrfs_inode = list_entry(splice.next, struct btrfs_inode, | ||
2728 | ordered_operations); | ||
2729 | |||
2730 | list_del_init(&btrfs_inode->ordered_operations); | ||
2731 | |||
2732 | btrfs_invalidate_inodes(btrfs_inode->root); | ||
2733 | } | ||
2734 | |||
2735 | spin_unlock(&root->fs_info->ordered_extent_lock); | ||
2736 | mutex_unlock(&root->fs_info->ordered_operations_mutex); | ||
2737 | |||
2738 | return 0; | ||
2739 | } | ||
2740 | |||
2741 | static int btrfs_destroy_ordered_extents(struct btrfs_root *root) | ||
2742 | { | ||
2743 | struct list_head splice; | ||
2744 | struct btrfs_ordered_extent *ordered; | ||
2745 | struct inode *inode; | ||
2746 | |||
2747 | INIT_LIST_HEAD(&splice); | ||
2748 | |||
2749 | spin_lock(&root->fs_info->ordered_extent_lock); | ||
2750 | |||
2751 | list_splice_init(&root->fs_info->ordered_extents, &splice); | ||
2752 | while (!list_empty(&splice)) { | ||
2753 | ordered = list_entry(splice.next, struct btrfs_ordered_extent, | ||
2754 | root_extent_list); | ||
2755 | |||
2756 | list_del_init(&ordered->root_extent_list); | ||
2757 | atomic_inc(&ordered->refs); | ||
2758 | |||
2759 | /* the inode may be getting freed (in sys_unlink path). */ | ||
2760 | inode = igrab(ordered->inode); | ||
2761 | |||
2762 | spin_unlock(&root->fs_info->ordered_extent_lock); | ||
2763 | if (inode) | ||
2764 | iput(inode); | ||
2765 | |||
2766 | atomic_set(&ordered->refs, 1); | ||
2767 | btrfs_put_ordered_extent(ordered); | ||
2768 | |||
2769 | spin_lock(&root->fs_info->ordered_extent_lock); | ||
2770 | } | ||
2771 | |||
2772 | spin_unlock(&root->fs_info->ordered_extent_lock); | ||
2773 | |||
2774 | return 0; | ||
2775 | } | ||
2776 | |||
2777 | static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans, | ||
2778 | struct btrfs_root *root) | ||
2779 | { | ||
2780 | struct rb_node *node; | ||
2781 | struct btrfs_delayed_ref_root *delayed_refs; | ||
2782 | struct btrfs_delayed_ref_node *ref; | ||
2783 | int ret = 0; | ||
2784 | |||
2785 | delayed_refs = &trans->delayed_refs; | ||
2786 | |||
2787 | spin_lock(&delayed_refs->lock); | ||
2788 | if (delayed_refs->num_entries == 0) { | ||
2789 | printk(KERN_INFO "delayed_refs has NO entry\n"); | ||
2790 | return ret; | ||
2791 | } | ||
2792 | |||
2793 | node = rb_first(&delayed_refs->root); | ||
2794 | while (node) { | ||
2795 | ref = rb_entry(node, struct btrfs_delayed_ref_node, rb_node); | ||
2796 | node = rb_next(node); | ||
2797 | |||
2798 | ref->in_tree = 0; | ||
2799 | rb_erase(&ref->rb_node, &delayed_refs->root); | ||
2800 | delayed_refs->num_entries--; | ||
2801 | |||
2802 | atomic_set(&ref->refs, 1); | ||
2803 | if (btrfs_delayed_ref_is_head(ref)) { | ||
2804 | struct btrfs_delayed_ref_head *head; | ||
2805 | |||
2806 | head = btrfs_delayed_node_to_head(ref); | ||
2807 | mutex_lock(&head->mutex); | ||
2808 | kfree(head->extent_op); | ||
2809 | delayed_refs->num_heads--; | ||
2810 | if (list_empty(&head->cluster)) | ||
2811 | delayed_refs->num_heads_ready--; | ||
2812 | list_del_init(&head->cluster); | ||
2813 | mutex_unlock(&head->mutex); | ||
2814 | } | ||
2815 | |||
2816 | spin_unlock(&delayed_refs->lock); | ||
2817 | btrfs_put_delayed_ref(ref); | ||
2818 | |||
2819 | cond_resched(); | ||
2820 | spin_lock(&delayed_refs->lock); | ||
2821 | } | ||
2822 | |||
2823 | spin_unlock(&delayed_refs->lock); | ||
2824 | |||
2825 | return ret; | ||
2826 | } | ||
2827 | |||
2828 | static int btrfs_destroy_pending_snapshots(struct btrfs_transaction *t) | ||
2829 | { | ||
2830 | struct btrfs_pending_snapshot *snapshot; | ||
2831 | struct list_head splice; | ||
2832 | |||
2833 | INIT_LIST_HEAD(&splice); | ||
2834 | |||
2835 | list_splice_init(&t->pending_snapshots, &splice); | ||
2836 | |||
2837 | while (!list_empty(&splice)) { | ||
2838 | snapshot = list_entry(splice.next, | ||
2839 | struct btrfs_pending_snapshot, | ||
2840 | list); | ||
2841 | |||
2842 | list_del_init(&snapshot->list); | ||
2843 | |||
2844 | kfree(snapshot); | ||
2845 | } | ||
2846 | |||
2847 | return 0; | ||
2848 | } | ||
2849 | |||
2850 | static int btrfs_destroy_delalloc_inodes(struct btrfs_root *root) | ||
2851 | { | ||
2852 | struct btrfs_inode *btrfs_inode; | ||
2853 | struct list_head splice; | ||
2854 | |||
2855 | INIT_LIST_HEAD(&splice); | ||
2856 | |||
2857 | list_splice_init(&root->fs_info->delalloc_inodes, &splice); | ||
2858 | |||
2859 | spin_lock(&root->fs_info->delalloc_lock); | ||
2860 | |||
2861 | while (!list_empty(&splice)) { | ||
2862 | btrfs_inode = list_entry(splice.next, struct btrfs_inode, | ||
2863 | delalloc_inodes); | ||
2864 | |||
2865 | list_del_init(&btrfs_inode->delalloc_inodes); | ||
2866 | |||
2867 | btrfs_invalidate_inodes(btrfs_inode->root); | ||
2868 | } | ||
2869 | |||
2870 | spin_unlock(&root->fs_info->delalloc_lock); | ||
2871 | |||
2872 | return 0; | ||
2873 | } | ||
2874 | |||
2875 | static int btrfs_destroy_marked_extents(struct btrfs_root *root, | ||
2876 | struct extent_io_tree *dirty_pages, | ||
2877 | int mark) | ||
2878 | { | ||
2879 | int ret; | ||
2880 | struct page *page; | ||
2881 | struct inode *btree_inode = root->fs_info->btree_inode; | ||
2882 | struct extent_buffer *eb; | ||
2883 | u64 start = 0; | ||
2884 | u64 end; | ||
2885 | u64 offset; | ||
2886 | unsigned long index; | ||
2887 | |||
2888 | while (1) { | ||
2889 | ret = find_first_extent_bit(dirty_pages, start, &start, &end, | ||
2890 | mark); | ||
2891 | if (ret) | ||
2892 | break; | ||
2893 | |||
2894 | clear_extent_bits(dirty_pages, start, end, mark, GFP_NOFS); | ||
2895 | while (start <= end) { | ||
2896 | index = start >> PAGE_CACHE_SHIFT; | ||
2897 | start = (u64)(index + 1) << PAGE_CACHE_SHIFT; | ||
2898 | page = find_get_page(btree_inode->i_mapping, index); | ||
2899 | if (!page) | ||
2900 | continue; | ||
2901 | offset = page_offset(page); | ||
2902 | |||
2903 | spin_lock(&dirty_pages->buffer_lock); | ||
2904 | eb = radix_tree_lookup( | ||
2905 | &(&BTRFS_I(page->mapping->host)->io_tree)->buffer, | ||
2906 | offset >> PAGE_CACHE_SHIFT); | ||
2907 | spin_unlock(&dirty_pages->buffer_lock); | ||
2908 | if (eb) { | ||
2909 | ret = test_and_clear_bit(EXTENT_BUFFER_DIRTY, | ||
2910 | &eb->bflags); | ||
2911 | atomic_set(&eb->refs, 1); | ||
2912 | } | ||
2913 | if (PageWriteback(page)) | ||
2914 | end_page_writeback(page); | ||
2915 | |||
2916 | lock_page(page); | ||
2917 | if (PageDirty(page)) { | ||
2918 | clear_page_dirty_for_io(page); | ||
2919 | spin_lock_irq(&page->mapping->tree_lock); | ||
2920 | radix_tree_tag_clear(&page->mapping->page_tree, | ||
2921 | page_index(page), | ||
2922 | PAGECACHE_TAG_DIRTY); | ||
2923 | spin_unlock_irq(&page->mapping->tree_lock); | ||
2924 | } | ||
2925 | |||
2926 | page->mapping->a_ops->invalidatepage(page, 0); | ||
2927 | unlock_page(page); | ||
2928 | } | ||
2929 | } | ||
2930 | |||
2931 | return ret; | ||
2932 | } | ||
2933 | |||
2934 | static int btrfs_destroy_pinned_extent(struct btrfs_root *root, | ||
2935 | struct extent_io_tree *pinned_extents) | ||
2936 | { | ||
2937 | struct extent_io_tree *unpin; | ||
2938 | u64 start; | ||
2939 | u64 end; | ||
2940 | int ret; | ||
2941 | |||
2942 | unpin = pinned_extents; | ||
2943 | while (1) { | ||
2944 | ret = find_first_extent_bit(unpin, 0, &start, &end, | ||
2945 | EXTENT_DIRTY); | ||
2946 | if (ret) | ||
2947 | break; | ||
2948 | |||
2949 | /* opt_discard */ | ||
2950 | ret = btrfs_error_discard_extent(root, start, end + 1 - start); | ||
2951 | |||
2952 | clear_extent_dirty(unpin, start, end, GFP_NOFS); | ||
2953 | btrfs_error_unpin_extent_range(root, start, end); | ||
2954 | cond_resched(); | ||
2955 | } | ||
2956 | |||
2957 | return 0; | ||
2958 | } | ||
2959 | |||
2960 | static int btrfs_cleanup_transaction(struct btrfs_root *root) | ||
2961 | { | ||
2962 | struct btrfs_transaction *t; | ||
2963 | LIST_HEAD(list); | ||
2964 | |||
2965 | WARN_ON(1); | ||
2966 | |||
2967 | mutex_lock(&root->fs_info->trans_mutex); | ||
2968 | mutex_lock(&root->fs_info->transaction_kthread_mutex); | ||
2969 | |||
2970 | list_splice_init(&root->fs_info->trans_list, &list); | ||
2971 | while (!list_empty(&list)) { | ||
2972 | t = list_entry(list.next, struct btrfs_transaction, list); | ||
2973 | if (!t) | ||
2974 | break; | ||
2975 | |||
2976 | btrfs_destroy_ordered_operations(root); | ||
2977 | |||
2978 | btrfs_destroy_ordered_extents(root); | ||
2979 | |||
2980 | btrfs_destroy_delayed_refs(t, root); | ||
2981 | |||
2982 | btrfs_block_rsv_release(root, | ||
2983 | &root->fs_info->trans_block_rsv, | ||
2984 | t->dirty_pages.dirty_bytes); | ||
2985 | |||
2986 | /* FIXME: cleanup wait for commit */ | ||
2987 | t->in_commit = 1; | ||
2988 | t->blocked = 1; | ||
2989 | if (waitqueue_active(&root->fs_info->transaction_blocked_wait)) | ||
2990 | wake_up(&root->fs_info->transaction_blocked_wait); | ||
2991 | |||
2992 | t->blocked = 0; | ||
2993 | if (waitqueue_active(&root->fs_info->transaction_wait)) | ||
2994 | wake_up(&root->fs_info->transaction_wait); | ||
2995 | mutex_unlock(&root->fs_info->trans_mutex); | ||
2996 | |||
2997 | mutex_lock(&root->fs_info->trans_mutex); | ||
2998 | t->commit_done = 1; | ||
2999 | if (waitqueue_active(&t->commit_wait)) | ||
3000 | wake_up(&t->commit_wait); | ||
3001 | mutex_unlock(&root->fs_info->trans_mutex); | ||
3002 | |||
3003 | mutex_lock(&root->fs_info->trans_mutex); | ||
3004 | |||
3005 | btrfs_destroy_pending_snapshots(t); | ||
3006 | |||
3007 | btrfs_destroy_delalloc_inodes(root); | ||
3008 | |||
3009 | spin_lock(&root->fs_info->new_trans_lock); | ||
3010 | root->fs_info->running_transaction = NULL; | ||
3011 | spin_unlock(&root->fs_info->new_trans_lock); | ||
3012 | |||
3013 | btrfs_destroy_marked_extents(root, &t->dirty_pages, | ||
3014 | EXTENT_DIRTY); | ||
3015 | |||
3016 | btrfs_destroy_pinned_extent(root, | ||
3017 | root->fs_info->pinned_extents); | ||
3018 | |||
3019 | t->use_count = 0; | ||
3020 | list_del_init(&t->list); | ||
3021 | memset(t, 0, sizeof(*t)); | ||
3022 | kmem_cache_free(btrfs_transaction_cachep, t); | ||
3023 | } | ||
3024 | |||
3025 | mutex_unlock(&root->fs_info->transaction_kthread_mutex); | ||
3026 | mutex_unlock(&root->fs_info->trans_mutex); | ||
3027 | |||
3028 | return 0; | ||
3029 | } | ||
3030 | |||
2644 | static struct extent_io_ops btree_extent_io_ops = { | 3031 | static struct extent_io_ops btree_extent_io_ops = { |
2645 | .write_cache_pages_lock_hook = btree_lock_page_hook, | 3032 | .write_cache_pages_lock_hook = btree_lock_page_hook, |
2646 | .readpage_end_io_hook = btree_readpage_end_io_hook, | 3033 | .readpage_end_io_hook = btree_readpage_end_io_hook, |
diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h index 88e825a0bf21..07b20dc2fd95 100644 --- a/fs/btrfs/disk-io.h +++ b/fs/btrfs/disk-io.h | |||
@@ -52,6 +52,7 @@ int write_ctree_super(struct btrfs_trans_handle *trans, | |||
52 | struct btrfs_root *root, int max_mirrors); | 52 | struct btrfs_root *root, int max_mirrors); |
53 | struct buffer_head *btrfs_read_dev_super(struct block_device *bdev); | 53 | struct buffer_head *btrfs_read_dev_super(struct block_device *bdev); |
54 | int btrfs_commit_super(struct btrfs_root *root); | 54 | int btrfs_commit_super(struct btrfs_root *root); |
55 | int btrfs_error_commit_super(struct btrfs_root *root); | ||
55 | struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root, | 56 | struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root, |
56 | u64 bytenr, u32 blocksize); | 57 | u64 bytenr, u32 blocksize); |
57 | struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info, | 58 | struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info, |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 055b837eab19..bcf303204f7f 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -8642,3 +8642,14 @@ out: | |||
8642 | btrfs_free_path(path); | 8642 | btrfs_free_path(path); |
8643 | return ret; | 8643 | return ret; |
8644 | } | 8644 | } |
8645 | |||
8646 | int btrfs_error_unpin_extent_range(struct btrfs_root *root, u64 start, u64 end) | ||
8647 | { | ||
8648 | return unpin_extent_range(root, start, end); | ||
8649 | } | ||
8650 | |||
8651 | int btrfs_error_discard_extent(struct btrfs_root *root, u64 bytenr, | ||
8652 | u64 num_bytes) | ||
8653 | { | ||
8654 | return btrfs_discard_extent(root, bytenr, num_bytes); | ||
8655 | } | ||
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 05df688c96f4..f903433f5bdf 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
@@ -892,6 +892,17 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb, | |||
892 | if (err) | 892 | if (err) |
893 | goto out; | 893 | goto out; |
894 | 894 | ||
895 | /* | ||
896 | * If BTRFS flips readonly due to some impossible error | ||
897 | * (fs_info->fs_state now has BTRFS_SUPER_FLAG_ERROR), | ||
898 | * although we have opened a file as writable, we have | ||
899 | * to stop this write operation to ensure FS consistency. | ||
900 | */ | ||
901 | if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) { | ||
902 | err = -EROFS; | ||
903 | goto out; | ||
904 | } | ||
905 | |||
895 | file_update_time(file); | 906 | file_update_time(file); |
896 | BTRFS_I(inode)->sequence++; | 907 | BTRFS_I(inode)->sequence++; |
897 | 908 | ||
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 2963376e77f4..52e903b0a293 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
@@ -54,6 +54,90 @@ | |||
54 | 54 | ||
55 | static const struct super_operations btrfs_super_ops; | 55 | static const struct super_operations btrfs_super_ops; |
56 | 56 | ||
57 | static const char *btrfs_decode_error(struct btrfs_fs_info *fs_info, int errno, | ||
58 | char nbuf[16]) | ||
59 | { | ||
60 | char *errstr = NULL; | ||
61 | |||
62 | switch (errno) { | ||
63 | case -EIO: | ||
64 | errstr = "IO failure"; | ||
65 | break; | ||
66 | case -ENOMEM: | ||
67 | errstr = "Out of memory"; | ||
68 | break; | ||
69 | case -EROFS: | ||
70 | errstr = "Readonly filesystem"; | ||
71 | break; | ||
72 | default: | ||
73 | if (nbuf) { | ||
74 | if (snprintf(nbuf, 16, "error %d", -errno) >= 0) | ||
75 | errstr = nbuf; | ||
76 | } | ||
77 | break; | ||
78 | } | ||
79 | |||
80 | return errstr; | ||
81 | } | ||
82 | |||
83 | static void __save_error_info(struct btrfs_fs_info *fs_info) | ||
84 | { | ||
85 | /* | ||
86 | * today we only save the error info into ram. Long term we'll | ||
87 | * also send it down to the disk | ||
88 | */ | ||
89 | fs_info->fs_state = BTRFS_SUPER_FLAG_ERROR; | ||
90 | } | ||
91 | |||
92 | /* NOTE: | ||
93 | * We move write_super stuff at umount in order to avoid deadlock | ||
94 | * for umount hold all lock. | ||
95 | */ | ||
96 | static void save_error_info(struct btrfs_fs_info *fs_info) | ||
97 | { | ||
98 | __save_error_info(fs_info); | ||
99 | } | ||
100 | |||
101 | /* btrfs handle error by forcing the filesystem readonly */ | ||
102 | static void btrfs_handle_error(struct btrfs_fs_info *fs_info) | ||
103 | { | ||
104 | struct super_block *sb = fs_info->sb; | ||
105 | |||
106 | if (sb->s_flags & MS_RDONLY) | ||
107 | return; | ||
108 | |||
109 | if (fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) { | ||
110 | sb->s_flags |= MS_RDONLY; | ||
111 | printk(KERN_INFO "btrfs is forced readonly\n"); | ||
112 | } | ||
113 | } | ||
114 | |||
115 | /* | ||
116 | * __btrfs_std_error decodes expected errors from the caller and | ||
117 | * invokes the approciate error response. | ||
118 | */ | ||
119 | void __btrfs_std_error(struct btrfs_fs_info *fs_info, const char *function, | ||
120 | unsigned int line, int errno) | ||
121 | { | ||
122 | struct super_block *sb = fs_info->sb; | ||
123 | char nbuf[16]; | ||
124 | const char *errstr; | ||
125 | |||
126 | /* | ||
127 | * Special case: if the error is EROFS, and we're already | ||
128 | * under MS_RDONLY, then it is safe here. | ||
129 | */ | ||
130 | if (errno == -EROFS && (sb->s_flags & MS_RDONLY)) | ||
131 | return; | ||
132 | |||
133 | errstr = btrfs_decode_error(fs_info, errno, nbuf); | ||
134 | printk(KERN_CRIT "BTRFS error (device %s) in %s:%d: %s\n", | ||
135 | sb->s_id, function, line, errstr); | ||
136 | save_error_info(fs_info); | ||
137 | |||
138 | btrfs_handle_error(fs_info); | ||
139 | } | ||
140 | |||
57 | static void btrfs_put_super(struct super_block *sb) | 141 | static void btrfs_put_super(struct super_block *sb) |
58 | { | 142 | { |
59 | struct btrfs_root *root = btrfs_sb(sb); | 143 | struct btrfs_root *root = btrfs_sb(sb); |
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 29e30d832ec9..bae5c7b8bbe2 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -181,6 +181,9 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root, | |||
181 | struct btrfs_trans_handle *h; | 181 | struct btrfs_trans_handle *h; |
182 | struct btrfs_transaction *cur_trans; | 182 | struct btrfs_transaction *cur_trans; |
183 | int ret; | 183 | int ret; |
184 | |||
185 | if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) | ||
186 | return ERR_PTR(-EROFS); | ||
184 | again: | 187 | again: |
185 | h = kmem_cache_alloc(btrfs_trans_handle_cachep, GFP_NOFS); | 188 | h = kmem_cache_alloc(btrfs_trans_handle_cachep, GFP_NOFS); |
186 | if (!h) | 189 | if (!h) |