aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Sterba <dsterba@suse.cz>2014-02-05 09:26:17 -0500
committerDavid Sterba <dsterba@suse.cz>2014-11-12 10:53:12 -0500
commit572d9ab7845ea0e043ec34cd733a75228130ad03 (patch)
tree0dcf250edd2859e3dd64b0b33f9694c3fd61c29b
parent206c5f60a3d902bc4b56dab2de3e88de5eb06108 (diff)
btrfs: add support for processing pending changes
There are some actions that modify global filesystem state but cannot be performed at the time of request, but later at the transaction commit time when the filesystem is in a known state. For example enabling new incompat features on-the-fly or issuing transaction commit from unsafe contexts (sysfs handlers). Signed-off-by: David Sterba <dsterba@suse.cz>
-rw-r--r--fs/btrfs/ctree.h45
-rw-r--r--fs/btrfs/disk-io.c6
-rw-r--r--fs/btrfs/transaction.c16
-rw-r--r--fs/btrfs/transaction.h2
4 files changed, 69 insertions, 0 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index fe69edda11fb..f30b061ef77d 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -1402,6 +1402,11 @@ struct btrfs_fs_info {
1402 */ 1402 */
1403 u64 last_trans_log_full_commit; 1403 u64 last_trans_log_full_commit;
1404 unsigned long mount_opt; 1404 unsigned long mount_opt;
1405 /*
1406 * Track requests for actions that need to be done during transaction
1407 * commit (like for some mount options).
1408 */
1409 unsigned long pending_changes;
1405 unsigned long compress_type:4; 1410 unsigned long compress_type:4;
1406 int commit_interval; 1411 int commit_interval;
1407 /* 1412 /*
@@ -2103,6 +2108,7 @@ struct btrfs_ioctl_defrag_range_args {
2103#define btrfs_raw_test_opt(o, opt) ((o) & BTRFS_MOUNT_##opt) 2108#define btrfs_raw_test_opt(o, opt) ((o) & BTRFS_MOUNT_##opt)
2104#define btrfs_test_opt(root, opt) ((root)->fs_info->mount_opt & \ 2109#define btrfs_test_opt(root, opt) ((root)->fs_info->mount_opt & \
2105 BTRFS_MOUNT_##opt) 2110 BTRFS_MOUNT_##opt)
2111
2106#define btrfs_set_and_info(root, opt, fmt, args...) \ 2112#define btrfs_set_and_info(root, opt, fmt, args...) \
2107{ \ 2113{ \
2108 if (!btrfs_test_opt(root, opt)) \ 2114 if (!btrfs_test_opt(root, opt)) \
@@ -2118,6 +2124,45 @@ struct btrfs_ioctl_defrag_range_args {
2118} 2124}
2119 2125
2120/* 2126/*
2127 * Requests for changes that need to be done during transaction commit.
2128 *
2129 * Internal mount options that are used for special handling of the real
2130 * mount options (eg. cannot be set during remount and have to be set during
2131 * transaction commit)
2132 */
2133
2134#define btrfs_test_pending(info, opt) \
2135 test_bit(BTRFS_PENDING_##opt, &(info)->pending_changes)
2136#define btrfs_set_pending(info, opt) \
2137 set_bit(BTRFS_PENDING_##opt, &(info)->pending_changes)
2138#define btrfs_clear_pending(info, opt) \
2139 clear_bit(BTRFS_PENDING_##opt, &(info)->pending_changes)
2140
2141/*
2142 * Helpers for setting pending mount option changes.
2143 *
2144 * Expects corresponding macros
2145 * BTRFS_PENDING_SET_ and CLEAR_ + short mount option name
2146 */
2147#define btrfs_set_pending_and_info(info, opt, fmt, args...) \
2148do { \
2149 if (!btrfs_raw_test_opt((info)->mount_opt, opt)) { \
2150 btrfs_info((info), fmt, ##args); \
2151 btrfs_set_pending((info), SET_##opt); \
2152 btrfs_clear_pending((info), CLEAR_##opt); \
2153 } \
2154} while(0)
2155
2156#define btrfs_clear_pending_and_info(info, opt, fmt, args...) \
2157do { \
2158 if (btrfs_raw_test_opt((info)->mount_opt, opt)) { \
2159 btrfs_info((info), fmt, ##args); \
2160 btrfs_set_pending((info), CLEAR_##opt); \
2161 btrfs_clear_pending((info), SET_##opt); \
2162 } \
2163} while(0)
2164
2165/*
2121 * Inode flags 2166 * Inode flags
2122 */ 2167 */
2123#define BTRFS_INODE_NODATASUM (1 << 0) 2168#define BTRFS_INODE_NODATASUM (1 << 0)
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 1bf9f897065d..fd80c0d98421 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -2834,6 +2834,12 @@ retry_root_backup:
2834 if (btrfs_test_opt(tree_root, CHANGE_INODE_CACHE)) 2834 if (btrfs_test_opt(tree_root, CHANGE_INODE_CACHE))
2835 btrfs_set_opt(tree_root->fs_info->mount_opt, INODE_MAP_CACHE); 2835 btrfs_set_opt(tree_root->fs_info->mount_opt, INODE_MAP_CACHE);
2836 2836
2837 /*
2838 * Mount does not set all options immediatelly, we can do it now and do
2839 * not have to wait for transaction commit
2840 */
2841 btrfs_apply_pending_changes(fs_info);
2842
2837#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY 2843#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
2838 if (btrfs_test_opt(tree_root, CHECK_INTEGRITY)) { 2844 if (btrfs_test_opt(tree_root, CHECK_INTEGRITY)) {
2839 ret = btrfsic_mount(tree_root, fs_devices, 2845 ret = btrfsic_mount(tree_root, fs_devices,
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index dcaae3616728..7a4024a55e5c 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -1850,6 +1850,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
1850 else 1850 else
1851 btrfs_clear_opt(root->fs_info->mount_opt, INODE_MAP_CACHE); 1851 btrfs_clear_opt(root->fs_info->mount_opt, INODE_MAP_CACHE);
1852 1852
1853 btrfs_apply_pending_changes(root->fs_info);
1854
1853 /* commit_fs_roots gets rid of all the tree log roots, it is now 1855 /* commit_fs_roots gets rid of all the tree log roots, it is now
1854 * safe to free the root of tree log roots 1856 * safe to free the root of tree log roots
1855 */ 1857 */
@@ -2019,3 +2021,17 @@ int btrfs_clean_one_deleted_snapshot(struct btrfs_root *root)
2019 2021
2020 return (ret < 0) ? 0 : 1; 2022 return (ret < 0) ? 0 : 1;
2021} 2023}
2024
2025void btrfs_apply_pending_changes(struct btrfs_fs_info *fs_info)
2026{
2027 unsigned long prev;
2028 unsigned long bit;
2029
2030 prev = cmpxchg(&fs_info->pending_changes, 0, 0);
2031 if (!prev)
2032 return;
2033
2034 if (prev)
2035 btrfs_warn(fs_info,
2036 "unknown pending changes left 0x%lx, ignoring", prev);
2037}
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h
index d8f40e1a5d2d..75ebcfce9d57 100644
--- a/fs/btrfs/transaction.h
+++ b/fs/btrfs/transaction.h
@@ -170,4 +170,6 @@ int btrfs_wait_marked_extents(struct btrfs_root *root,
170int btrfs_transaction_blocked(struct btrfs_fs_info *info); 170int btrfs_transaction_blocked(struct btrfs_fs_info *info);
171int btrfs_transaction_in_commit(struct btrfs_fs_info *info); 171int btrfs_transaction_in_commit(struct btrfs_fs_info *info);
172void btrfs_put_transaction(struct btrfs_transaction *transaction); 172void btrfs_put_transaction(struct btrfs_transaction *transaction);
173void btrfs_apply_pending_changes(struct btrfs_fs_info *fs_info);
174
173#endif 175#endif