Merge branch 'for-linus-4.8' of git://git.kernel.org/pub/scm/linux/kernel/git/mason...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 10 Aug 2016 18:16:03 +0000 (11:16 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 10 Aug 2016 18:16:03 +0000 (11:16 -0700)
Pull btrfs fixes from Chris Mason:
 "Some fixes for btrfs send/recv and fsync from Filipe and Robbie Ko.

  Bonus points to Filipe for already having xfstests in place for many
  of these"

* 'for-linus-4.8' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs:
  Btrfs: remove unused function btrfs_add_delayed_qgroup_reserve()
  Btrfs: improve performance on fsync against new inode after rename/unlink
  Btrfs: be more precise on errors when getting an inode from disk
  Btrfs: send, don't bug on inconsistent snapshots
  Btrfs: send, avoid incorrect leaf accesses when sending utimes operations
  Btrfs: send, fix invalid leaf accesses due to incorrect utimes operations
  Btrfs: send, fix warning due to late freeing of orphan_dir_info structures
  Btrfs: incremental send, fix premature rmdir operations
  Btrfs: incremental send, fix invalid paths for rename operations
  Btrfs: send, add missing error check for calls to path_loop()
  Btrfs: send, fix failure to move directories with the same name around
  Btrfs: add missing check for writeback errors on fsync

1  2 
fs/btrfs/inode.c

