diff options
-rw-r--r-- | fs/btrfs/inode.c | 36 | ||||
-rw-r--r-- | fs/btrfs/tree-log.c | 14 |
2 files changed, 39 insertions, 11 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index b8bb7591ff9f..e4565456eb01 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -7115,21 +7115,41 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode, | |||
7115 | if (ret) | 7115 | if (ret) |
7116 | return ERR_PTR(ret); | 7116 | return ERR_PTR(ret); |
7117 | 7117 | ||
7118 | em = create_pinned_em(inode, start, ins.offset, start, ins.objectid, | 7118 | /* |
7119 | ins.offset, ins.offset, ins.offset, 0); | 7119 | * Create the ordered extent before the extent map. This is to avoid |
7120 | if (IS_ERR(em)) { | 7120 | * races with the fast fsync path that would lead to it logging file |
7121 | btrfs_free_reserved_extent(root, ins.objectid, ins.offset, 1); | 7121 | * extent items that point to disk extents that were not yet written to. |
7122 | return em; | 7122 | * The fast fsync path collects ordered extents into a local list and |
7123 | } | 7123 | * then collects all the new extent maps, so we must create the ordered |
7124 | 7124 | * extent first and make sure the fast fsync path collects any new | |
7125 | * ordered extents after collecting new extent maps as well. | ||
7126 | * The fsync path simply can not rely on inode_dio_wait() because it | ||
7127 | * causes deadlock with AIO. | ||
7128 | */ | ||
7125 | ret = btrfs_add_ordered_extent_dio(inode, start, ins.objectid, | 7129 | ret = btrfs_add_ordered_extent_dio(inode, start, ins.objectid, |
7126 | ins.offset, ins.offset, 0); | 7130 | ins.offset, ins.offset, 0); |
7127 | if (ret) { | 7131 | if (ret) { |
7128 | btrfs_free_reserved_extent(root, ins.objectid, ins.offset, 1); | 7132 | btrfs_free_reserved_extent(root, ins.objectid, ins.offset, 1); |
7129 | free_extent_map(em); | ||
7130 | return ERR_PTR(ret); | 7133 | return ERR_PTR(ret); |
7131 | } | 7134 | } |
7132 | 7135 | ||
7136 | em = create_pinned_em(inode, start, ins.offset, start, ins.objectid, | ||
7137 | ins.offset, ins.offset, ins.offset, 0); | ||
7138 | if (IS_ERR(em)) { | ||
7139 | struct btrfs_ordered_extent *oe; | ||
7140 | |||
7141 | btrfs_free_reserved_extent(root, ins.objectid, ins.offset, 1); | ||
7142 | oe = btrfs_lookup_ordered_extent(inode, start); | ||
7143 | ASSERT(oe); | ||
7144 | if (WARN_ON(!oe)) | ||
7145 | return em; | ||
7146 | set_bit(BTRFS_ORDERED_IOERR, &oe->flags); | ||
7147 | set_bit(BTRFS_ORDERED_IO_DONE, &oe->flags); | ||
7148 | btrfs_remove_ordered_extent(inode, oe); | ||
7149 | /* Once for our lookup and once for the ordered extents tree. */ | ||
7150 | btrfs_put_ordered_extent(oe); | ||
7151 | btrfs_put_ordered_extent(oe); | ||
7152 | } | ||
7133 | return em; | 7153 | return em; |
7134 | } | 7154 | } |
7135 | 7155 | ||
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 323e12cc9d2f..978c3a810893 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
@@ -4127,7 +4127,9 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, | |||
4127 | struct inode *inode, | 4127 | struct inode *inode, |
4128 | struct btrfs_path *path, | 4128 | struct btrfs_path *path, |
4129 | struct list_head *logged_list, | 4129 | struct list_head *logged_list, |
4130 | struct btrfs_log_ctx *ctx) | 4130 | struct btrfs_log_ctx *ctx, |
4131 | const u64 start, | ||
4132 | const u64 end) | ||
4131 | { | 4133 | { |
4132 | struct extent_map *em, *n; | 4134 | struct extent_map *em, *n; |
4133 | struct list_head extents; | 4135 | struct list_head extents; |
@@ -4166,7 +4168,13 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, | |||
4166 | } | 4168 | } |
4167 | 4169 | ||
4168 | list_sort(NULL, &extents, extent_cmp); | 4170 | list_sort(NULL, &extents, extent_cmp); |
4169 | 4171 | /* | |
4172 | * Collect any new ordered extents within the range. This is to | ||
4173 | * prevent logging file extent items without waiting for the disk | ||
4174 | * location they point to being written. We do this only to deal | ||
4175 | * with races against concurrent lockless direct IO writes. | ||
4176 | */ | ||
4177 | btrfs_get_logged_extents(inode, logged_list, start, end); | ||
4170 | process: | 4178 | process: |
4171 | while (!list_empty(&extents)) { | 4179 | while (!list_empty(&extents)) { |
4172 | em = list_entry(extents.next, struct extent_map, list); | 4180 | em = list_entry(extents.next, struct extent_map, list); |
@@ -4701,7 +4709,7 @@ log_extents: | |||
4701 | goto out_unlock; | 4709 | goto out_unlock; |
4702 | } | 4710 | } |
4703 | ret = btrfs_log_changed_extents(trans, root, inode, dst_path, | 4711 | ret = btrfs_log_changed_extents(trans, root, inode, dst_path, |
4704 | &logged_list, ctx); | 4712 | &logged_list, ctx, start, end); |
4705 | if (ret) { | 4713 | if (ret) { |
4706 | err = ret; | 4714 | err = ret; |
4707 | goto out_unlock; | 4715 | goto out_unlock; |