Commit 4d5e74bc0aec3f54b7e429d77b7c35de042c507d
1 parent
2da98f003f
Exists in
master
and in
7 other branches
Btrfs: Fix data=ordered vs wait_on_inode deadlock on older kernels
Using ilookup5 during data=ordered writeback could deadlock on I_LOCK. This saves a pointer to the inode instead. Signed-off-by: Chris Mason <chris.mason@oracle.com>
Showing 3 changed files with 27 additions and 21 deletions Side-by-side Diff
fs/btrfs/ordered-data.c
... | ... | @@ -25,6 +25,7 @@ |
25 | 25 | struct tree_entry { |
26 | 26 | u64 root_objectid; |
27 | 27 | u64 objectid; |
28 | + struct inode *inode; | |
28 | 29 | struct rb_node rb_node; |
29 | 30 | }; |
30 | 31 | |
... | ... | @@ -144,6 +145,7 @@ |
144 | 145 | write_lock(&tree->lock); |
145 | 146 | entry->objectid = inode->i_ino; |
146 | 147 | entry->root_objectid = root_objectid; |
148 | + entry->inode = inode; | |
147 | 149 | |
148 | 150 | node = tree_insert(&tree->tree, root_objectid, |
149 | 151 | inode->i_ino, &entry->rb_node); |
... | ... | @@ -159,7 +161,8 @@ |
159 | 161 | } |
160 | 162 | |
161 | 163 | int btrfs_find_first_ordered_inode(struct btrfs_ordered_inode_tree *tree, |
162 | - u64 *root_objectid, u64 *objectid) | |
164 | + u64 *root_objectid, u64 *objectid, | |
165 | + struct inode **inode) | |
163 | 166 | { |
164 | 167 | struct tree_entry *entry; |
165 | 168 | struct rb_node *node; |
166 | 169 | |
... | ... | @@ -184,13 +187,16 @@ |
184 | 187 | } |
185 | 188 | |
186 | 189 | *root_objectid = entry->root_objectid; |
190 | + *inode = entry->inode; | |
191 | + atomic_inc(&entry->inode->i_count); | |
187 | 192 | *objectid = entry->objectid; |
188 | 193 | write_unlock(&tree->lock); |
189 | 194 | return 1; |
190 | 195 | } |
191 | 196 | |
192 | 197 | int btrfs_find_del_first_ordered_inode(struct btrfs_ordered_inode_tree *tree, |
193 | - u64 *root_objectid, u64 *objectid) | |
198 | + u64 *root_objectid, u64 *objectid, | |
199 | + struct inode **inode) | |
194 | 200 | { |
195 | 201 | struct tree_entry *entry; |
196 | 202 | struct rb_node *node; |
... | ... | @@ -216,6 +222,8 @@ |
216 | 222 | |
217 | 223 | *root_objectid = entry->root_objectid; |
218 | 224 | *objectid = entry->objectid; |
225 | + *inode = entry->inode; | |
226 | + atomic_inc(&entry->inode->i_count); | |
219 | 227 | rb_erase(node, &tree->tree); |
220 | 228 | write_unlock(&tree->lock); |
221 | 229 | kfree(entry); |
fs/btrfs/ordered-data.h
... | ... | @@ -33,9 +33,11 @@ |
33 | 33 | |
34 | 34 | int btrfs_add_ordered_inode(struct inode *inode); |
35 | 35 | int btrfs_find_del_first_ordered_inode(struct btrfs_ordered_inode_tree *tree, |
36 | - u64 *root_objectid, u64 *objectid); | |
36 | + u64 *root_objectid, u64 *objectid, | |
37 | + struct inode **inode); | |
37 | 38 | int btrfs_find_first_ordered_inode(struct btrfs_ordered_inode_tree *tree, |
38 | - u64 *root_objectid, u64 *objectid); | |
39 | + u64 *root_objectid, u64 *objectid, | |
40 | + struct inode **inode); | |
39 | 41 | int btrfs_del_ordered_inode(struct inode *inode); |
40 | 42 | #endif |
fs/btrfs/transaction.c
... | ... | @@ -490,19 +490,17 @@ |
490 | 490 | while(1) { |
491 | 491 | ret = btrfs_find_first_ordered_inode( |
492 | 492 | &cur_trans->ordered_inode_tree, |
493 | - &root_objectid, &objectid); | |
493 | + &root_objectid, &objectid, &inode); | |
494 | 494 | if (!ret) |
495 | 495 | break; |
496 | 496 | |
497 | 497 | mutex_unlock(&root->fs_info->trans_mutex); |
498 | 498 | mutex_unlock(&root->fs_info->fs_mutex); |
499 | - inode = btrfs_ilookup(root->fs_info->sb, objectid, | |
500 | - root_objectid); | |
501 | - if (inode) { | |
502 | - if (S_ISREG(inode->i_mode)) | |
503 | - filemap_fdatawrite(inode->i_mapping); | |
504 | - iput(inode); | |
505 | - } | |
499 | + | |
500 | + if (S_ISREG(inode->i_mode)) | |
501 | + filemap_fdatawrite(inode->i_mapping); | |
502 | + iput(inode); | |
503 | + | |
506 | 504 | mutex_lock(&root->fs_info->fs_mutex); |
507 | 505 | mutex_lock(&root->fs_info->trans_mutex); |
508 | 506 | } |
509 | 507 | |
... | ... | @@ -511,19 +509,17 @@ |
511 | 509 | objectid = 0; |
512 | 510 | ret = btrfs_find_del_first_ordered_inode( |
513 | 511 | &cur_trans->ordered_inode_tree, |
514 | - &root_objectid, &objectid); | |
512 | + &root_objectid, &objectid, &inode); | |
515 | 513 | if (!ret) |
516 | 514 | break; |
517 | 515 | mutex_unlock(&root->fs_info->trans_mutex); |
518 | 516 | mutex_unlock(&root->fs_info->fs_mutex); |
519 | - inode = btrfs_ilookup(root->fs_info->sb, objectid, | |
520 | - root_objectid); | |
521 | - if (inode) { | |
522 | - if (S_ISREG(inode->i_mode)) | |
523 | - filemap_write_and_wait(inode->i_mapping); | |
524 | - atomic_dec(&inode->i_count); | |
525 | - iput(inode); | |
526 | - } | |
517 | + | |
518 | + if (S_ISREG(inode->i_mode)) | |
519 | + filemap_write_and_wait(inode->i_mapping); | |
520 | + atomic_dec(&inode->i_count); | |
521 | + iput(inode); | |
522 | + | |
527 | 523 | mutex_lock(&root->fs_info->fs_mutex); |
528 | 524 | mutex_lock(&root->fs_info->trans_mutex); |
529 | 525 | } |