diff --combined fs/btrfs/inode.c
index 2f5975954ccf198737e07b29c8706024114a78ae,29636624a42797388d25a9671f0c1440fe1bedbd..08dfc57e22705363f1159def79316263a9f4293a
@@@ -1831,7 -1831,7 +1831,7 @@@ static void btrfs_clear_bit_hook(struc
   * return 0 if page can be merged to bio
   * return error otherwise
   */
 -int btrfs_merge_bio_hook(int rw, struct page *page, unsigned long offset,
 +int btrfs_merge_bio_hook(struct page *page, unsigned long offset,
                         size_t size, struct bio *bio,
                         unsigned long bio_flags)
  {
  
        length = bio->bi_iter.bi_size;
        map_length = length;
 -      ret = btrfs_map_block(root->fs_info, rw, logical,
 +      ret = btrfs_map_block(root->fs_info, bio_op(bio), logical,
                              &map_length, NULL, 0);
        if (ret < 0)
                return ret;
   * At IO completion time the cums attached on the ordered extent record
   * are inserted into the btree
   */
 -static int __btrfs_submit_bio_start(struct inode *inode, int rw,
 -                                  struct bio *bio, int mirror_num,
 -                                  unsigned long bio_flags,
 +static int __btrfs_submit_bio_start(struct inode *inode, struct bio *bio,
 +                                  int mirror_num, unsigned long bio_flags,
                                    u64 bio_offset)
  {
        struct btrfs_root *root = BTRFS_I(inode)->root;
   * At IO completion time the cums attached on the ordered extent record
   * are inserted into the btree
   */
 -static int __btrfs_submit_bio_done(struct inode *inode, int rw, struct bio *bio,
 +static int __btrfs_submit_bio_done(struct inode *inode, struct bio *bio,
                          int mirror_num, unsigned long bio_flags,
                          u64 bio_offset)
  {
        struct btrfs_root *root = BTRFS_I(inode)->root;
        int ret;
  
 -      ret = btrfs_map_bio(root, rw, bio, mirror_num, 1);
 +      ret = btrfs_map_bio(root, bio, mirror_num, 1);
        if (ret) {
                bio->bi_error = ret;
                bio_endio(bio);
   * extent_io.c submission hook. This does the right thing for csum calculation
   * on write, or reading the csums from the tree before a read
   */
 -static int btrfs_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
 +static int btrfs_submit_bio_hook(struct inode *inode, struct bio *bio,
                          int mirror_num, unsigned long bio_flags,
                          u64 bio_offset)
  {
        if (btrfs_is_free_space_inode(inode))
                metadata = BTRFS_WQ_ENDIO_FREE_SPACE;
  
 -      if (!(rw & REQ_WRITE)) {
 +      if (bio_op(bio) != REQ_OP_WRITE) {
                ret = btrfs_bio_wq_end_io(root->fs_info, bio, metadata);
                if (ret)
                        goto out;
                        goto mapit;
                /* we're doing a write, do the async checksumming */
                ret = btrfs_wq_submit_bio(BTRFS_I(inode)->root->fs_info,
 -                                 inode, rw, bio, mirror_num,
 +                                 inode, bio, mirror_num,
                                   bio_flags, bio_offset,
                                   __btrfs_submit_bio_start,
                                   __btrfs_submit_bio_done);
        }
  
  mapit:
 -      ret = btrfs_map_bio(root, rw, bio, mirror_num, 0);
 +      ret = btrfs_map_bio(root, bio, mirror_num, 0);
  
  out:
        if (ret < 0) {
@@@ -3435,10 -3436,10 +3435,10 @@@ int btrfs_orphan_cleanup(struct btrfs_r
                found_key.offset = 0;
                inode = btrfs_iget(root->fs_info->sb, &found_key, root, NULL);
                ret = PTR_ERR_OR_ZERO(inode);
-               if (ret && ret != -ESTALE)
+               if (ret && ret != -ENOENT)
                        goto out;
  
-               if (ret == -ESTALE && root == root->fs_info->tree_root) {
+               if (ret == -ENOENT && root == root->fs_info->tree_root) {
                        struct btrfs_root *dead_root;
                        struct btrfs_fs_info *fs_info = root->fs_info;
                        int is_dead_root = 0;
                 * Inode is already gone but the orphan item is still there,
                 * kill the orphan item.
                 */
-               if (ret == -ESTALE) {
+               if (ret == -ENOENT) {
                        trans = btrfs_start_transaction(root, 1);
                        if (IS_ERR(trans)) {
                                ret = PTR_ERR(trans);
@@@ -3633,7 -3634,7 +3633,7 @@@ static noinline int acls_after_inode_it
  /*
   * read an inode from the btree into the in-memory inode
   */
- static void btrfs_read_locked_inode(struct inode *inode)
+ static int btrfs_read_locked_inode(struct inode *inode)
  {
        struct btrfs_path *path;
        struct extent_buffer *leaf;
                filled = true;
  
        path = btrfs_alloc_path();
-       if (!path)
+       if (!path) {
+               ret = -ENOMEM;
                goto make_bad;
+       }
  
        memcpy(&location, &BTRFS_I(inode)->location, sizeof(location));
  
        ret = btrfs_lookup_inode(NULL, root, path, &location, 0);
-       if (ret)
+       if (ret) {
+               if (ret > 0)
+                       ret = -ENOENT;
                goto make_bad;
+       }
  
        leaf = path->nodes[0];
  
@@@ -3812,11 -3818,12 +3817,12 @@@ cache_acl
        }
  
        btrfs_update_iflags(inode);
-       return;
+       return 0;
  
  make_bad:
        btrfs_free_path(path);
        make_bad_inode(inode);
+       return ret;
  }
  
  /*
@@@ -4204,6 -4211,7 +4210,7 @@@ static int btrfs_rmdir(struct inode *di
        int err = 0;
        struct btrfs_root *root = BTRFS_I(dir)->root;
        struct btrfs_trans_handle *trans;
+       u64 last_unlink_trans;
  
        if (inode->i_size > BTRFS_EMPTY_DIR_SIZE)
                return -ENOTEMPTY;
        if (err)
                goto out;
  
+       last_unlink_trans = BTRFS_I(inode)->last_unlink_trans;
        /* now the directory is empty */
        err = btrfs_unlink_inode(trans, root, dir, d_inode(dentry),
                                 dentry->d_name.name, dentry->d_name.len);
-       if (!err)
+       if (!err) {
                btrfs_i_size_write(inode, 0);
+               /*
+                * Propagate the last_unlink_trans value of the deleted dir to
+                * its parent directory. This is to prevent an unrecoverable
+                * log tree in the case we do something like this:
+                * 1) create dir foo
+                * 2) create snapshot under dir foo
+                * 3) delete the snapshot
+                * 4) rmdir foo
+                * 5) mkdir foo
+                * 6) fsync foo or some file inside foo
+                */
+               if (last_unlink_trans >= trans->transid)
+                       BTRFS_I(dir)->last_unlink_trans = last_unlink_trans;
+       }
  out:
        btrfs_end_transaction(trans, root);
        btrfs_btree_balance_dirty(root);
@@@ -5606,7 -5630,9 +5629,9 @@@ struct inode *btrfs_iget(struct super_b
                return ERR_PTR(-ENOMEM);
  
        if (inode->i_state & I_NEW) {
-               btrfs_read_locked_inode(inode);
+               int ret;
+               ret = btrfs_read_locked_inode(inode);
                if (!is_bad_inode(inode)) {
                        inode_tree_add(inode);
                        unlock_new_inode(inode);
                } else {
                        unlock_new_inode(inode);
                        iput(inode);
-                       inode = ERR_PTR(-ESTALE);
+                       ASSERT(ret < 0);
+                       inode = ERR_PTR(ret < 0 ? ret : -ESTALE);
                }
        }
  
  }
  
  static inline int submit_dio_repair_bio(struct inode *inode, struct bio *bio,
 -                                      int rw, int mirror_num)
 +                                      int mirror_num)
  {
        struct btrfs_root *root = BTRFS_I(inode)->root;
        int ret;
  
 -      BUG_ON(rw & REQ_WRITE);
 +      BUG_ON(bio_op(bio) == REQ_OP_WRITE);
  
        bio_get(bio);
  
        if (ret)
                goto err;
  
 -      ret = btrfs_map_bio(root, rw, bio, mirror_num, 0);
 +      ret = btrfs_map_bio(root, bio, mirror_num, 0);
  err:
        bio_put(bio);
        return ret;
@@@ -7866,7 -7893,7 +7892,7 @@@ static int dio_read_error(struct inode 
        int read_mode;
        int ret;
  
 -      BUG_ON(failed_bio->bi_rw & REQ_WRITE);
 +      BUG_ON(bio_op(failed_bio) == REQ_OP_WRITE);
  
        ret = btrfs_get_io_failure_record(inode, start, end, &failrec);
        if (ret)
                free_io_failure(inode, failrec);
                return -EIO;
        }
 +      bio_set_op_attrs(bio, REQ_OP_READ, read_mode);
  
        btrfs_debug(BTRFS_I(inode)->root->fs_info,
                    "Repair DIO Read Error: submitting new dio read[%#x] to this_mirror=%d, in_validation=%d\n",
                    read_mode, failrec->this_mirror, failrec->in_validation);
  
 -      ret = submit_dio_repair_bio(inode, bio, read_mode,
 -                                  failrec->this_mirror);
 +      ret = submit_dio_repair_bio(inode, bio, failrec->this_mirror);
        if (ret) {
                free_io_failure(inode, failrec);
                bio_put(bio);
@@@ -8190,7 -8217,7 +8216,7 @@@ static void btrfs_endio_direct_write(st
        bio_put(bio);
  }
  
 -static int __btrfs_submit_bio_start_direct_io(struct inode *inode, int rw,
 +static int __btrfs_submit_bio_start_direct_io(struct inode *inode,
                                    struct bio *bio, int mirror_num,
                                    unsigned long bio_flags, u64 offset)
  {
@@@ -8208,8 -8235,8 +8234,8 @@@ static void btrfs_end_dio_bio(struct bi
  
        if (err)
                btrfs_warn(BTRFS_I(dip->inode)->root->fs_info,
 -                         "direct IO failed ino %llu rw %lu sector %#Lx len %u err no %d",
 -                         btrfs_ino(dip->inode), bio->bi_rw,
 +                         "direct IO failed ino %llu rw %d,%u sector %#Lx len %u err no %d",
 +                         btrfs_ino(dip->inode), bio_op(bio), bio->bi_opf,
                           (unsigned long long)bio->bi_iter.bi_sector,
                           bio->bi_iter.bi_size, err);
  
@@@ -8283,11 -8310,11 +8309,11 @@@ static inline int btrfs_lookup_and_bind
  }
  
  static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode,
 -                                       int rw, u64 file_offset, int skip_sum,
 +                                       u64 file_offset, int skip_sum,
                                         int async_submit)
  {
        struct btrfs_dio_private *dip = bio->bi_private;
 -      int write = rw & REQ_WRITE;
 +      bool write = bio_op(bio) == REQ_OP_WRITE;
        struct btrfs_root *root = BTRFS_I(inode)->root;
        int ret;
  
  
        if (write && async_submit) {
                ret = btrfs_wq_submit_bio(root->fs_info,
 -                                 inode, rw, bio, 0, 0,
 -                                 file_offset,
 +                                 inode, bio, 0, 0, file_offset,
                                   __btrfs_submit_bio_start_direct_io,
                                   __btrfs_submit_bio_done);
                goto err;
                        goto err;
        }
  map:
 -      ret = btrfs_map_bio(root, rw, bio, 0, async_submit);
 +      ret = btrfs_map_bio(root, bio, 0, async_submit);
  err:
        bio_put(bio);
        return ret;
  }
  
 -static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip,
 +static int btrfs_submit_direct_hook(struct btrfs_dio_private *dip,
                                    int skip_sum)
  {
        struct inode *inode = dip->inode;
        int i;
  
        map_length = orig_bio->bi_iter.bi_size;
 -      ret = btrfs_map_block(root->fs_info, rw, start_sector << 9,
 -                            &map_length, NULL, 0);
 +      ret = btrfs_map_block(root->fs_info, bio_op(orig_bio),
 +                            start_sector << 9, &map_length, NULL, 0);
        if (ret)
                return -EIO;
  
        if (!bio)
                return -ENOMEM;
  
 +      bio_set_op_attrs(bio, bio_op(orig_bio), orig_bio->bi_opf);
        bio->bi_private = dip;
        bio->bi_end_io = btrfs_end_dio_bio;
        btrfs_io_bio(bio)->logical = file_offset;
@@@ -8393,7 -8420,7 +8419,7 @@@ next_block
                         * before we're done setting it up
                         */
                        atomic_inc(&dip->pending_bios);
 -                      ret = __btrfs_submit_dio_bio(bio, inode, rw,
 +                      ret = __btrfs_submit_dio_bio(bio, inode,
                                                     file_offset, skip_sum,
                                                     async_submit);
                        if (ret) {
                                                  start_sector, GFP_NOFS);
                        if (!bio)
                                goto out_err;
 +                      bio_set_op_attrs(bio, bio_op(orig_bio), orig_bio->bi_opf);
                        bio->bi_private = dip;
                        bio->bi_end_io = btrfs_end_dio_bio;
                        btrfs_io_bio(bio)->logical = file_offset;
  
                        map_length = orig_bio->bi_iter.bi_size;
 -                      ret = btrfs_map_block(root->fs_info, rw,
 +                      ret = btrfs_map_block(root->fs_info, bio_op(orig_bio),
                                              start_sector << 9,
                                              &map_length, NULL, 0);
                        if (ret) {
        }
  
  submit:
 -      ret = __btrfs_submit_dio_bio(bio, inode, rw, file_offset, skip_sum,
 +      ret = __btrfs_submit_dio_bio(bio, inode, file_offset, skip_sum,
                                     async_submit);
        if (!ret)
                return 0;
@@@ -8457,14 -8483,14 +8483,14 @@@ out_err
        return 0;
  }
  
 -static void btrfs_submit_direct(int rw, struct bio *dio_bio,
 -                              struct inode *inode, loff_t file_offset)
 +static void btrfs_submit_direct(struct bio *dio_bio, struct inode *inode,
 +                              loff_t file_offset)
  {
        struct btrfs_dio_private *dip = NULL;
        struct bio *io_bio = NULL;
        struct btrfs_io_bio *btrfs_bio;
        int skip_sum;
 -      int write = rw & REQ_WRITE;
 +      bool write = (bio_op(dio_bio) == REQ_OP_WRITE);
        int ret = 0;
  
        skip_sum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM;
                        dio_data->unsubmitted_oe_range_end;
        }
  
 -      ret = btrfs_submit_direct_hook(rw, dip, skip_sum);
 +      ret = btrfs_submit_direct_hook(dip, skip_sum);
        if (!ret)
                return;
  
This page took 0.055041 seconds and 5 git commands to generate.