Commit ad27c0da authored by Chris Mason's avatar Chris Mason

Merge branch 'dev/pending-changes' of...

Merge branch 'dev/pending-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux into for-linus
parents b38ef71c a6f69dc8
...@@ -1407,6 +1407,11 @@ struct btrfs_fs_info { ...@@ -1407,6 +1407,11 @@ struct btrfs_fs_info {
*/ */
u64 last_trans_log_full_commit; u64 last_trans_log_full_commit;
unsigned long mount_opt; unsigned long mount_opt;
/*
* Track requests for actions that need to be done during transaction
* commit (like for some mount options).
*/
unsigned long pending_changes;
unsigned long compress_type:4; unsigned long compress_type:4;
int commit_interval; int commit_interval;
/* /*
...@@ -2098,7 +2103,6 @@ struct btrfs_ioctl_defrag_range_args { ...@@ -2098,7 +2103,6 @@ struct btrfs_ioctl_defrag_range_args {
#define BTRFS_MOUNT_CHECK_INTEGRITY_INCLUDING_EXTENT_DATA (1 << 21) #define BTRFS_MOUNT_CHECK_INTEGRITY_INCLUDING_EXTENT_DATA (1 << 21)
#define BTRFS_MOUNT_PANIC_ON_FATAL_ERROR (1 << 22) #define BTRFS_MOUNT_PANIC_ON_FATAL_ERROR (1 << 22)
#define BTRFS_MOUNT_RESCAN_UUID_TREE (1 << 23) #define BTRFS_MOUNT_RESCAN_UUID_TREE (1 << 23)
#define BTRFS_MOUNT_CHANGE_INODE_CACHE (1 << 24)
#define BTRFS_DEFAULT_COMMIT_INTERVAL (30) #define BTRFS_DEFAULT_COMMIT_INTERVAL (30)
#define BTRFS_DEFAULT_MAX_INLINE (8192) #define BTRFS_DEFAULT_MAX_INLINE (8192)
...@@ -2108,6 +2112,7 @@ struct btrfs_ioctl_defrag_range_args { ...@@ -2108,6 +2112,7 @@ struct btrfs_ioctl_defrag_range_args {
#define btrfs_raw_test_opt(o, opt) ((o) & BTRFS_MOUNT_##opt) #define btrfs_raw_test_opt(o, opt) ((o) & BTRFS_MOUNT_##opt)
#define btrfs_test_opt(root, opt) ((root)->fs_info->mount_opt & \ #define btrfs_test_opt(root, opt) ((root)->fs_info->mount_opt & \
BTRFS_MOUNT_##opt) BTRFS_MOUNT_##opt)
#define btrfs_set_and_info(root, opt, fmt, args...) \ #define btrfs_set_and_info(root, opt, fmt, args...) \
{ \ { \
if (!btrfs_test_opt(root, opt)) \ if (!btrfs_test_opt(root, opt)) \
...@@ -2122,6 +2127,49 @@ struct btrfs_ioctl_defrag_range_args { ...@@ -2122,6 +2127,49 @@ struct btrfs_ioctl_defrag_range_args {
btrfs_clear_opt(root->fs_info->mount_opt, opt); \ btrfs_clear_opt(root->fs_info->mount_opt, opt); \
} }
/*
* Requests for changes that need to be done during transaction commit.
*
* Internal mount options that are used for special handling of the real
* mount options (eg. cannot be set during remount and have to be set during
* transaction commit)
*/
#define BTRFS_PENDING_SET_INODE_MAP_CACHE (0)
#define BTRFS_PENDING_CLEAR_INODE_MAP_CACHE (1)
#define BTRFS_PENDING_COMMIT (2)
#define btrfs_test_pending(info, opt) \
test_bit(BTRFS_PENDING_##opt, &(info)->pending_changes)
#define btrfs_set_pending(info, opt) \
set_bit(BTRFS_PENDING_##opt, &(info)->pending_changes)
#define btrfs_clear_pending(info, opt) \
clear_bit(BTRFS_PENDING_##opt, &(info)->pending_changes)
/*
* Helpers for setting pending mount option changes.
*
* Expects corresponding macros
* BTRFS_PENDING_SET_ and CLEAR_ + short mount option name
*/
#define btrfs_set_pending_and_info(info, opt, fmt, args...) \
do { \
if (!btrfs_raw_test_opt((info)->mount_opt, opt)) { \
btrfs_info((info), fmt, ##args); \
btrfs_set_pending((info), SET_##opt); \
btrfs_clear_pending((info), CLEAR_##opt); \
} \
} while(0)
#define btrfs_clear_pending_and_info(info, opt, fmt, args...) \
do { \
if (btrfs_raw_test_opt((info)->mount_opt, opt)) { \
btrfs_info((info), fmt, ##args); \
btrfs_set_pending((info), CLEAR_##opt); \
btrfs_clear_pending((info), SET_##opt); \
} \
} while(0)
/* /*
* Inode flags * Inode flags
*/ */
......
...@@ -2830,9 +2830,11 @@ int open_ctree(struct super_block *sb, ...@@ -2830,9 +2830,11 @@ int open_ctree(struct super_block *sb,
btrfs_set_opt(fs_info->mount_opt, SSD); btrfs_set_opt(fs_info->mount_opt, SSD);
} }
/* Set the real inode map cache flag */ /*
if (btrfs_test_opt(tree_root, CHANGE_INODE_CACHE)) * Mount does not set all options immediatelly, we can do it now and do
btrfs_set_opt(tree_root->fs_info->mount_opt, INODE_MAP_CACHE); * not have to wait for transaction commit
*/
btrfs_apply_pending_changes(fs_info);
#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
if (btrfs_test_opt(tree_root, CHECK_INTEGRITY)) { if (btrfs_test_opt(tree_root, CHECK_INTEGRITY)) {
......
...@@ -178,7 +178,7 @@ static void start_caching(struct btrfs_root *root) ...@@ -178,7 +178,7 @@ static void start_caching(struct btrfs_root *root)
root->root_key.objectid); root->root_key.objectid);
if (IS_ERR(tsk)) { if (IS_ERR(tsk)) {
btrfs_warn(root->fs_info, "failed to start inode caching task"); btrfs_warn(root->fs_info, "failed to start inode caching task");
btrfs_clear_and_info(root, CHANGE_INODE_CACHE, btrfs_clear_pending_and_info(root->fs_info, INODE_MAP_CACHE,
"disabling inode map caching"); "disabling inode map caching");
} }
} }
......
...@@ -642,11 +642,11 @@ int btrfs_parse_options(struct btrfs_root *root, char *options) ...@@ -642,11 +642,11 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
"disabling disk space caching"); "disabling disk space caching");
break; break;
case Opt_inode_cache: case Opt_inode_cache:
btrfs_set_and_info(root, CHANGE_INODE_CACHE, btrfs_set_pending_and_info(info, INODE_MAP_CACHE,
"enabling inode map caching"); "enabling inode map caching");
break; break;
case Opt_noinode_cache: case Opt_noinode_cache:
btrfs_clear_and_info(root, CHANGE_INODE_CACHE, btrfs_clear_pending_and_info(info, INODE_MAP_CACHE,
"disabling inode map caching"); "disabling inode map caching");
break; break;
case Opt_clear_cache: case Opt_clear_cache:
...@@ -993,10 +993,18 @@ int btrfs_sync_fs(struct super_block *sb, int wait) ...@@ -993,10 +993,18 @@ int btrfs_sync_fs(struct super_block *sb, int wait)
trans = btrfs_attach_transaction_barrier(root); trans = btrfs_attach_transaction_barrier(root);
if (IS_ERR(trans)) { if (IS_ERR(trans)) {
/* no transaction, don't bother */ /* no transaction, don't bother */
if (PTR_ERR(trans) == -ENOENT) if (PTR_ERR(trans) == -ENOENT) {
/*
* Exit unless we have some pending changes
* that need to go through commit
*/
if (fs_info->pending_changes == 0)
return 0; return 0;
trans = btrfs_start_transaction(root, 0);
} else {
return PTR_ERR(trans); return PTR_ERR(trans);
} }
}
return btrfs_commit_transaction(trans, root); return btrfs_commit_transaction(trans, root);
} }
......
...@@ -111,7 +111,6 @@ static ssize_t btrfs_feature_attr_store(struct kobject *kobj, ...@@ -111,7 +111,6 @@ static ssize_t btrfs_feature_attr_store(struct kobject *kobj,
{ {
struct btrfs_fs_info *fs_info; struct btrfs_fs_info *fs_info;
struct btrfs_feature_attr *fa = to_btrfs_feature_attr(a); struct btrfs_feature_attr *fa = to_btrfs_feature_attr(a);
struct btrfs_trans_handle *trans;
u64 features, set, clear; u64 features, set, clear;
unsigned long val; unsigned long val;
int ret; int ret;
...@@ -153,10 +152,6 @@ static ssize_t btrfs_feature_attr_store(struct kobject *kobj, ...@@ -153,10 +152,6 @@ static ssize_t btrfs_feature_attr_store(struct kobject *kobj,
btrfs_info(fs_info, "%s %s feature flag", btrfs_info(fs_info, "%s %s feature flag",
val ? "Setting" : "Clearing", fa->kobj_attr.attr.name); val ? "Setting" : "Clearing", fa->kobj_attr.attr.name);
trans = btrfs_start_transaction(fs_info->fs_root, 0);
if (IS_ERR(trans))
return PTR_ERR(trans);
spin_lock(&fs_info->super_lock); spin_lock(&fs_info->super_lock);
features = get_features(fs_info, fa->feature_set); features = get_features(fs_info, fa->feature_set);
if (val) if (val)
...@@ -166,9 +161,11 @@ static ssize_t btrfs_feature_attr_store(struct kobject *kobj, ...@@ -166,9 +161,11 @@ static ssize_t btrfs_feature_attr_store(struct kobject *kobj,
set_features(fs_info, fa->feature_set, features); set_features(fs_info, fa->feature_set, features);
spin_unlock(&fs_info->super_lock); spin_unlock(&fs_info->super_lock);
ret = btrfs_commit_transaction(trans, fs_info->fs_root); /*
if (ret) * We don't want to do full transaction commit from inside sysfs
return ret; */
btrfs_set_pending(fs_info, COMMIT);
wake_up_process(fs_info->transaction_kthread);
return count; return count;
} }
...@@ -372,9 +369,6 @@ static ssize_t btrfs_label_store(struct kobject *kobj, ...@@ -372,9 +369,6 @@ static ssize_t btrfs_label_store(struct kobject *kobj,
const char *buf, size_t len) const char *buf, size_t len)
{ {
struct btrfs_fs_info *fs_info = to_fs_info(kobj); struct btrfs_fs_info *fs_info = to_fs_info(kobj);
struct btrfs_trans_handle *trans;
struct btrfs_root *root = fs_info->fs_root;
int ret;
size_t p_len; size_t p_len;
if (fs_info->sb->s_flags & MS_RDONLY) if (fs_info->sb->s_flags & MS_RDONLY)
...@@ -389,20 +383,18 @@ static ssize_t btrfs_label_store(struct kobject *kobj, ...@@ -389,20 +383,18 @@ static ssize_t btrfs_label_store(struct kobject *kobj,
if (p_len >= BTRFS_LABEL_SIZE) if (p_len >= BTRFS_LABEL_SIZE)
return -EINVAL; return -EINVAL;
trans = btrfs_start_transaction(root, 0); spin_lock(&fs_info->super_lock);
if (IS_ERR(trans))
return PTR_ERR(trans);
spin_lock(&root->fs_info->super_lock);
memset(fs_info->super_copy->label, 0, BTRFS_LABEL_SIZE); memset(fs_info->super_copy->label, 0, BTRFS_LABEL_SIZE);
memcpy(fs_info->super_copy->label, buf, p_len); memcpy(fs_info->super_copy->label, buf, p_len);
spin_unlock(&root->fs_info->super_lock); spin_unlock(&fs_info->super_lock);
ret = btrfs_commit_transaction(trans, root);
if (!ret) /*
return len; * We don't want to do full transaction commit from inside sysfs
*/
btrfs_set_pending(fs_info, COMMIT);
wake_up_process(fs_info->transaction_kthread);
return ret; return len;
} }
BTRFS_ATTR_RW(label, btrfs_label_show, btrfs_label_store); BTRFS_ATTR_RW(label, btrfs_label_show, btrfs_label_store);
......
...@@ -1938,13 +1938,10 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, ...@@ -1938,13 +1938,10 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
} }
/* /*
* Since the transaction is done, we should set the inode map cache flag * Since the transaction is done, we can apply the pending changes
* before any other comming transaction. * before the next transaction.
*/ */
if (btrfs_test_opt(root, CHANGE_INODE_CACHE)) btrfs_apply_pending_changes(root->fs_info);
btrfs_set_opt(root->fs_info->mount_opt, INODE_MAP_CACHE);
else
btrfs_clear_opt(root->fs_info->mount_opt, INODE_MAP_CACHE);
/* commit_fs_roots gets rid of all the tree log roots, it is now /* commit_fs_roots gets rid of all the tree log roots, it is now
* safe to free the root of tree log roots * safe to free the root of tree log roots
...@@ -2115,3 +2112,32 @@ int btrfs_clean_one_deleted_snapshot(struct btrfs_root *root) ...@@ -2115,3 +2112,32 @@ int btrfs_clean_one_deleted_snapshot(struct btrfs_root *root)
return (ret < 0) ? 0 : 1; return (ret < 0) ? 0 : 1;
} }
void btrfs_apply_pending_changes(struct btrfs_fs_info *fs_info)
{
unsigned long prev;
unsigned long bit;
prev = cmpxchg(&fs_info->pending_changes, 0, 0);
if (!prev)
return;
bit = 1 << BTRFS_PENDING_SET_INODE_MAP_CACHE;
if (prev & bit)
btrfs_set_opt(fs_info->mount_opt, INODE_MAP_CACHE);
prev &= ~bit;
bit = 1 << BTRFS_PENDING_CLEAR_INODE_MAP_CACHE;
if (prev & bit)
btrfs_clear_opt(fs_info->mount_opt, INODE_MAP_CACHE);
prev &= ~bit;
bit = 1 << BTRFS_PENDING_COMMIT;
if (prev & bit)
btrfs_debug(fs_info, "pending commit done");
prev &= ~bit;
if (prev)
btrfs_warn(fs_info,
"unknown pending changes left 0x%lx, ignoring", prev);
}
...@@ -170,4 +170,6 @@ int btrfs_wait_marked_extents(struct btrfs_root *root, ...@@ -170,4 +170,6 @@ int btrfs_wait_marked_extents(struct btrfs_root *root,
int btrfs_transaction_blocked(struct btrfs_fs_info *info); int btrfs_transaction_blocked(struct btrfs_fs_info *info);
int btrfs_transaction_in_commit(struct btrfs_fs_info *info); int btrfs_transaction_in_commit(struct btrfs_fs_info *info);
void btrfs_put_transaction(struct btrfs_transaction *transaction); void btrfs_put_transaction(struct btrfs_transaction *transaction);
void btrfs_apply_pending_changes(struct btrfs_fs_info *fs_info);
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment