Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 12 Sep 2014 18:53:30 +0000 (11:53 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 12 Sep 2014 18:53:30 +0000 (11:53 -0700)
Pull btrfs fixes from Chris Mason:
 "Filipe is doing a careful pass through fsync problems, and these are
  the fixes so far.  I'll have one more for rc6 that we're still
  testing.

  My big commit is fixing up some inode hash races that Al Viro found
  (thanks Al)"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs:
  Btrfs: use insert_inode_locked4 for inode creation
  Btrfs: fix fsync data loss after a ranged fsync
  Btrfs: kfree()ing ERR_PTRs
  Btrfs: fix crash while doing a ranged fsync
  Btrfs: fix corruption after write/fsync failure + fsync + log recovery
  Btrfs: fix autodefrag with compression

1  2 
fs/btrfs/inode.c

diff --combined fs/btrfs/inode.c
index 9c194bd74d6e513c075b077b62ee1754cd02e966,214b936bdd3d95e359dcca7346699d0bb2a62b6b..016c403bfe7e4241b33c6b6c3e4101ba5ea993b2
@@@ -778,8 -778,12 +778,12 @@@ retry
                                                ins.offset,
                                                BTRFS_ORDERED_COMPRESSED,
                                                async_extent->compress_type);
-               if (ret)
+               if (ret) {
+                       btrfs_drop_extent_cache(inode, async_extent->start,
+                                               async_extent->start +
+                                               async_extent->ram_size - 1, 0);
                        goto out_free_reserve;
+               }
  
                /*
                 * clear dirty, set writeback and unlock the pages.
@@@ -971,14 -975,14 +975,14 @@@ static noinline int cow_file_range(stru
                ret = btrfs_add_ordered_extent(inode, start, ins.objectid,
                                               ram_size, cur_alloc_size, 0);
                if (ret)
-                       goto out_reserve;
+                       goto out_drop_extent_cache;
  
                if (root->root_key.objectid ==
                    BTRFS_DATA_RELOC_TREE_OBJECTID) {
                        ret = btrfs_reloc_clone_csums(inode, start,
                                                      cur_alloc_size);
                        if (ret)
-                               goto out_reserve;
+                               goto out_drop_extent_cache;
                }
  
                if (disk_num_bytes < cur_alloc_size)
  out:
        return ret;
  
+ out_drop_extent_cache:
+       btrfs_drop_extent_cache(inode, start, start + ram_size - 1, 0);
  out_reserve:
        btrfs_free_reserved_extent(root, ins.objectid, ins.offset, 1);
  out_unlock:
@@@ -4242,7 -4248,8 +4248,8 @@@ out
                        btrfs_abort_transaction(trans, root, ret);
        }
  error:
-       if (last_size != (u64)-1)
+       if (last_size != (u64)-1 &&
+           root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID)
                btrfs_ordered_update_i_size(inode, last_size, NULL);
        btrfs_free_path(path);
        return err;
@@@ -5627,6 -5634,17 +5634,17 @@@ int btrfs_set_inode_index(struct inode 
        return ret;
  }
  
+ static int btrfs_insert_inode_locked(struct inode *inode)
+ {
+       struct btrfs_iget_args args;
+       args.location = &BTRFS_I(inode)->location;
+       args.root = BTRFS_I(inode)->root;
+       return insert_inode_locked4(inode,
+                  btrfs_inode_hash(inode->i_ino, BTRFS_I(inode)->root),
+                  btrfs_find_actor, &args);
+ }
  static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
                                     struct btrfs_root *root,
                                     struct inode *dir,
                sizes[1] = name_len + sizeof(*ref);
        }
  
+       location = &BTRFS_I(inode)->location;
+       location->objectid = objectid;
+       location->offset = 0;
+       btrfs_set_key_type(location, BTRFS_INODE_ITEM_KEY);
+       ret = btrfs_insert_inode_locked(inode);
+       if (ret < 0)
+               goto fail;
        path->leave_spinning = 1;
        ret = btrfs_insert_empty_items(trans, root, path, key, sizes, nitems);
        if (ret != 0)
-               goto fail;
+               goto fail_unlock;
  
        inode_init_owner(inode, dir, mode);
        inode_set_bytes(inode, 0);
        btrfs_mark_buffer_dirty(path->nodes[0]);
        btrfs_free_path(path);
  
-       location = &BTRFS_I(inode)->location;
-       location->objectid = objectid;
-       location->offset = 0;
-       btrfs_set_key_type(location, BTRFS_INODE_ITEM_KEY);
        btrfs_inherit_iflags(inode, dir);
  
        if (S_ISREG(mode)) {
                                BTRFS_INODE_NODATASUM;
        }
  
-       btrfs_insert_inode_hash(inode);
        inode_tree_add(inode);
  
        trace_btrfs_inode_new(inode);
                          btrfs_ino(inode), root->root_key.objectid, ret);
  
        return inode;
+ fail_unlock:
+       unlock_new_inode(inode);
  fail:
        if (dir && name)
                BTRFS_I(dir)->index_cnt--;
@@@ -5909,28 -5933,28 +5933,28 @@@ static int btrfs_mknod(struct inode *di
                goto out_unlock;
        }
  
-       err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
-       if (err) {
-               drop_inode = 1;
-               goto out_unlock;
-       }
        /*
        * If the active LSM wants to access the inode during
        * d_instantiate it needs these. Smack checks to see
        * if the filesystem supports xattrs by looking at the
        * ops vector.
        */
        inode->i_op = &btrfs_special_inode_operations;
