diff options
| -rw-r--r-- | fs/btrfs/btrfs_inode.h | 6 | ||||
| -rw-r--r-- | fs/btrfs/ctree.h | 1 | ||||
| -rw-r--r-- | fs/btrfs/disk-io.c | 2 | ||||
| -rw-r--r-- | fs/btrfs/file.c | 41 | ||||
| -rw-r--r-- | fs/btrfs/inode.c | 6 | ||||
| -rw-r--r-- | fs/btrfs/transaction.h | 1 | ||||
| -rw-r--r-- | fs/btrfs/tree-log.c | 27 | ||||
| -rw-r--r-- | fs/btrfs/tree-log.h | 3 |
8 files changed, 71 insertions, 16 deletions
diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h index c71abec0ab90..f6783a42f010 100644 --- a/fs/btrfs/btrfs_inode.h +++ b/fs/btrfs/btrfs_inode.h | |||
| @@ -86,6 +86,12 @@ struct btrfs_inode { | |||
| 86 | * transid of the trans_handle that last modified this inode | 86 | * transid of the trans_handle that last modified this inode |
| 87 | */ | 87 | */ |
| 88 | u64 last_trans; | 88 | u64 last_trans; |
| 89 | |||
| 90 | /* | ||
| 91 | * log transid when this inode was last modified | ||
| 92 | */ | ||
| 93 | u64 last_sub_trans; | ||
| 94 | |||
| 89 | /* | 95 | /* |
| 90 | * transid that last logged this inode | 96 | * transid that last logged this inode |
| 91 | */ | 97 | */ |
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 36a19cd43e03..d0cede5ff25e 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
| @@ -1009,6 +1009,7 @@ struct btrfs_root { | |||
| 1009 | atomic_t log_writers; | 1009 | atomic_t log_writers; |
| 1010 | atomic_t log_commit[2]; | 1010 | atomic_t log_commit[2]; |
| 1011 | unsigned long log_transid; | 1011 | unsigned long log_transid; |
| 1012 | unsigned long last_log_commit; | ||
| 1012 | unsigned long log_batch; | 1013 | unsigned long log_batch; |
| 1013 | pid_t log_start_pid; | 1014 | pid_t log_start_pid; |
| 1014 | bool log_multiple_pids; | 1015 | bool log_multiple_pids; |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index ac8927bdc33d..d4132aad9ea1 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
| @@ -919,6 +919,7 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, | |||
| 919 | atomic_set(&root->log_writers, 0); | 919 | atomic_set(&root->log_writers, 0); |
| 920 | root->log_batch = 0; | 920 | root->log_batch = 0; |
| 921 | root->log_transid = 0; | 921 | root->log_transid = 0; |
| 922 | root->last_log_commit = 0; | ||
| 922 | extent_io_tree_init(&root->dirty_log_pages, | 923 | extent_io_tree_init(&root->dirty_log_pages, |
| 923 | fs_info->btree_inode->i_mapping, GFP_NOFS); | 924 | fs_info->btree_inode->i_mapping, GFP_NOFS); |
| 924 | 925 | ||
| @@ -1089,6 +1090,7 @@ int btrfs_add_log_tree(struct btrfs_trans_handle *trans, | |||
| 1089 | WARN_ON(root->log_root); | 1090 | WARN_ON(root->log_root); |
| 1090 | root->log_root = log_root; | 1091 | root->log_root = log_root; |
| 1091 | root->log_transid = 0; | 1092 | root->log_transid = 0; |
| 1093 | root->last_log_commit = 0; | ||
| 1092 | return 0; | 1094 | return 0; |
| 1093 | } | 1095 | } |
| 1094 | 1096 | ||
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 53fb1c997f0e..4599113ed72e 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
| @@ -1087,8 +1087,10 @@ out_nolock: | |||
| 1087 | btrfs_end_transaction(trans, root); | 1087 | btrfs_end_transaction(trans, root); |
| 1088 | else | 1088 | else |
| 1089 | btrfs_commit_transaction(trans, root); | 1089 | btrfs_commit_transaction(trans, root); |
| 1090 | } else { | 1090 | } else if (ret != BTRFS_NO_LOG_SYNC) { |
| 1091 | btrfs_commit_transaction(trans, root); | 1091 | btrfs_commit_transaction(trans, root); |
| 1092 | } else { | ||
| 1093 | btrfs_end_transaction(trans, root); | ||
| 1092 | } | 1094 | } |
| 1093 | } | 1095 | } |
| 1094 | if (file->f_flags & O_DIRECT) { | 1096 | if (file->f_flags & O_DIRECT) { |
| @@ -1138,6 +1140,13 @@ int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync) | |||
| 1138 | int ret = 0; | 1140 | int ret = 0; |
| 1139 | struct btrfs_trans_handle *trans; | 1141 | struct btrfs_trans_handle *trans; |
| 1140 | 1142 | ||
| 1143 | |||
| 1144 | /* we wait first, since the writeback may change the inode */ | ||
| 1145 | root->log_batch++; | ||
| 1146 | /* the VFS called filemap_fdatawrite for us */ | ||
| 1147 | btrfs_wait_ordered_range(inode, 0, (u64)-1); | ||
| 1148 | root->log_batch++; | ||
| 1149 | |||
| 1141 | /* | 1150 | /* |
| 1142 | * check the transaction that last modified this inode | 1151 | * check the transaction that last modified this inode |
| 1143 | * and see if its already been committed | 1152 | * and see if its already been committed |
| @@ -1145,6 +1154,11 @@ int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync) | |||
| 1145 | if (!BTRFS_I(inode)->last_trans) | 1154 | if (!BTRFS_I(inode)->last_trans) |
| 1146 | goto out; | 1155 | goto out; |
| 1147 | 1156 | ||
| 1157 | /* | ||
| 1158 | * if the last transaction that changed this file was before | ||
| 1159 | * the current transaction, we can bail out now without any | ||
| 1160 | * syncing | ||
| 1161 | */ | ||
| 1148 | mutex_lock(&root->fs_info->trans_mutex); | 1162 | mutex_lock(&root->fs_info->trans_mutex); |
| 1149 | if (BTRFS_I(inode)->last_trans <= | 1163 | if (BTRFS_I(inode)->last_trans <= |
| 1150 | root->fs_info->last_trans_committed) { | 1164 | root->fs_info->last_trans_committed) { |
| @@ -1154,13 +1168,6 @@ int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync) | |||
| 1154 | } | 1168 | } |
| 1155 | mutex_unlock(&root->fs_info->trans_mutex); | 1169 | mutex_unlock(&root->fs_info->trans_mutex); |
| 1156 | 1170 | ||
| 1157 | root->log_batch++; | ||
| 1158 | filemap_fdatawrite(inode->i_mapping); | ||
| 1159 | btrfs_wait_ordered_range(inode, 0, (u64)-1); | ||
| 1160 | root->log_batch++; | ||
| 1161 | |||
| 1162 | if (datasync && !(inode->i_state & I_DIRTY_PAGES)) | ||
| 1163 | goto out; | ||
| 1164 | /* | 1171 | /* |
| 1165 | * ok we haven't committed the transaction yet, lets do a commit | 1172 | * ok we haven't committed the transaction yet, lets do a commit |
| 1166 | */ | 1173 | */ |
| @@ -1189,14 +1196,18 @@ int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync) | |||
| 1189 | */ | 1196 | */ |
| 1190 | mutex_unlock(&dentry->d_inode->i_mutex); | 1197 | mutex_unlock(&dentry->d_inode->i_mutex); |
| 1191 | 1198 | ||
| 1192 | if (ret > 0) { | 1199 | if (ret != BTRFS_NO_LOG_SYNC) { |
| 1193 | ret = btrfs_commit_transaction(trans, root); | 1200 | if (ret > 0) { |
| 1194 | } else { | ||
| 1195 | ret = btrfs_sync_log(trans, root); | ||
| 1196 | if (ret == 0) | ||
| 1197 | ret = btrfs_end_transaction(trans, root); | ||
| 1198 | else | ||
| 1199 | ret = btrfs_commit_transaction(trans, root); | 1201 | ret = btrfs_commit_transaction(trans, root); |
| 1202 | } else { | ||
| 1203 | ret = btrfs_sync_log(trans, root); | ||
| 1204 | if (ret == 0) | ||
| 1205 | ret = btrfs_end_transaction(trans, root); | ||
| 1206 | else | ||
| 1207 | ret = btrfs_commit_transaction(trans, root); | ||
| 1208 | } | ||
| 1209 | } else { | ||
| 1210 | ret = btrfs_end_transaction(trans, root); | ||
| 1200 | } | 1211 | } |
| 1201 | mutex_lock(&dentry->d_inode->i_mutex); | 1212 | mutex_lock(&dentry->d_inode->i_mutex); |
| 1202 | out: | 1213 | out: |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index ef399a7794ff..5b9567caba0a 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
| @@ -3480,6 +3480,7 @@ static noinline void init_btrfs_i(struct inode *inode) | |||
| 3480 | bi->generation = 0; | 3480 | bi->generation = 0; |
| 3481 | bi->sequence = 0; | 3481 | bi->sequence = 0; |
| 3482 | bi->last_trans = 0; | 3482 | bi->last_trans = 0; |
| 3483 | bi->last_sub_trans = 0; | ||
| 3483 | bi->logged_trans = 0; | 3484 | bi->logged_trans = 0; |
| 3484 | bi->delalloc_bytes = 0; | 3485 | bi->delalloc_bytes = 0; |
| 3485 | bi->reserved_bytes = 0; | 3486 | bi->reserved_bytes = 0; |
| @@ -4980,7 +4981,9 @@ again: | |||
| 4980 | set_page_dirty(page); | 4981 | set_page_dirty(page); |
| 4981 | SetPageUptodate(page); | 4982 | SetPageUptodate(page); |
| 4982 | 4983 | ||
| 4983 | BTRFS_I(inode)->last_trans = root->fs_info->generation + 1; | 4984 | BTRFS_I(inode)->last_trans = root->fs_info->generation; |
| 4985 | BTRFS_I(inode)->last_sub_trans = BTRFS_I(inode)->root->log_transid; | ||
| 4986 | |||
| 4984 | unlock_extent(io_tree, page_start, page_end, GFP_NOFS); | 4987 | unlock_extent(io_tree, page_start, page_end, GFP_NOFS); |
| 4985 | 4988 | ||
| 4986 | out_unlock: | 4989 | out_unlock: |
| @@ -5100,6 +5103,7 @@ struct inode *btrfs_alloc_inode(struct super_block *sb) | |||
| 5100 | if (!ei) | 5103 | if (!ei) |
| 5101 | return NULL; | 5104 | return NULL; |
| 5102 | ei->last_trans = 0; | 5105 | ei->last_trans = 0; |
| 5106 | ei->last_sub_trans = 0; | ||
| 5103 | ei->logged_trans = 0; | 5107 | ei->logged_trans = 0; |
| 5104 | ei->outstanding_extents = 0; | 5108 | ei->outstanding_extents = 0; |
| 5105 | ei->reserved_extents = 0; | 5109 | ei->reserved_extents = 0; |
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h index 663c67404918..f68cbbe61e56 100644 --- a/fs/btrfs/transaction.h +++ b/fs/btrfs/transaction.h | |||
| @@ -79,6 +79,7 @@ static inline void btrfs_set_inode_last_trans(struct btrfs_trans_handle *trans, | |||
| 79 | struct inode *inode) | 79 | struct inode *inode) |
| 80 | { | 80 | { |
| 81 | BTRFS_I(inode)->last_trans = trans->transaction->transid; | 81 | BTRFS_I(inode)->last_trans = trans->transaction->transid; |
| 82 | BTRFS_I(inode)->last_sub_trans = BTRFS_I(inode)->root->log_transid; | ||
| 82 | } | 83 | } |
| 83 | 84 | ||
| 84 | int btrfs_end_transaction(struct btrfs_trans_handle *trans, | 85 | int btrfs_end_transaction(struct btrfs_trans_handle *trans, |
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 6d9ec285644d..0a1bde268963 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
| @@ -1980,6 +1980,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
| 1980 | int ret; | 1980 | int ret; |
| 1981 | struct btrfs_root *log = root->log_root; | 1981 | struct btrfs_root *log = root->log_root; |
| 1982 | struct btrfs_root *log_root_tree = root->fs_info->log_root_tree; | 1982 | struct btrfs_root *log_root_tree = root->fs_info->log_root_tree; |
| 1983 | u64 log_transid = 0; | ||
| 1983 | 1984 | ||
| 1984 | mutex_lock(&root->log_mutex); | 1985 | mutex_lock(&root->log_mutex); |
| 1985 | index1 = root->log_transid % 2; | 1986 | index1 = root->log_transid % 2; |
| @@ -2018,6 +2019,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
| 2018 | btrfs_set_root_node(&log->root_item, log->node); | 2019 | btrfs_set_root_node(&log->root_item, log->node); |
| 2019 | 2020 | ||
| 2020 | root->log_batch = 0; | 2021 | root->log_batch = 0; |
| 2022 | log_transid = root->log_transid; | ||
| 2021 | root->log_transid++; | 2023 | root->log_transid++; |
| 2022 | log->log_transid = root->log_transid; | 2024 | log->log_transid = root->log_transid; |
| 2023 | root->log_start_pid = 0; | 2025 | root->log_start_pid = 0; |
| @@ -2095,6 +2097,11 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
| 2095 | write_ctree_super(trans, root->fs_info->tree_root, 1); | 2097 | write_ctree_super(trans, root->fs_info->tree_root, 1); |
| 2096 | ret = 0; | 2098 | ret = 0; |
| 2097 | 2099 | ||
| 2100 | mutex_lock(&root->log_mutex); | ||
| 2101 | if (root->last_log_commit < log_transid) | ||
| 2102 | root->last_log_commit = log_transid; | ||
| 2103 | mutex_unlock(&root->log_mutex); | ||
| 2104 | |||
| 2098 | out_wake_log_root: | 2105 | out_wake_log_root: |
| 2099 | atomic_set(&log_root_tree->log_commit[index2], 0); | 2106 | atomic_set(&log_root_tree->log_commit[index2], 0); |
| 2100 | smp_mb(); | 2107 | smp_mb(); |
| @@ -2862,6 +2869,21 @@ out: | |||
| 2862 | return ret; | 2869 | return ret; |
| 2863 | } | 2870 | } |
| 2864 | 2871 | ||
| 2872 | static int inode_in_log(struct btrfs_trans_handle *trans, | ||
| 2873 | struct inode *inode) | ||
| 2874 | { | ||
| 2875 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
| 2876 | int ret = 0; | ||
| 2877 | |||
| 2878 | mutex_lock(&root->log_mutex); | ||
| 2879 | if (BTRFS_I(inode)->logged_trans == trans->transid && | ||
| 2880 | BTRFS_I(inode)->last_sub_trans <= root->last_log_commit) | ||
| 2881 | ret = 1; | ||
| 2882 | mutex_unlock(&root->log_mutex); | ||
| 2883 | return ret; | ||
| 2884 | } | ||
| 2885 | |||
| 2886 | |||
| 2865 | /* | 2887 | /* |
| 2866 | * helper function around btrfs_log_inode to make sure newly created | 2888 | * helper function around btrfs_log_inode to make sure newly created |
| 2867 | * parent directories also end up in the log. A minimal inode and backref | 2889 | * parent directories also end up in the log. A minimal inode and backref |
| @@ -2901,6 +2923,11 @@ int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, | |||
| 2901 | if (ret) | 2923 | if (ret) |
| 2902 | goto end_no_trans; | 2924 | goto end_no_trans; |
| 2903 | 2925 | ||
| 2926 | if (inode_in_log(trans, inode)) { | ||
| 2927 | ret = BTRFS_NO_LOG_SYNC; | ||
| 2928 | goto end_no_trans; | ||
| 2929 | } | ||
| 2930 | |||
| 2904 | start_log_trans(trans, root); | 2931 | start_log_trans(trans, root); |
| 2905 | 2932 | ||
| 2906 | ret = btrfs_log_inode(trans, root, inode, inode_only); | 2933 | ret = btrfs_log_inode(trans, root, inode, inode_only); |
diff --git a/fs/btrfs/tree-log.h b/fs/btrfs/tree-log.h index d09c7609e16b..0776eacb5083 100644 --- a/fs/btrfs/tree-log.h +++ b/fs/btrfs/tree-log.h | |||
| @@ -19,6 +19,9 @@ | |||
| 19 | #ifndef __TREE_LOG_ | 19 | #ifndef __TREE_LOG_ |
| 20 | #define __TREE_LOG_ | 20 | #define __TREE_LOG_ |
| 21 | 21 | ||
| 22 | /* return value for btrfs_log_dentry_safe that means we don't need to log it at all */ | ||
| 23 | #define BTRFS_NO_LOG_SYNC 256 | ||
| 24 | |||
| 22 | int btrfs_sync_log(struct btrfs_trans_handle *trans, | 25 | int btrfs_sync_log(struct btrfs_trans_handle *trans, |
| 23 | struct btrfs_root *root); | 26 | struct btrfs_root *root); |
| 24 | int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root); | 27 | int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root); |
