diff options
-rw-r--r-- | fs/btrfs/ctree.h | 50 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 8 | ||||
-rw-r--r-- | fs/btrfs/inode-map.c | 2 | ||||
-rw-r--r-- | fs/btrfs/super.c | 18 | ||||
-rw-r--r-- | fs/btrfs/sysfs.c | 34 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 38 | ||||
-rw-r--r-- | fs/btrfs/transaction.h | 2 |
7 files changed, 115 insertions, 37 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 49d956b2cf30..9918ba3ec2b2 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -1407,6 +1407,11 @@ struct btrfs_fs_info { | |||
1407 | */ | 1407 | */ |
1408 | u64 last_trans_log_full_commit; | 1408 | u64 last_trans_log_full_commit; |
1409 | unsigned long mount_opt; | 1409 | unsigned long mount_opt; |
1410 | /* | ||
1411 | * Track requests for actions that need to be done during transaction | ||
1412 | * commit (like for some mount options). | ||
1413 | */ | ||
1414 | unsigned long pending_changes; | ||
1410 | unsigned long compress_type:4; | 1415 | unsigned long compress_type:4; |
1411 | int commit_interval; | 1416 | int commit_interval; |
1412 | /* | 1417 | /* |
@@ -2098,7 +2103,6 @@ struct btrfs_ioctl_defrag_range_args { | |||
2098 | #define BTRFS_MOUNT_CHECK_INTEGRITY_INCLUDING_EXTENT_DATA (1 << 21) | 2103 | #define BTRFS_MOUNT_CHECK_INTEGRITY_INCLUDING_EXTENT_DATA (1 << 21) |
2099 | #define BTRFS_MOUNT_PANIC_ON_FATAL_ERROR (1 << 22) | 2104 | #define BTRFS_MOUNT_PANIC_ON_FATAL_ERROR (1 << 22) |
2100 | #define BTRFS_MOUNT_RESCAN_UUID_TREE (1 << 23) | 2105 | #define BTRFS_MOUNT_RESCAN_UUID_TREE (1 << 23) |
2101 | #define BTRFS_MOUNT_CHANGE_INODE_CACHE (1 << 24) | ||
2102 | 2106 | ||
2103 | #define BTRFS_DEFAULT_COMMIT_INTERVAL (30) | 2107 | #define BTRFS_DEFAULT_COMMIT_INTERVAL (30) |
2104 | #define BTRFS_DEFAULT_MAX_INLINE (8192) | 2108 | #define BTRFS_DEFAULT_MAX_INLINE (8192) |
@@ -2108,6 +2112,7 @@ struct btrfs_ioctl_defrag_range_args { | |||
2108 | #define btrfs_raw_test_opt(o, opt) ((o) & BTRFS_MOUNT_##opt) | 2112 | #define btrfs_raw_test_opt(o, opt) ((o) & BTRFS_MOUNT_##opt) |
2109 | #define btrfs_test_opt(root, opt) ((root)->fs_info->mount_opt & \ | 2113 | #define btrfs_test_opt(root, opt) ((root)->fs_info->mount_opt & \ |
2110 | BTRFS_MOUNT_##opt) | 2114 | BTRFS_MOUNT_##opt) |
2115 | |||
2111 | #define btrfs_set_and_info(root, opt, fmt, args...) \ | 2116 | #define btrfs_set_and_info(root, opt, fmt, args...) \ |
2112 | { \ | 2117 | { \ |
2113 | if (!btrfs_test_opt(root, opt)) \ | 2118 | if (!btrfs_test_opt(root, opt)) \ |
@@ -2123,6 +2128,49 @@ struct btrfs_ioctl_defrag_range_args { | |||
2123 | } | 2128 | } |
2124 | 2129 | ||
2125 | /* | 2130 | /* |
2131 | * Requests for changes that need to be done during transaction commit. | ||
2132 | * | ||
2133 | * Internal mount options that are used for special handling of the real | ||
2134 | * mount options (eg. cannot be set during remount and have to be set during | ||
2135 | * transaction commit) | ||
2136 | */ | ||
2137 | |||
2138 | #define BTRFS_PENDING_SET_INODE_MAP_CACHE (0) | ||
2139 | #define BTRFS_PENDING_CLEAR_INODE_MAP_CACHE (1) | ||
2140 | #define BTRFS_PENDING_COMMIT (2) | ||
2141 | |||
2142 | #define btrfs_test_pending(info, opt) \ | ||
2143 | test_bit(BTRFS_PENDING_##opt, &(info)->pending_changes) | ||
2144 | #define btrfs_set_pending(info, opt) \ | ||
2145 | set_bit(BTRFS_PENDING_##opt, &(info)->pending_changes) | ||
2146 | #define btrfs_clear_pending(info, opt) \ | ||
2147 | clear_bit(BTRFS_PENDING_##opt, &(info)->pending_changes) | ||
2148 | |||
2149 | /* | ||
2150 | * Helpers for setting pending mount option changes. | ||
2151 | * | ||
2152 | * Expects corresponding macros | ||
2153 | * BTRFS_PENDING_SET_ and CLEAR_ + short mount option name | ||
2154 | */ | ||
2155 | #define btrfs_set_pending_and_info(info, opt, fmt, args...) \ | ||
2156 | do { \ | ||
2157 | if (!btrfs_raw_test_opt((info)->mount_opt, opt)) { \ | ||
2158 | btrfs_info((info), fmt, ##args); \ | ||
2159 | btrfs_set_pending((info), SET_##opt); \ | ||
2160 | btrfs_clear_pending((info), CLEAR_##opt); \ | ||
2161 | } \ | ||
2162 | } while(0) | ||
2163 | |||
2164 | #define btrfs_clear_pending_and_info(info, opt, fmt, args...) \ | ||
2165 | do { \ | ||
2166 | if (btrfs_raw_test_opt((info)->mount_opt, opt)) { \ | ||
2167 | btrfs_info((info), fmt, ##args); \ | ||
2168 | btrfs_set_pending((info), CLEAR_##opt); \ | ||
2169 | btrfs_clear_pending((info), SET_##opt); \ | ||
2170 | } \ | ||
2171 | } while(0) | ||
2172 | |||
2173 | /* | ||
2126 | * Inode flags | 2174 | * Inode flags |
2127 | */ | 2175 | */ |
2128 | #define BTRFS_INODE_NODATASUM (1 << 0) | 2176 | #define BTRFS_INODE_NODATASUM (1 << 0) |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 6efaee8d7739..1e3e414c8501 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -2830,9 +2830,11 @@ retry_root_backup: | |||
2830 | btrfs_set_opt(fs_info->mount_opt, SSD); | 2830 | btrfs_set_opt(fs_info->mount_opt, SSD); |
2831 | } | 2831 | } |
2832 | 2832 | ||
2833 | /* Set the real inode map cache flag */ | 2833 | /* |
2834 | if (btrfs_test_opt(tree_root, CHANGE_INODE_CACHE)) | 2834 | * Mount does not set all options immediatelly, we can do it now and do |
2835 | btrfs_set_opt(tree_root->fs_info->mount_opt, INODE_MAP_CACHE); | 2835 | * not have to wait for transaction commit |
2836 | */ | ||
2837 | btrfs_apply_pending_changes(fs_info); | ||
2836 | 2838 | ||
2837 | #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY | 2839 | #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY |
2838 | if (btrfs_test_opt(tree_root, CHECK_INTEGRITY)) { | 2840 | if (btrfs_test_opt(tree_root, CHECK_INTEGRITY)) { |
diff --git a/fs/btrfs/inode-map.c b/fs/btrfs/inode-map.c index 83d646bd2e4b..4ebd5ebb1ea1 100644 --- a/fs/btrfs/inode-map.c +++ b/fs/btrfs/inode-map.c | |||
@@ -178,7 +178,7 @@ static void start_caching(struct btrfs_root *root) | |||
178 | root->root_key.objectid); | 178 | root->root_key.objectid); |
179 | if (IS_ERR(tsk)) { | 179 | if (IS_ERR(tsk)) { |
180 | btrfs_warn(root->fs_info, "failed to start inode caching task"); | 180 | btrfs_warn(root->fs_info, "failed to start inode caching task"); |
181 | btrfs_clear_and_info(root, CHANGE_INODE_CACHE, | 181 | btrfs_clear_pending_and_info(root->fs_info, INODE_MAP_CACHE, |
182 | "disabling inode map caching"); | 182 | "disabling inode map caching"); |
183 | } | 183 | } |
184 | } | 184 | } |
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 21c60ee2f664..391ec4418460 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
@@ -642,11 +642,11 @@ int btrfs_parse_options(struct btrfs_root *root, char *options) | |||
642 | "disabling disk space caching"); | 642 | "disabling disk space caching"); |
643 | break; | 643 | break; |
644 | case Opt_inode_cache: | 644 | case Opt_inode_cache: |
645 | btrfs_set_and_info(root, CHANGE_INODE_CACHE, | 645 | btrfs_set_pending_and_info(info, INODE_MAP_CACHE, |
646 | "enabling inode map caching"); | 646 | "enabling inode map caching"); |
647 | break; | 647 | break; |
648 | case Opt_noinode_cache: | 648 | case Opt_noinode_cache: |
649 | btrfs_clear_and_info(root, CHANGE_INODE_CACHE, | 649 | btrfs_clear_pending_and_info(info, INODE_MAP_CACHE, |
650 | "disabling inode map caching"); | 650 | "disabling inode map caching"); |
651 | break; | 651 | break; |
652 | case Opt_clear_cache: | 652 | case Opt_clear_cache: |
@@ -993,9 +993,17 @@ int btrfs_sync_fs(struct super_block *sb, int wait) | |||
993 | trans = btrfs_attach_transaction_barrier(root); | 993 | trans = btrfs_attach_transaction_barrier(root); |
994 | if (IS_ERR(trans)) { | 994 | if (IS_ERR(trans)) { |
995 | /* no transaction, don't bother */ | 995 | /* no transaction, don't bother */ |
996 | if (PTR_ERR(trans) == -ENOENT) | 996 | if (PTR_ERR(trans) == -ENOENT) { |
997 | return 0; | 997 | /* |
998 | return PTR_ERR(trans); | 998 | * Exit unless we have some pending changes |
999 | * that need to go through commit | ||
1000 | */ | ||
1001 | if (fs_info->pending_changes == 0) | ||
1002 | return 0; | ||
1003 | trans = btrfs_start_transaction(root, 0); | ||
1004 | } else { | ||
1005 | return PTR_ERR(trans); | ||
1006 | } | ||
999 | } | 1007 | } |
1000 | return btrfs_commit_transaction(trans, root); | 1008 | return btrfs_commit_transaction(trans, root); |
1001 | } | 1009 | } |
diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c index b2e7bb4393f6..92db3f648df4 100644 --- a/fs/btrfs/sysfs.c +++ b/fs/btrfs/sysfs.c | |||
@@ -111,7 +111,6 @@ static ssize_t btrfs_feature_attr_store(struct kobject *kobj, | |||
111 | { | 111 | { |
112 | struct btrfs_fs_info *fs_info; | 112 | struct btrfs_fs_info *fs_info; |
113 | struct btrfs_feature_attr *fa = to_btrfs_feature_attr(a); | 113 | struct btrfs_feature_attr *fa = to_btrfs_feature_attr(a); |
114 | struct btrfs_trans_handle *trans; | ||
115 | u64 features, set, clear; | 114 | u64 features, set, clear; |
116 | unsigned long val; | 115 | unsigned long val; |
117 | int ret; | 116 | int ret; |
@@ -153,10 +152,6 @@ static ssize_t btrfs_feature_attr_store(struct kobject *kobj, | |||
153 | btrfs_info(fs_info, "%s %s feature flag", | 152 | btrfs_info(fs_info, "%s %s feature flag", |
154 | val ? "Setting" : "Clearing", fa->kobj_attr.attr.name); | 153 | val ? "Setting" : "Clearing", fa->kobj_attr.attr.name); |
155 | 154 | ||
156 | trans = btrfs_start_transaction(fs_info->fs_root, 0); | ||
157 | if (IS_ERR(trans)) | ||
158 | return PTR_ERR(trans); | ||
159 | |||
160 | spin_lock(&fs_info->super_lock); | 155 | spin_lock(&fs_info->super_lock); |
161 | features = get_features(fs_info, fa->feature_set); | 156 | features = get_features(fs_info, fa->feature_set); |
162 | if (val) | 157 | if (val) |
@@ -166,9 +161,11 @@ static ssize_t btrfs_feature_attr_store(struct kobject *kobj, | |||
166 | set_features(fs_info, fa->feature_set, features); | 161 | set_features(fs_info, fa->feature_set, features); |
167 | spin_unlock(&fs_info->super_lock); | 162 | spin_unlock(&fs_info->super_lock); |
168 | 163 | ||
169 | ret = btrfs_commit_transaction(trans, fs_info->fs_root); | 164 | /* |
170 | if (ret) | 165 | * We don't want to do full transaction commit from inside sysfs |
171 | return ret; | 166 | */ |
167 | btrfs_set_pending(fs_info, COMMIT); | ||
168 | wake_up_process(fs_info->transaction_kthread); | ||
172 | 169 | ||
173 | return count; | 170 | return count; |
174 | } | 171 | } |
@@ -372,9 +369,6 @@ static ssize_t btrfs_label_store(struct kobject *kobj, | |||
372 | const char *buf, size_t len) | 369 | const char *buf, size_t len) |
373 | { | 370 | { |
374 | struct btrfs_fs_info *fs_info = to_fs_info(kobj); | 371 | struct btrfs_fs_info *fs_info = to_fs_info(kobj); |
375 | struct btrfs_trans_handle *trans; | ||
376 | struct btrfs_root *root = fs_info->fs_root; | ||
377 | int ret; | ||
378 | size_t p_len; | 372 | size_t p_len; |
379 | 373 | ||
380 | if (fs_info->sb->s_flags & MS_RDONLY) | 374 | if (fs_info->sb->s_flags & MS_RDONLY) |
@@ -389,20 +383,18 @@ static ssize_t btrfs_label_store(struct kobject *kobj, | |||
389 | if (p_len >= BTRFS_LABEL_SIZE) | 383 | if (p_len >= BTRFS_LABEL_SIZE) |
390 | return -EINVAL; | 384 | return -EINVAL; |
391 | 385 | ||
392 | trans = btrfs_start_transaction(root, 0); | 386 | spin_lock(&fs_info->super_lock); |
393 | if (IS_ERR(trans)) | ||
394 | return PTR_ERR(trans); | ||
395 | |||
396 | spin_lock(&root->fs_info->super_lock); | ||
397 | memset(fs_info->super_copy->label, 0, BTRFS_LABEL_SIZE); | 387 | memset(fs_info->super_copy->label, 0, BTRFS_LABEL_SIZE); |
398 | memcpy(fs_info->super_copy->label, buf, p_len); | 388 | memcpy(fs_info->super_copy->label, buf, p_len); |
399 | spin_unlock(&root->fs_info->super_lock); | 389 | spin_unlock(&fs_info->super_lock); |
400 | ret = btrfs_commit_transaction(trans, root); | ||
401 | 390 | ||
402 | if (!ret) | 391 | /* |
403 | return len; | 392 | * We don't want to do full transaction commit from inside sysfs |
393 | */ | ||
394 | btrfs_set_pending(fs_info, COMMIT); | ||
395 | wake_up_process(fs_info->transaction_kthread); | ||
404 | 396 | ||
405 | return ret; | 397 | return len; |
406 | } | 398 | } |
407 | BTRFS_ATTR_RW(label, btrfs_label_show, btrfs_label_store); | 399 | BTRFS_ATTR_RW(label, btrfs_label_show, btrfs_label_store); |
408 | 400 | ||
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 295a135c9c24..a605d4e2f2bc 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -1938,13 +1938,10 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1938 | } | 1938 | } |
1939 | 1939 | ||
1940 | /* | 1940 | /* |
1941 | * Since the transaction is done, we should set the inode map cache flag | 1941 | * Since the transaction is done, we can apply the pending changes |
1942 | * before any other comming transaction. | 1942 | * before the next transaction. |
1943 | */ | 1943 | */ |
1944 | if (btrfs_test_opt(root, CHANGE_INODE_CACHE)) | 1944 | btrfs_apply_pending_changes(root->fs_info); |
1945 | btrfs_set_opt(root->fs_info->mount_opt, INODE_MAP_CACHE); | ||
1946 | else | ||
1947 | btrfs_clear_opt(root->fs_info->mount_opt, INODE_MAP_CACHE); | ||
1948 | 1945 | ||
1949 | /* commit_fs_roots gets rid of all the tree log roots, it is now | 1946 | /* commit_fs_roots gets rid of all the tree log roots, it is now |
1950 | * safe to free the root of tree log roots | 1947 | * safe to free the root of tree log roots |
@@ -2115,3 +2112,32 @@ int btrfs_clean_one_deleted_snapshot(struct btrfs_root *root) | |||
2115 | 2112 | ||
2116 | return (ret < 0) ? 0 : 1; | 2113 | return (ret < 0) ? 0 : 1; |
2117 | } | 2114 | } |
2115 | |||
2116 | void btrfs_apply_pending_changes(struct btrfs_fs_info *fs_info) | ||
2117 | { | ||
2118 | unsigned long prev; | ||
2119 | unsigned long bit; | ||
2120 | |||
2121 | prev = cmpxchg(&fs_info->pending_changes, 0, 0); | ||
2122 | if (!prev) | ||
2123 | return; | ||
2124 | |||
2125 | bit = 1 << BTRFS_PENDING_SET_INODE_MAP_CACHE; | ||
2126 | if (prev & bit) | ||
2127 | btrfs_set_opt(fs_info->mount_opt, INODE_MAP_CACHE); | ||
2128 | prev &= ~bit; | ||
2129 | |||
2130 | bit = 1 << BTRFS_PENDING_CLEAR_INODE_MAP_CACHE; | ||
2131 | if (prev & bit) | ||
2132 | btrfs_clear_opt(fs_info->mount_opt, INODE_MAP_CACHE); | ||
2133 | prev &= ~bit; | ||
2134 | |||
2135 | bit = 1 << BTRFS_PENDING_COMMIT; | ||
2136 | if (prev & bit) | ||
2137 | btrfs_debug(fs_info, "pending commit done"); | ||
2138 | prev &= ~bit; | ||
2139 | |||
2140 | if (prev) | ||
2141 | btrfs_warn(fs_info, | ||
2142 | "unknown pending changes left 0x%lx, ignoring", prev); | ||
2143 | } | ||
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h index fd400a3668a8..00ed29c4b3f9 100644 --- a/fs/btrfs/transaction.h +++ b/fs/btrfs/transaction.h | |||
@@ -170,4 +170,6 @@ int btrfs_wait_marked_extents(struct btrfs_root *root, | |||
170 | int btrfs_transaction_blocked(struct btrfs_fs_info *info); | 170 | int btrfs_transaction_blocked(struct btrfs_fs_info *info); |
171 | int btrfs_transaction_in_commit(struct btrfs_fs_info *info); | 171 | int btrfs_transaction_in_commit(struct btrfs_fs_info *info); |
172 | void btrfs_put_transaction(struct btrfs_transaction *transaction); | 172 | void btrfs_put_transaction(struct btrfs_transaction *transaction); |
173 | void btrfs_apply_pending_changes(struct btrfs_fs_info *fs_info); | ||
174 | |||
173 | #endif | 175 | #endif |