diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-12-17 20:14:01 -0500 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:03:58 -0400 |
commit | be20aa9dbadc8c06283784ee12bbc0d97dea3418 (patch) | |
tree | 52bd8b7e21b36d10dbb48f8b163eea992c9cfd4a /fs/btrfs | |
parent | b6cda9bcb4df7544c67fc3548a53bc1607d59f46 (diff) |
Btrfs: Add mount option to turn off data cow
A number of workloads do not require copy on write data or checksumming.
mount -o nodatasum to disable checksums and -o nodatacow to disable
both copy on write and checksumming.
In nodatacow mode, copy on write is still performed when a given extent
is under snapshot.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/ctree.c | 53 | ||||
-rw-r--r-- | fs/btrfs/ctree.h | 8 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 101 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 122 | ||||
-rw-r--r-- | fs/btrfs/super.c | 34 |
5 files changed, 293 insertions, 25 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index fd8233e05cf4..585f279d1112 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -70,7 +70,58 @@ void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p) | |||
70 | memset(p, 0, sizeof(*p)); | 70 | memset(p, 0, sizeof(*p)); |
71 | } | 71 | } |
72 | 72 | ||
73 | static int __btrfs_cow_block(struct btrfs_trans_handle *trans, | 73 | int btrfs_copy_root(struct btrfs_trans_handle *trans, |
74 | struct btrfs_root *root, | ||
75 | struct extent_buffer *buf, | ||
76 | struct extent_buffer **cow_ret, u64 new_root_objectid) | ||
77 | { | ||
78 | struct extent_buffer *cow; | ||
79 | u32 nritems; | ||
80 | int ret = 0; | ||
81 | int level; | ||
82 | struct btrfs_key first_key; | ||
83 | struct btrfs_root new_root; | ||
84 | |||
85 | memcpy(&new_root, root, sizeof(new_root)); | ||
86 | new_root.root_key.objectid = new_root_objectid; | ||
87 | |||
88 | WARN_ON(root->ref_cows && trans->transid != | ||
89 | root->fs_info->running_transaction->transid); | ||
90 | WARN_ON(root->ref_cows && trans->transid != root->last_trans); | ||
91 | |||
92 | level = btrfs_header_level(buf); | ||
93 | nritems = btrfs_header_nritems(buf); | ||
94 | if (nritems) { | ||
95 | if (level == 0) | ||
96 | btrfs_item_key_to_cpu(buf, &first_key, 0); | ||
97 | else | ||
98 | btrfs_node_key_to_cpu(buf, &first_key, 0); | ||
99 | } else { | ||
100 | first_key.objectid = 0; | ||
101 | } | ||
102 | cow = __btrfs_alloc_free_block(trans, &new_root, buf->len, | ||
103 | new_root_objectid, | ||
104 | trans->transid, first_key.objectid, | ||
105 | level, buf->start, 0); | ||
106 | if (IS_ERR(cow)) | ||
107 | return PTR_ERR(cow); | ||
108 | |||
109 | copy_extent_buffer(cow, buf, 0, 0, cow->len); | ||
110 | btrfs_set_header_bytenr(cow, cow->start); | ||
111 | btrfs_set_header_generation(cow, trans->transid); | ||
112 | btrfs_set_header_owner(cow, new_root_objectid); | ||
113 | |||
114 | WARN_ON(btrfs_header_generation(buf) > trans->transid); | ||
115 | ret = btrfs_inc_ref(trans, &new_root, buf); | ||
116 | if (ret) | ||
117 | return ret; | ||
118 | |||
119 | btrfs_mark_buffer_dirty(cow); | ||
120 | *cow_ret = cow; | ||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | int __btrfs_cow_block(struct btrfs_trans_handle *trans, | ||
74 | struct btrfs_root *root, | 125 | struct btrfs_root *root, |
75 | struct extent_buffer *buf, | 126 | struct extent_buffer *buf, |
76 | struct extent_buffer *parent, int parent_slot, | 127 | struct extent_buffer *parent, int parent_slot, |
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 5e255cabfd10..b51b021fff85 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -431,6 +431,7 @@ struct btrfs_root { | |||
431 | #define BTRFS_STRING_ITEM_KEY 253 | 431 | #define BTRFS_STRING_ITEM_KEY 253 |
432 | 432 | ||
433 | #define BTRFS_MOUNT_NODATASUM 0x1 | 433 | #define BTRFS_MOUNT_NODATASUM 0x1 |
434 | #define BTRFS_MOUNT_NODATACOW 0x2 | ||
434 | 435 | ||
435 | #define btrfs_clear_opt(o, opt) ((o) &= ~BTRFS_MOUNT_##opt) | 436 | #define btrfs_clear_opt(o, opt) ((o) &= ~BTRFS_MOUNT_##opt) |
436 | #define btrfs_set_opt(o, opt) ((o) |= BTRFS_MOUNT_##opt) | 437 | #define btrfs_set_opt(o, opt) ((o) |= BTRFS_MOUNT_##opt) |
@@ -915,6 +916,9 @@ static inline u32 btrfs_level_size(struct btrfs_root *root, int level) { | |||
915 | btrfs_item_offset_nr(leaf, slot))) | 916 | btrfs_item_offset_nr(leaf, slot))) |
916 | 917 | ||
917 | /* extent-tree.c */ | 918 | /* extent-tree.c */ |
919 | u32 btrfs_count_snapshots_in_path(struct btrfs_root *root, | ||
920 | struct btrfs_path *count_path, | ||
921 | u64 first_extent); | ||
918 | int btrfs_extent_post_op(struct btrfs_trans_handle *trans, | 922 | int btrfs_extent_post_op(struct btrfs_trans_handle *trans, |
919 | struct btrfs_root *root); | 923 | struct btrfs_root *root); |
920 | int btrfs_copy_pinned(struct btrfs_root *root, struct extent_map_tree *copy); | 924 | int btrfs_copy_pinned(struct btrfs_root *root, struct extent_map_tree *copy); |
@@ -974,6 +978,10 @@ int btrfs_cow_block(struct btrfs_trans_handle *trans, | |||
974 | struct btrfs_root *root, struct extent_buffer *buf, | 978 | struct btrfs_root *root, struct extent_buffer *buf, |
975 | struct extent_buffer *parent, int parent_slot, | 979 | struct extent_buffer *parent, int parent_slot, |
976 | struct extent_buffer **cow_ret); | 980 | struct extent_buffer **cow_ret); |
981 | int btrfs_copy_root(struct btrfs_trans_handle *trans, | ||
982 | struct btrfs_root *root, | ||
983 | struct extent_buffer *buf, | ||
984 | struct extent_buffer **cow_ret, u64 new_root_objectid); | ||
977 | int btrfs_extend_item(struct btrfs_trans_handle *trans, struct btrfs_root | 985 | int btrfs_extend_item(struct btrfs_trans_handle *trans, struct btrfs_root |
978 | *root, struct btrfs_path *path, u32 data_size); | 986 | *root, struct btrfs_path *path, u32 data_size); |
979 | int btrfs_truncate_item(struct btrfs_trans_handle *trans, | 987 | int btrfs_truncate_item(struct btrfs_trans_handle *trans, |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 00414836e963..1412d556313f 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -679,6 +679,104 @@ out: | |||
679 | return 0; | 679 | return 0; |
680 | } | 680 | } |
681 | 681 | ||
682 | u32 btrfs_count_snapshots_in_path(struct btrfs_root *root, | ||
683 | struct btrfs_path *count_path, | ||
684 | u64 first_extent) | ||
685 | { | ||
686 | struct btrfs_root *extent_root = root->fs_info->extent_root; | ||
687 | struct btrfs_path *path; | ||
688 | u64 bytenr; | ||
689 | u64 found_objectid; | ||
690 | u64 root_objectid = 0; | ||
691 | u32 total_count = 0; | ||
692 | u32 cur_count; | ||
693 | u32 refs; | ||
694 | u32 nritems; | ||
695 | int ret; | ||
696 | struct btrfs_key key; | ||
697 | struct btrfs_key found_key; | ||
698 | struct extent_buffer *l; | ||
699 | struct btrfs_extent_item *item; | ||
700 | struct btrfs_extent_ref *ref_item; | ||
701 | int level = -1; | ||
702 | |||
703 | path = btrfs_alloc_path(); | ||
704 | again: | ||
705 | if (level == -1) | ||
706 | bytenr = first_extent; | ||
707 | else | ||
708 | bytenr = count_path->nodes[level]->start; | ||
709 | |||
710 | cur_count = 0; | ||
711 | key.objectid = bytenr; | ||
712 | key.offset = 0; | ||
713 | |||
714 | btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY); | ||
715 | ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0); | ||
716 | if (ret < 0) | ||
717 | goto out; | ||
718 | BUG_ON(ret == 0); | ||
719 | |||
720 | l = path->nodes[0]; | ||
721 | btrfs_item_key_to_cpu(l, &found_key, path->slots[0]); | ||
722 | |||
723 | if (found_key.objectid != bytenr || | ||
724 | found_key.type != BTRFS_EXTENT_ITEM_KEY) { | ||
725 | goto out; | ||
726 | } | ||
727 | |||
728 | item = btrfs_item_ptr(l, path->slots[0], struct btrfs_extent_item); | ||
729 | refs = btrfs_extent_refs(l, item); | ||
730 | while (1) { | ||
731 | nritems = btrfs_header_nritems(l); | ||
732 | if (path->slots[0] >= nritems) { | ||
733 | ret = btrfs_next_leaf(extent_root, path); | ||
734 | if (ret == 0) | ||
735 | continue; | ||
736 | break; | ||
737 | } | ||
738 | btrfs_item_key_to_cpu(l, &found_key, path->slots[0]); | ||
739 | if (found_key.objectid != bytenr) | ||
740 | break; | ||
741 | if (found_key.type != BTRFS_EXTENT_REF_KEY) { | ||
742 | path->slots[0]++; | ||
743 | continue; | ||
744 | } | ||
745 | |||
746 | cur_count++; | ||
747 | ref_item = btrfs_item_ptr(l, path->slots[0], | ||
748 | struct btrfs_extent_ref); | ||
749 | found_objectid = btrfs_ref_root(l, ref_item); | ||
750 | |||
751 | if (found_objectid != root_objectid) | ||
752 | total_count++; | ||
753 | |||
754 | if (total_count > 1) | ||
755 | goto out; | ||
756 | |||
757 | if (root_objectid == 0) | ||
758 | root_objectid = found_objectid; | ||
759 | |||
760 | path->slots[0]++; | ||
761 | } | ||
762 | if (cur_count == 0) { | ||
763 | total_count = 0; | ||
764 | goto out; | ||
765 | } | ||
766 | if (total_count > 1) | ||
767 | goto out; | ||
768 | if (level >= 0 && root->node == count_path->nodes[level]) | ||
769 | goto out; | ||
770 | level++; | ||
771 | btrfs_release_path(root, path); | ||
772 | goto again; | ||
773 | |||
774 | out: | ||
775 | btrfs_free_path(path); | ||
776 | return total_count; | ||
777 | |||
778 | } | ||
779 | |||
682 | int btrfs_inc_root_ref(struct btrfs_trans_handle *trans, | 780 | int btrfs_inc_root_ref(struct btrfs_trans_handle *trans, |
683 | struct btrfs_root *root, u64 owner_objectid) | 781 | struct btrfs_root *root, u64 owner_objectid) |
684 | { | 782 | { |
@@ -1127,9 +1225,6 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1127 | if (!path) | 1225 | if (!path) |
1128 | return -ENOMEM; | 1226 | return -ENOMEM; |
1129 | 1227 | ||
1130 | if (ref_generation && owner_objectid == 0 && root_objectid == 3) { | ||
1131 | //printk("drop backref root %Lu gen %Lu byte %Lu\n", root_objectid, ref_generation, bytenr ); | ||
1132 | } | ||
1133 | ret = lookup_extent_backref(trans, extent_root, path, | 1228 | ret = lookup_extent_backref(trans, extent_root, path, |
1134 | bytenr, root_objectid, | 1229 | bytenr, root_objectid, |
1135 | ref_generation, | 1230 | ref_generation, |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 11885cb114e2..91f3fc43e2a9 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -72,21 +72,22 @@ static unsigned char btrfs_type_by_mode[S_IFMT >> S_SHIFT] = { | |||
72 | [S_IFLNK >> S_SHIFT] = BTRFS_FT_SYMLINK, | 72 | [S_IFLNK >> S_SHIFT] = BTRFS_FT_SYMLINK, |
73 | }; | 73 | }; |
74 | 74 | ||
75 | static int run_delalloc_range(struct inode *inode, u64 start, u64 end) | 75 | static int cow_file_range(struct inode *inode, u64 start, u64 end) |
76 | { | 76 | { |
77 | struct btrfs_root *root = BTRFS_I(inode)->root; | 77 | struct btrfs_root *root = BTRFS_I(inode)->root; |
78 | struct btrfs_trans_handle *trans; | 78 | struct btrfs_trans_handle *trans; |
79 | struct btrfs_key ins; | ||
80 | u64 alloc_hint = 0; | 79 | u64 alloc_hint = 0; |
81 | u64 num_bytes; | 80 | u64 num_bytes; |
82 | int ret; | ||
83 | u64 blocksize = root->sectorsize; | 81 | u64 blocksize = root->sectorsize; |
82 | struct btrfs_key ins; | ||
83 | int ret; | ||
84 | 84 | ||
85 | mutex_lock(&root->fs_info->fs_mutex); | ||
86 | trans = btrfs_start_transaction(root, 1); | 85 | trans = btrfs_start_transaction(root, 1); |
87 | btrfs_set_trans_block_group(trans, inode); | ||
88 | BUG_ON(!trans); | 86 | BUG_ON(!trans); |
87 | btrfs_set_trans_block_group(trans, inode); | ||
88 | |||
89 | num_bytes = (end - start + blocksize) & ~(blocksize - 1); | 89 | num_bytes = (end - start + blocksize) & ~(blocksize - 1); |
90 | num_bytes = max(blocksize, num_bytes); | ||
90 | ret = btrfs_drop_extents(trans, root, inode, | 91 | ret = btrfs_drop_extents(trans, root, inode, |
91 | start, start + num_bytes, start, &alloc_hint); | 92 | start, start + num_bytes, start, &alloc_hint); |
92 | 93 | ||
@@ -106,6 +107,101 @@ static int run_delalloc_range(struct inode *inode, u64 start, u64 end) | |||
106 | ins.offset); | 107 | ins.offset); |
107 | out: | 108 | out: |
108 | btrfs_end_transaction(trans, root); | 109 | btrfs_end_transaction(trans, root); |
110 | return ret; | ||
111 | } | ||
112 | |||
113 | static int run_delalloc_nocow(struct inode *inode, u64 start, u64 end) | ||
114 | { | ||
115 | u64 extent_start; | ||
116 | u64 extent_end; | ||
117 | u64 bytenr; | ||
118 | u64 cow_end; | ||
119 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
120 | struct extent_buffer *leaf; | ||
121 | int found_type; | ||
122 | struct btrfs_path *path; | ||
123 | struct btrfs_file_extent_item *item; | ||
124 | int ret; | ||
125 | int err; | ||
126 | struct btrfs_key found_key; | ||
127 | |||
128 | path = btrfs_alloc_path(); | ||
129 | BUG_ON(!path); | ||
130 | again: | ||
131 | ret = btrfs_lookup_file_extent(NULL, root, path, | ||
132 | inode->i_ino, start, 0); | ||
133 | if (ret < 0) { | ||
134 | btrfs_free_path(path); | ||
135 | return ret; | ||
136 | } | ||
137 | |||
138 | cow_end = end; | ||
139 | if (ret != 0) { | ||
140 | if (path->slots[0] == 0) | ||
141 | goto not_found; | ||
142 | path->slots[0]--; | ||
143 | } | ||
144 | |||
145 | leaf = path->nodes[0]; | ||
146 | item = btrfs_item_ptr(leaf, path->slots[0], | ||
147 | struct btrfs_file_extent_item); | ||
148 | |||
149 | /* are we inside the extent that was found? */ | ||
150 | btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); | ||
151 | found_type = btrfs_key_type(&found_key); | ||
152 | if (found_key.objectid != inode->i_ino || | ||
153 | found_type != BTRFS_EXTENT_DATA_KEY) { | ||
154 | goto not_found; | ||
155 | } | ||
156 | |||
157 | found_type = btrfs_file_extent_type(leaf, item); | ||
158 | extent_start = found_key.offset; | ||
159 | if (found_type == BTRFS_FILE_EXTENT_REG) { | ||
160 | extent_end = extent_start + | ||
161 | btrfs_file_extent_num_bytes(leaf, item); | ||
162 | err = 0; | ||
163 | |||
164 | if (start < extent_start || start >= extent_end) | ||
165 | goto not_found; | ||
166 | |||
167 | cow_end = min(end, extent_end - 1); | ||
168 | bytenr = btrfs_file_extent_disk_bytenr(leaf, item); | ||
169 | if (bytenr == 0) | ||
170 | goto not_found; | ||
171 | |||
172 | bytenr += btrfs_file_extent_offset(leaf, item); | ||
173 | if (btrfs_count_snapshots_in_path(root, path, bytenr) != 1) { | ||
174 | goto not_found; | ||
175 | } | ||
176 | |||
177 | start = extent_end; | ||
178 | } else if (found_type == BTRFS_FILE_EXTENT_INLINE) { | ||
179 | goto not_found; | ||
180 | } | ||
181 | loop: | ||
182 | if (start > end) { | ||
183 | btrfs_free_path(path); | ||
184 | return 0; | ||
185 | } | ||
186 | btrfs_release_path(root, path); | ||
187 | goto again; | ||
188 | |||
189 | not_found: | ||
190 | cow_file_range(inode, start, cow_end); | ||
191 | start = cow_end + 1; | ||
192 | goto loop; | ||
193 | } | ||
194 | |||
195 | static int run_delalloc_range(struct inode *inode, u64 start, u64 end) | ||
196 | { | ||
197 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
198 | int ret; | ||
199 | |||
200 | mutex_lock(&root->fs_info->fs_mutex); | ||
201 | if (btrfs_test_opt(root, NODATACOW)) | ||
202 | ret = run_delalloc_nocow(inode, start, end); | ||
203 | else | ||
204 | ret = cow_file_range(inode, start, end); | ||
109 | mutex_unlock(&root->fs_info->fs_mutex); | 205 | mutex_unlock(&root->fs_info->fs_mutex); |
110 | return ret; | 206 | return ret; |
111 | } | 207 | } |
@@ -1907,9 +2003,6 @@ int btrfs_commit_write(struct file *file, struct page *page, | |||
1907 | 2003 | ||
1908 | btrfs_cow_one_page(inode, page, PAGE_CACHE_SIZE); | 2004 | btrfs_cow_one_page(inode, page, PAGE_CACHE_SIZE); |
1909 | 2005 | ||
1910 | set_page_extent_mapped(page); | ||
1911 | set_page_dirty(page); | ||
1912 | |||
1913 | if (pos > inode->i_size) { | 2006 | if (pos > inode->i_size) { |
1914 | i_size_write(inode, pos); | 2007 | i_size_write(inode, pos); |
1915 | mark_inode_dirty(inode); | 2008 | mark_inode_dirty(inode); |
@@ -2078,13 +2171,18 @@ static int create_snapshot(struct btrfs_root *root, char *name, int namelen) | |||
2078 | key.objectid = objectid; | 2171 | key.objectid = objectid; |
2079 | key.offset = 1; | 2172 | key.offset = 1; |
2080 | btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); | 2173 | btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); |
2174 | |||
2081 | extent_buffer_get(root->node); | 2175 | extent_buffer_get(root->node); |
2082 | btrfs_cow_block(trans, root, root->node, NULL, 0, &tmp); | 2176 | btrfs_cow_block(trans, root, root->node, NULL, 0, &tmp); |
2083 | free_extent_buffer(tmp); | 2177 | free_extent_buffer(tmp); |
2084 | btrfs_set_root_bytenr(&new_root_item, root->node->start); | 2178 | |
2085 | btrfs_set_root_level(&new_root_item, btrfs_header_level(root->node)); | 2179 | btrfs_copy_root(trans, root, root->node, &tmp, objectid); |
2180 | |||
2181 | btrfs_set_root_bytenr(&new_root_item, tmp->start); | ||
2182 | btrfs_set_root_level(&new_root_item, btrfs_header_level(tmp)); | ||
2086 | ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key, | 2183 | ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key, |
2087 | &new_root_item); | 2184 | &new_root_item); |
2185 | free_extent_buffer(tmp); | ||
2088 | if (ret) | 2186 | if (ret) |
2089 | goto fail; | 2187 | goto fail; |
2090 | 2188 | ||
@@ -2106,10 +2204,6 @@ static int create_snapshot(struct btrfs_root *root, char *name, int namelen) | |||
2106 | 2204 | ||
2107 | if (ret) | 2205 | if (ret) |
2108 | goto fail; | 2206 | goto fail; |
2109 | |||
2110 | ret = btrfs_inc_root_ref(trans, root, objectid); | ||
2111 | if (ret) | ||
2112 | goto fail; | ||
2113 | fail: | 2207 | fail: |
2114 | nr = trans->blocks_used; | 2208 | nr = trans->blocks_used; |
2115 | err = btrfs_commit_transaction(trans, root); | 2209 | err = btrfs_commit_transaction(trans, root); |
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index ad4f280ec777..2116728d1f98 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
@@ -61,12 +61,13 @@ static void btrfs_put_super (struct super_block * sb) | |||
61 | } | 61 | } |
62 | 62 | ||
63 | enum { | 63 | enum { |
64 | Opt_subvol, Opt_nodatasum, Opt_err, | 64 | Opt_subvol, Opt_nodatasum, Opt_nodatacow, Opt_err, |
65 | }; | 65 | }; |
66 | 66 | ||
67 | static match_table_t tokens = { | 67 | static match_table_t tokens = { |
68 | {Opt_subvol, "subvol=%s"}, | 68 | {Opt_subvol, "subvol=%s"}, |
69 | {Opt_nodatasum, "nodatasum"}, | 69 | {Opt_nodatasum, "nodatasum"}, |
70 | {Opt_nodatacow, "nodatacow"}, | ||
70 | {Opt_err, NULL} | 71 | {Opt_err, NULL} |
71 | }; | 72 | }; |
72 | 73 | ||
@@ -78,12 +79,20 @@ static int parse_options (char * options, | |||
78 | struct btrfs_fs_info *info = NULL; | 79 | struct btrfs_fs_info *info = NULL; |
79 | substring_t args[MAX_OPT_ARGS]; | 80 | substring_t args[MAX_OPT_ARGS]; |
80 | 81 | ||
81 | if (root) | ||
82 | info = root->fs_info; | ||
83 | |||
84 | if (!options) | 82 | if (!options) |
85 | return 1; | 83 | return 1; |
86 | 84 | ||
85 | /* | ||
86 | * strsep changes the string, duplicate it because parse_options | ||
87 | * gets called twice | ||
88 | */ | ||
89 | options = kstrdup(options, GFP_NOFS); | ||
90 | if (!options) | ||
91 | return -ENOMEM; | ||
92 | |||
93 | if (root) | ||
94 | info = root->fs_info; | ||
95 | |||
87 | while ((p = strsep (&options, ",")) != NULL) { | 96 | while ((p = strsep (&options, ",")) != NULL) { |
88 | int token; | 97 | int token; |
89 | if (!*p) | 98 | if (!*p) |
@@ -92,17 +101,28 @@ static int parse_options (char * options, | |||
92 | token = match_token(p, tokens, args); | 101 | token = match_token(p, tokens, args); |
93 | switch (token) { | 102 | switch (token) { |
94 | case Opt_subvol: | 103 | case Opt_subvol: |
95 | if (subvol_name) | 104 | if (subvol_name) { |
96 | *subvol_name = match_strdup(&args[0]); | 105 | *subvol_name = match_strdup(&args[0]); |
106 | } | ||
97 | break; | 107 | break; |
98 | case Opt_nodatasum: | 108 | case Opt_nodatasum: |
99 | if (root) | 109 | if (info) { |
110 | printk("btrfs: setting nodatacsum\n"); | ||
100 | btrfs_set_opt(info->mount_opt, NODATASUM); | 111 | btrfs_set_opt(info->mount_opt, NODATASUM); |
112 | } | ||
113 | break; | ||
114 | case Opt_nodatacow: | ||
115 | if (info) { | ||
116 | printk("btrfs: setting nodatacow\n"); | ||
117 | btrfs_set_opt(info->mount_opt, NODATACOW); | ||
118 | btrfs_set_opt(info->mount_opt, NODATASUM); | ||
119 | } | ||
101 | break; | 120 | break; |
102 | default: | 121 | default: |
103 | return 0; | 122 | break; |
104 | } | 123 | } |
105 | } | 124 | } |
125 | kfree(options); | ||
106 | return 1; | 126 | return 1; |
107 | } | 127 | } |
108 | 128 | ||