aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/tree-log.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2008-09-08 11:18:08 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:04:07 -0400
commit4bef084857ab8fe71cf49eae349c25e440a49150 (patch)
tree7a9a850515538421c2976f8ee4c1bea5ceced59c /fs/btrfs/tree-log.c
parent325cd4bafeb6cfb44addd6e807a9b74170d1be31 (diff)
Btrfs: Tree logging fixes
* Pin down data blocks to prevent them from being reallocated like so: trans 1: allocate file extent trans 2: free file extent trans 3: free file extent during old snapshot deletion trans 3: allocate file extent to new file trans 3: fsync new file Before the tree logging code, this was legal because the fsync would commit the transation that did the final data extent free and the transaction that allocated the extent to the new file at the same time. With the tree logging code, the tree log subtransaction can commit before the transaction that freed the extent. If we crash, we're left with two different files using the extent. * Don't wait in start_transaction if log replay is going on. This avoids deadlocks from iput while we're cleaning up link counts in the replay code. * Don't deadlock in replay_one_name by trying to read an inode off the disk while holding paths for the directory * Hold the buffer lock while we mark a buffer as written. This closes a race where someone is changing a buffer while we write it. They are supposed to mark it dirty again after they change it, but this violates the cow rules. Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/tree-log.c')
-rw-r--r--fs/btrfs/tree-log.c13
1 files changed, 9 insertions, 4 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index d1ce8314b948..13d7ee8e0c52 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -1176,8 +1176,8 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
1176 struct btrfs_key found_key; 1176 struct btrfs_key found_key;
1177 struct btrfs_key log_key; 1177 struct btrfs_key log_key;
1178 struct inode *dir; 1178 struct inode *dir;
1179 struct inode *inode;
1180 u8 log_type; 1179 u8 log_type;
1180 int exists;
1181 int ret; 1181 int ret;
1182 1182
1183 dir = read_one_inode(root, key->objectid); 1183 dir = read_one_inode(root, key->objectid);
@@ -1190,6 +1190,13 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
1190 name_len); 1190 name_len);
1191 1191
1192 btrfs_dir_item_key_to_cpu(eb, di, &log_key); 1192 btrfs_dir_item_key_to_cpu(eb, di, &log_key);
1193 exists = btrfs_lookup_inode(trans, root, path, &log_key, 0);
1194 if (exists == 0)
1195 exists = 1;
1196 else
1197 exists = 0;
1198 btrfs_release_path(root, path);
1199
1193 if (key->type == BTRFS_DIR_ITEM_KEY) { 1200 if (key->type == BTRFS_DIR_ITEM_KEY) {
1194 dst_di = btrfs_lookup_dir_item(trans, root, path, key->objectid, 1201 dst_di = btrfs_lookup_dir_item(trans, root, path, key->objectid,
1195 name, name_len, 1); 1202 name, name_len, 1);
@@ -1224,11 +1231,9 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
1224 * don't drop the conflicting directory entry if the inode 1231 * don't drop the conflicting directory entry if the inode
1225 * for the new entry doesn't exist 1232 * for the new entry doesn't exist
1226 */ 1233 */
1227 inode = read_one_inode(root, log_key.objectid); 1234 if (!exists)
1228 if (!inode)
1229 goto out; 1235 goto out;
1230 1236
1231 iput(inode);
1232 ret = drop_one_dir_item(trans, root, path, dir, dst_di); 1237 ret = drop_one_dir_item(trans, root, path, dir, dst_di);
1233 BUG_ON(ret); 1238 BUG_ON(ret);
1234 1239