-       err = btrfs_add_nondir(trans, dir, dentry, inode, 0, index);
+       init_special_inode(inode, inode->i_mode, rdev);
+       err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
        if (err)
-               drop_inode = 1;
-       else {
-               init_special_inode(inode, inode->i_mode, rdev);
+               goto out_unlock_inode;
+       err = btrfs_add_nondir(trans, dir, dentry, inode, 0, index);
+       if (err) {
+               goto out_unlock_inode;
+       } else {
                btrfs_update_inode(trans, root, inode);
+               unlock_new_inode(inode);
                d_instantiate(dentry, inode);
        }
  out_unlock:
        btrfs_end_transaction(trans, root);
        btrfs_balance_delayed_items(root);
                iput(inode);
        }
        return err;
+ out_unlock_inode:
+       drop_inode = 1;
+       unlock_new_inode(inode);
+       goto out_unlock;
  }
  
  static int btrfs_create(struct inode *dir, struct dentry *dentry,
                goto out_unlock;
        }
        drop_inode_on_err = 1;
-       err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
-       if (err)
-               goto out_unlock;
-       err = btrfs_update_inode(trans, root, inode);
-       if (err)
-               goto out_unlock;
        /*
        * If the active LSM wants to access the inode during
        * d_instantiate it needs these. Smack checks to see
        */
        inode->i_fop = &btrfs_file_operations;
        inode->i_op = &btrfs_file_inode_operations;
+       inode->i_mapping->a_ops = &btrfs_aops;
+       inode->i_mapping->backing_dev_info = &root->fs_info->bdi;
+       err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
+       if (err)
+               goto out_unlock_inode;
+       err = btrfs_update_inode(trans, root, inode);
+       if (err)
+               goto out_unlock_inode;
  
        err = btrfs_add_nondir(trans, dir, dentry, inode, 0, index);
        if (err)
-               goto out_unlock;
+               goto out_unlock_inode;
  
-       inode->i_mapping->a_ops = &btrfs_aops;
-       inode->i_mapping->backing_dev_info = &root->fs_info->bdi;
        BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
+       unlock_new_inode(inode);
        d_instantiate(dentry, inode);
  
  out_unlock:
        btrfs_balance_delayed_items(root);
        btrfs_btree_balance_dirty(root);
        return err;
+ out_unlock_inode:
+       unlock_new_inode(inode);
+       goto out_unlock;
  }
  
  static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
@@@ -6117,25 -6152,30 +6152,30 @@@ static int btrfs_mkdir(struct inode *di
        }
  
        drop_on_err = 1;
+       /* these must be set before we unlock the inode */
+       inode->i_op = &btrfs_dir_inode_operations;
+       inode->i_fop = &btrfs_dir_file_operations;
  
        err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
        if (err)
-               goto out_fail;
-       inode->i_op = &btrfs_dir_inode_operations;
-       inode->i_fop = &btrfs_dir_file_operations;
+               goto out_fail_inode;
  
        btrfs_i_size_write(inode, 0);
        err = btrfs_update_inode(trans, root, inode);
        if (err)
-               goto out_fail;
+               goto out_fail_inode;
  
        err = btrfs_add_link(trans, dir, inode, dentry->d_name.name,
                             dentry->d_name.len, 0, index);
        if (err)
-               goto out_fail;
+               goto out_fail_inode;
  
        d_instantiate(dentry, inode);
+       /*
+        * mkdir is special.  We're unlocking after we call d_instantiate
+        * to avoid a race with nfsd calling d_instantiate.
+        */
+       unlock_new_inode(inode);
        drop_on_err = 0;
  
  out_fail:
        btrfs_balance_delayed_items(root);
        btrfs_btree_balance_dirty(root);
        return err;
