diff options
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r-- | fs/btrfs/inode.c | 36 |
1 files changed, 28 insertions, 8 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index e28f3d4691af..5f06eb1f4384 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -7116,21 +7116,41 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode, | |||
7116 | if (ret) | 7116 | if (ret) |
7117 | return ERR_PTR(ret); | 7117 | return ERR_PTR(ret); |
7118 | 7118 | ||
7119 | em = create_pinned_em(inode, start, ins.offset, start, ins.objectid, | 7119 | /* |
7120 | ins.offset, ins.offset, ins.offset, 0); | 7120 | * Create the ordered extent before the extent map. This is to avoid |
7121 | if (IS_ERR(em)) { | 7121 | * races with the fast fsync path that would lead to it logging file |
7122 | btrfs_free_reserved_extent(root, ins.objectid, ins.offset, 1); | 7122 | * extent items that point to disk extents that were not yet written to. |
7123 | return em; | 7123 | * The fast fsync path collects ordered extents into a local list and |
7124 | } | 7124 | * then collects all the new extent maps, so we must create the ordered |
7125 | 7125 | * extent first and make sure the fast fsync path collects any new | |
7126 | * ordered extents after collecting new extent maps as well. | ||
7127 | * The fsync path simply can not rely on inode_dio_wait() because it | ||
7128 | * causes deadlock with AIO. | ||
7129 | */ | ||
7126 | ret = btrfs_add_ordered_extent_dio(inode, start, ins.objectid, | 7130 | ret = btrfs_add_ordered_extent_dio(inode, start, ins.objectid, |
7127 | ins.offset, ins.offset, 0); | 7131 | ins.offset, ins.offset, 0); |
7128 | if (ret) { | 7132 | if (ret) { |
7129 | btrfs_free_reserved_extent(root, ins.objectid, ins.offset, 1); | 7133 | btrfs_free_reserved_extent(root, ins.objectid, ins.offset, 1); |
7130 | free_extent_map(em); | ||
7131 | return ERR_PTR(ret); | 7134 | return ERR_PTR(ret); |
7132 | } | 7135 | } |
7133 | 7136 | ||
7137 | em = create_pinned_em(inode, start, ins.offset, start, ins.objectid, | ||
7138 | ins.offset, ins.offset, ins.offset, 0); | ||
7139 | if (IS_ERR(em)) { | ||
7140 | struct btrfs_ordered_extent *oe; | ||
7141 | |||
7142 | btrfs_free_reserved_extent(root, ins.objectid, ins.offset, 1); | ||
7143 | oe = btrfs_lookup_ordered_extent(inode, start); | ||
7144 | ASSERT(oe); | ||
7145 | if (WARN_ON(!oe)) | ||
7146 | return em; | ||
7147 | set_bit(BTRFS_ORDERED_IOERR, &oe->flags); | ||
7148 | set_bit(BTRFS_ORDERED_IO_DONE, &oe->flags); | ||
7149 | btrfs_remove_ordered_extent(inode, oe); | ||
7150 | /* Once for our lookup and once for the ordered extents tree. */ | ||
7151 | btrfs_put_ordered_extent(oe); | ||
7152 | btrfs_put_ordered_extent(oe); | ||
7153 | } | ||
7134 | return em; | 7154 | return em; |
7135 | } | 7155 | } |
7136 | 7156 | ||