diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-10-10 11:30:51 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-10-10 11:30:51 -0400 |
commit | f8779876d4a79d243870a5b5d60009e4ec6f22f4 (patch) | |
tree | aeb62fd90c9eb089656a7742613c419490bc80fd /fs/btrfs/tree-log.c | |
parent | ad338d05438ec003f90ac7304fbac80ef2d8c80e (diff) | |
parent | 431d39887d6273d6d84edf3c2eab09f4200e788a (diff) |
Merge tag 'for-5.4-rc2-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux
Pull btrfs fixes from David Sterba:
"A few more stabitly fixes, one build warning fix.
- fix inode allocation under NOFS context
- fix leak in fiemap due to concurrent append writes
- fix log-root tree updates
- fix balance convert of single profile on 32bit architectures
- silence false positive warning on old GCCs (code moved in rc1)"
* tag 'for-5.4-rc2-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
btrfs: silence maybe-uninitialized warning in clone_range
btrfs: fix uninitialized ret in ref-verify
btrfs: allocate new inode in NOFS context
btrfs: fix balance convert to single on 32-bit host CPUs
btrfs: fix incorrect updating of log root tree
Btrfs: fix memory leak due to concurrent append writes with fiemap
Diffstat (limited to 'fs/btrfs/tree-log.c')
-rw-r--r-- | fs/btrfs/tree-log.c | 36 |
1 files changed, 27 insertions, 9 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 29b82a795522..8a6cc600bf18 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
@@ -2932,7 +2932,8 @@ out: | |||
2932 | * in the tree of log roots | 2932 | * in the tree of log roots |
2933 | */ | 2933 | */ |
2934 | static int update_log_root(struct btrfs_trans_handle *trans, | 2934 | static int update_log_root(struct btrfs_trans_handle *trans, |
2935 | struct btrfs_root *log) | 2935 | struct btrfs_root *log, |
2936 | struct btrfs_root_item *root_item) | ||
2936 | { | 2937 | { |
2937 | struct btrfs_fs_info *fs_info = log->fs_info; | 2938 | struct btrfs_fs_info *fs_info = log->fs_info; |
2938 | int ret; | 2939 | int ret; |
@@ -2940,10 +2941,10 @@ static int update_log_root(struct btrfs_trans_handle *trans, | |||
2940 | if (log->log_transid == 1) { | 2941 | if (log->log_transid == 1) { |
2941 | /* insert root item on the first sync */ | 2942 | /* insert root item on the first sync */ |
2942 | ret = btrfs_insert_root(trans, fs_info->log_root_tree, | 2943 | ret = btrfs_insert_root(trans, fs_info->log_root_tree, |
2943 | &log->root_key, &log->root_item); | 2944 | &log->root_key, root_item); |
2944 | } else { | 2945 | } else { |
2945 | ret = btrfs_update_root(trans, fs_info->log_root_tree, | 2946 | ret = btrfs_update_root(trans, fs_info->log_root_tree, |
2946 | &log->root_key, &log->root_item); | 2947 | &log->root_key, root_item); |
2947 | } | 2948 | } |
2948 | return ret; | 2949 | return ret; |
2949 | } | 2950 | } |
@@ -3041,6 +3042,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
3041 | struct btrfs_fs_info *fs_info = root->fs_info; | 3042 | struct btrfs_fs_info *fs_info = root->fs_info; |
3042 | struct btrfs_root *log = root->log_root; | 3043 | struct btrfs_root *log = root->log_root; |
3043 | struct btrfs_root *log_root_tree = fs_info->log_root_tree; | 3044 | struct btrfs_root *log_root_tree = fs_info->log_root_tree; |
3045 | struct btrfs_root_item new_root_item; | ||
3044 | int log_transid = 0; | 3046 | int log_transid = 0; |
3045 | struct btrfs_log_ctx root_log_ctx; | 3047 | struct btrfs_log_ctx root_log_ctx; |
3046 | struct blk_plug plug; | 3048 | struct blk_plug plug; |
@@ -3104,18 +3106,26 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
3104 | goto out; | 3106 | goto out; |
3105 | } | 3107 | } |
3106 | 3108 | ||
3109 | /* | ||
3110 | * We _must_ update under the root->log_mutex in order to make sure we | ||
3111 | * have a consistent view of the log root we are trying to commit at | ||
3112 | * this moment. | ||
3113 | * | ||
3114 | * We _must_ copy this into a local copy, because we are not holding the | ||
3115 | * log_root_tree->log_mutex yet. This is important because when we | ||
3116 | * commit the log_root_tree we must have a consistent view of the | ||
3117 | * log_root_tree when we update the super block to point at the | ||
3118 | * log_root_tree bytenr. If we update the log_root_tree here we'll race | ||
3119 | * with the commit and possibly point at the new block which we may not | ||
3120 | * have written out. | ||
3121 | */ | ||
3107 | btrfs_set_root_node(&log->root_item, log->node); | 3122 | btrfs_set_root_node(&log->root_item, log->node); |
3123 | memcpy(&new_root_item, &log->root_item, sizeof(new_root_item)); | ||
3108 | 3124 | ||
3109 | root->log_transid++; | 3125 | root->log_transid++; |
3110 | log->log_transid = root->log_transid; | 3126 | log->log_transid = root->log_transid; |
3111 | root->log_start_pid = 0; | 3127 | root->log_start_pid = 0; |
3112 | /* | 3128 | /* |
3113 | * Update or create log root item under the root's log_mutex to prevent | ||
3114 | * races with concurrent log syncs that can lead to failure to update | ||
3115 | * log root item because it was not created yet. | ||
3116 | */ | ||
3117 | ret = update_log_root(trans, log); | ||
3118 | /* | ||
3119 | * IO has been started, blocks of the log tree have WRITTEN flag set | 3129 | * IO has been started, blocks of the log tree have WRITTEN flag set |
3120 | * in their headers. new modifications of the log will be written to | 3130 | * in their headers. new modifications of the log will be written to |
3121 | * new positions. so it's safe to allow log writers to go in. | 3131 | * new positions. so it's safe to allow log writers to go in. |
@@ -3135,6 +3145,14 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
3135 | mutex_unlock(&log_root_tree->log_mutex); | 3145 | mutex_unlock(&log_root_tree->log_mutex); |
3136 | 3146 | ||
3137 | mutex_lock(&log_root_tree->log_mutex); | 3147 | mutex_lock(&log_root_tree->log_mutex); |
3148 | |||
3149 | /* | ||
3150 | * Now we are safe to update the log_root_tree because we're under the | ||
3151 | * log_mutex, and we're a current writer so we're holding the commit | ||
3152 | * open until we drop the log_mutex. | ||
3153 | */ | ||
3154 | ret = update_log_root(trans, log, &new_root_item); | ||
3155 | |||
3138 | if (atomic_dec_and_test(&log_root_tree->log_writers)) { | 3156 | if (atomic_dec_and_test(&log_root_tree->log_writers)) { |
3139 | /* atomic_dec_and_test implies a barrier */ | 3157 | /* atomic_dec_and_test implies a barrier */ |
3140 | cond_wake_up_nomb(&log_root_tree->log_writer_wait); | 3158 | cond_wake_up_nomb(&log_root_tree->log_writer_wait); |