+ out_fail_inode:
+       unlock_new_inode(inode);
+       goto out_fail;
  }
  
  /* helper for btfs_get_extent.  Given an existing extent in the tree,
@@@ -8100,6 -8144,7 +8144,7 @@@ int btrfs_create_subvol_root(struct btr
  
        set_nlink(inode, 1);
        btrfs_i_size_write(inode, 0);
+       unlock_new_inode(inode);
  
        err = btrfs_subvol_inherit_props(trans, new_root, parent_root);
        if (err)
@@@ -8506,16 -8551,6 +8551,16 @@@ out_notrans
        return ret;
  }
  
 +static int btrfs_rename2(struct inode *old_dir, struct dentry *old_dentry,
 +                       struct inode *new_dir, struct dentry *new_dentry,
 +                       unsigned int flags)
 +{
 +      if (flags & ~RENAME_NOREPLACE)
 +              return -EINVAL;
 +
 +      return btrfs_rename(old_dir, old_dentry, new_dir, new_dentry);
 +}
 +
  static void btrfs_run_delalloc_work(struct btrfs_work *work)
  {
        struct btrfs_delalloc_work *delalloc_work;
@@@ -8760,12 -8795,6 +8805,6 @@@ static int btrfs_symlink(struct inode *
                goto out_unlock;
        }
  
-       err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
-       if (err) {
-               drop_inode = 1;
-               goto out_unlock;
-       }
        /*
        * If the active LSM wants to access the inode during
        * d_instantiate it needs these. Smack checks to see
        */
        inode->i_fop = &btrfs_file_operations;
        inode->i_op = &btrfs_file_inode_operations;
+       inode->i_mapping->a_ops = &btrfs_aops;
+       inode->i_mapping->backing_dev_info = &root->fs_info->bdi;
+       BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
+       err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
+       if (err)
+               goto out_unlock_inode;
  
        err = btrfs_add_nondir(trans, dir, dentry, inode, 0, index);
        if (err)
-               drop_inode = 1;
-       else {
-               inode->i_mapping->a_ops = &btrfs_aops;
-               inode->i_mapping->backing_dev_info = &root->fs_info->bdi;
-               BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
-       }
-       if (drop_inode)
-               goto out_unlock;
+               goto out_unlock_inode;
  
        path = btrfs_alloc_path();
        if (!path) {
                err = -ENOMEM;
-               drop_inode = 1;
-               goto out_unlock;
+               goto out_unlock_inode;
        }
        key.objectid = btrfs_ino(inode);
        key.offset = 0;
        err = btrfs_insert_empty_item(trans, root, path, &key,
                                      datasize);
        if (err) {
-               drop_inode = 1;
                btrfs_free_path(path);
-               goto out_unlock;
+               goto out_unlock_inode;
        }
        leaf = path->nodes[0];
        ei = btrfs_item_ptr(leaf, path->slots[0],
        inode_set_bytes(inode, name_len);
        btrfs_i_size_write(inode, name_len);
        err = btrfs_update_inode(trans, root, inode);
-       if (err)
+       if (err) {
                drop_inode = 1;
+               goto out_unlock_inode;
+       }
+       unlock_new_inode(inode);
+       d_instantiate(dentry, inode);
  
  out_unlock:
-       if (!err)
-               d_instantiate(dentry, inode);
        btrfs_end_transaction(trans, root);
        if (drop_inode) {
                inode_dec_link_count(inode);
        }
        btrfs_btree_balance_dirty(root);
        return err;
+ out_unlock_inode:
+       drop_inode = 1;
+       unlock_new_inode(inode);
+       goto out_unlock;
  }
  
  static int __btrfs_prealloc_file_range(struct inode *inode, int mode,
@@@ -9021,14 -9056,6 +9066,6 @@@ static int btrfs_tmpfile(struct inode *
                goto out;
        }
  
-       ret = btrfs_init_inode_security(trans, inode, dir, NULL);
-       if (ret)
-               goto out;
-       ret = btrfs_update_inode(trans, root, inode);
-       if (ret)
-               goto out;
        inode->i_fop = &btrfs_file_operations;
        inode->i_op = &btrfs_file_inode_operations;
  
        inode->i_mapping->backing_dev_info = &root->fs_info->bdi;
        BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
  
+       ret = btrfs_init_inode_security(trans, inode, dir, NULL);
+       if (ret)
+               goto out_inode;
+       ret = btrfs_update_inode(trans, root, inode);
+       if (ret)
+               goto out_inode;
        ret = btrfs_orphan_add(trans, inode);
        if (ret)
-               goto out;
+               goto out_inode;
  
        /*
         * We set number of links to 0 in btrfs_new_inode(), and here we set
         *    d_tmpfile() -> inode_dec_link_count() -> drop_nlink()
         */
        set_nlink(inode, 1);
+       unlock_new_inode(inode);
        d_tmpfile(dentry, inode);
        mark_inode_dirty(inode);
  
                iput(inode);
        btrfs_balance_delayed_items(root);
        btrfs_btree_balance_dirty(root);
        return ret;
+ out_inode:
+       unlock_new_inode(inode);
+       goto out;
  }
  
  static const struct inode_operations btrfs_dir_inode_operations = {
        .link           = btrfs_link,
        .mkdir          = btrfs_mkdir,
        .rmdir          = btrfs_rmdir,
 -      .rename         = btrfs_rename,
 +      .rename2        = btrfs_rename2,
        .symlink        = btrfs_symlink,
        .setattr        = btrfs_setattr,
        .mknod          = btrfs_mknod,