summaryrefslogtreecommitdiffstats
path: root/fs/btrfs/inode.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2016-02-18 03:28:03 -0500
committerIngo Molnar <mingo@kernel.org>2016-02-18 03:28:03 -0500
commit3a2f2ac9b96f9a9f5538396a212d3b9fb543bfc5 (patch)
tree294c2f340b11584e58cea90adfc4182ac8742348 /fs/btrfs/inode.c
parent4e79e182b419172e35936a47f098509092d69817 (diff)
parentf4eafd8bcd5229e998aa252627703b8462c3b90f (diff)
Merge branch 'x86/urgent' into x86/asm, to pick up fixes
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r--fs/btrfs/inode.c50
1 files changed, 41 insertions, 9 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index e28f3d4691af..151b7c71b868 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -5717,6 +5717,7 @@ static int btrfs_real_readdir(struct file *file, struct dir_context *ctx)
5717 char *name_ptr; 5717 char *name_ptr;
5718 int name_len; 5718 int name_len;
5719 int is_curr = 0; /* ctx->pos points to the current index? */ 5719 int is_curr = 0; /* ctx->pos points to the current index? */
5720 bool emitted;
5720 5721
5721 /* FIXME, use a real flag for deciding about the key type */ 5722 /* FIXME, use a real flag for deciding about the key type */
5722 if (root->fs_info->tree_root == root) 5723 if (root->fs_info->tree_root == root)
@@ -5745,6 +5746,7 @@ static int btrfs_real_readdir(struct file *file, struct dir_context *ctx)
5745 if (ret < 0) 5746 if (ret < 0)
5746 goto err; 5747 goto err;
5747 5748
5749 emitted = false;
5748 while (1) { 5750 while (1) {
5749 leaf = path->nodes[0]; 5751 leaf = path->nodes[0];
5750 slot = path->slots[0]; 5752 slot = path->slots[0];
@@ -5824,6 +5826,7 @@ skip:
5824 5826
5825 if (over) 5827 if (over)
5826 goto nopos; 5828 goto nopos;
5829 emitted = true;
5827 di_len = btrfs_dir_name_len(leaf, di) + 5830 di_len = btrfs_dir_name_len(leaf, di) +
5828 btrfs_dir_data_len(leaf, di) + sizeof(*di); 5831 btrfs_dir_data_len(leaf, di) + sizeof(*di);
5829 di_cur += di_len; 5832 di_cur += di_len;
@@ -5836,11 +5839,20 @@ next:
5836 if (key_type == BTRFS_DIR_INDEX_KEY) { 5839 if (key_type == BTRFS_DIR_INDEX_KEY) {
5837 if (is_curr) 5840 if (is_curr)
5838 ctx->pos++; 5841 ctx->pos++;
5839 ret = btrfs_readdir_delayed_dir_index(ctx, &ins_list); 5842 ret = btrfs_readdir_delayed_dir_index(ctx, &ins_list, &emitted);
5840 if (ret) 5843 if (ret)
5841 goto nopos; 5844 goto nopos;
5842 } 5845 }
5843 5846
5847 /*
5848 * If we haven't emitted any dir entry, we must not touch ctx->pos as
5849 * it was was set to the termination value in previous call. We assume
5850 * that "." and ".." were emitted if we reach this point and set the
5851 * termination value as well for an empty directory.
5852 */
5853 if (ctx->pos > 2 && !emitted)
5854 goto nopos;
5855
5844 /* Reached end of directory/root. Bump pos past the last item. */ 5856 /* Reached end of directory/root. Bump pos past the last item. */
5845 ctx->pos++; 5857 ctx->pos++;
5846 5858
@@ -7116,21 +7128,41 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode,
7116 if (ret) 7128 if (ret)
7117 return ERR_PTR(ret); 7129 return ERR_PTR(ret);
7118 7130
7119 em = create_pinned_em(inode, start, ins.offset, start, ins.objectid, 7131 /*
7120 ins.offset, ins.offset, ins.offset, 0); 7132 * Create the ordered extent before the extent map. This is to avoid
7121 if (IS_ERR(em)) { 7133 * races with the fast fsync path that would lead to it logging file
7122 btrfs_free_reserved_extent(root, ins.objectid, ins.offset, 1); 7134 * extent items that point to disk extents that were not yet written to.
7123 return em; 7135 * The fast fsync path collects ordered extents into a local list and
7124 } 7136 * then collects all the new extent maps, so we must create the ordered
7125 7137 * extent first and make sure the fast fsync path collects any new
7138 * ordered extents after collecting new extent maps as well.
7139 * The fsync path simply can not rely on inode_dio_wait() because it
7140 * causes deadlock with AIO.
7141 */
7126 ret = btrfs_add_ordered_extent_dio(inode, start, ins.objectid, 7142 ret = btrfs_add_ordered_extent_dio(inode, start, ins.objectid,
7127 ins.offset, ins.offset, 0); 7143 ins.offset, ins.offset, 0);
7128 if (ret) { 7144 if (ret) {
7129 btrfs_free_reserved_extent(root, ins.objectid, ins.offset, 1); 7145 btrfs_free_reserved_extent(root, ins.objectid, ins.offset, 1);
7130 free_extent_map(em);
7131 return ERR_PTR(ret); 7146 return ERR_PTR(ret);
7132 } 7147 }
7133 7148
7149 em = create_pinned_em(inode, start, ins.offset, start, ins.objectid,
7150 ins.offset, ins.offset, ins.offset, 0);
7151 if (IS_ERR(em)) {
7152 struct btrfs_ordered_extent *oe;
7153
7154 btrfs_free_reserved_extent(root, ins.objectid, ins.offset, 1);
7155 oe = btrfs_lookup_ordered_extent(inode, start);
7156 ASSERT(oe);
7157 if (WARN_ON(!oe))
7158 return em;
7159 set_bit(BTRFS_ORDERED_IOERR, &oe->flags);
7160 set_bit(BTRFS_ORDERED_IO_DONE, &oe->flags);
7161 btrfs_remove_ordered_extent(inode, oe);
7162 /* Once for our lookup and once for the ordered extents tree. */
7163 btrfs_put_ordered_extent(oe);
7164 btrfs_put_ordered_extent(oe);
7165 }
7134 return em; 7166 return em;
7135} 7167}
7136 7168