]> git.proxmox.com Git - mirror_ubuntu-disco-kernel.git/commitdiff
Merge tag 'for-4.16-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 16 Feb 2018 17:26:18 +0000 (09:26 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 16 Feb 2018 17:26:18 +0000 (09:26 -0800)
Pull btrfs fixes from David Sterba:
 "We have a few assorted fixes, some of them show up during fstests so I
  gave them more testing"

* tag 'for-4.16-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
  btrfs: Fix use-after-free when cleaning up fs_devs with a single stale device
  Btrfs: fix null pointer dereference when replacing missing device
  btrfs: remove spurious WARN_ON(ref->count < 0) in find_parent_nodes
  btrfs: Ignore errors from btrfs_qgroup_trace_extent_post
  Btrfs: fix unexpected -EEXIST when creating new inode
  Btrfs: fix use-after-free on root->orphan_block_rsv
  Btrfs: fix btrfs_evict_inode to handle abnormal inodes correctly
  Btrfs: fix extent state leak from tree log
  Btrfs: fix crash due to not cleaning up tree log block's dirty bits
  Btrfs: fix deadlock in run_delalloc_nocow

1  2 
fs/btrfs/inode.c
fs/btrfs/tree-log.c

diff --combined fs/btrfs/inode.c
index 53ca025655fca690b5f92ef93eb0d11047a1a0cc,29b491328f4ee5286135b93108e38dd362f0ab65..a79299a89b7d0285328e29cecaaff51ff82c5be7
@@@ -43,7 -43,6 +43,7 @@@
  #include <linux/posix_acl_xattr.h>
  #include <linux/uio.h>
  #include <linux/magic.h>
 +#include <linux/iversion.h>
  #include "ctree.h"
  #include "disk-io.h"
  #include "transaction.h"
@@@ -1335,8 -1334,11 +1335,11 @@@ next_slot
                leaf = path->nodes[0];
                if (path->slots[0] >= btrfs_header_nritems(leaf)) {
                        ret = btrfs_next_leaf(root, path);
-                       if (ret < 0)
+                       if (ret < 0) {
+                               if (cow_start != (u64)-1)
+                                       cur_offset = cow_start;
                                goto error;
+                       }
                        if (ret > 0)
                                break;
                        leaf = path->nodes[0];
@@@ -3385,6 -3387,11 +3388,11 @@@ int btrfs_orphan_add(struct btrfs_trans
                ret = btrfs_orphan_reserve_metadata(trans, inode);
                ASSERT(!ret);
                if (ret) {
+                       /*
+                        * dec doesn't need spin_lock as ->orphan_block_rsv
+                        * would be released only if ->orphan_inodes is
+                        * zero.
+                        */
                        atomic_dec(&root->orphan_inodes);
                        clear_bit(BTRFS_INODE_ORPHAN_META_RESERVED,
                                  &inode->runtime_flags);
        if (insert >= 1) {
                ret = btrfs_insert_orphan_item(trans, root, btrfs_ino(inode));
                if (ret) {
-                       atomic_dec(&root->orphan_inodes);
                        if (reserve) {
                                clear_bit(BTRFS_INODE_ORPHAN_META_RESERVED,
                                          &inode->runtime_flags);
                                btrfs_orphan_release_metadata(inode);
                        }
+                       /*
+                        * btrfs_orphan_commit_root may race with us and set
+                        * ->orphan_block_rsv to zero, in order to avoid that,
+                        * decrease ->orphan_inodes after everything is done.
+                        */
+                       atomic_dec(&root->orphan_inodes);
                        if (ret != -EEXIST) {
                                clear_bit(BTRFS_INODE_HAS_ORPHAN_ITEM,
                                          &inode->runtime_flags);
@@@ -3436,28 -3448,26 +3449,26 @@@ static int btrfs_orphan_del(struct btrf
  {
        struct btrfs_root *root = inode->root;
        int delete_item = 0;
-       int release_rsv = 0;
        int ret = 0;
  
-       spin_lock(&root->orphan_lock);
        if (test_and_clear_bit(BTRFS_INODE_HAS_ORPHAN_ITEM,
                               &inode->runtime_flags))
                delete_item = 1;
  
+       if (delete_item && trans)
+               ret = btrfs_del_orphan_item(trans, root, btrfs_ino(inode));
        if (test_and_clear_bit(BTRFS_INODE_ORPHAN_META_RESERVED,
                               &inode->runtime_flags))
-               release_rsv = 1;
-       spin_unlock(&root->orphan_lock);
+               btrfs_orphan_release_metadata(inode);
  
-       if (delete_item) {
+       /*
+        * btrfs_orphan_commit_root may race with us and set ->orphan_block_rsv
+        * to zero, in order to avoid that, decrease ->orphan_inodes after
+        * everything is done.
+        */
+       if (delete_item)
                atomic_dec(&root->orphan_inodes);
-               if (trans)
-                       ret = btrfs_del_orphan_item(trans, root,
-                                                   btrfs_ino(inode));
-       }
-       if (release_rsv)
-               btrfs_orphan_release_metadata(inode);
  
        return ret;
  }
@@@ -3803,8 -3813,7 +3814,8 @@@ static int btrfs_read_locked_inode(stru
        BTRFS_I(inode)->generation = btrfs_inode_generation(leaf, inode_item);
        BTRFS_I(inode)->last_trans = btrfs_inode_transid(leaf, inode_item);
  
 -      inode->i_version = btrfs_inode_sequence(leaf, inode_item);
 +      inode_set_iversion_queried(inode,
 +                                 btrfs_inode_sequence(leaf, inode_item));
        inode->i_generation = BTRFS_I(inode)->generation;
        inode->i_rdev = 0;
        rdev = btrfs_inode_rdev(leaf, inode_item);
@@@ -3972,8 -3981,7 +3983,8 @@@ static void fill_inode_item(struct btrf
                                     &token);
        btrfs_set_token_inode_generation(leaf, item, BTRFS_I(inode)->generation,
                                         &token);
 -      btrfs_set_token_inode_sequence(leaf, item, inode->i_version, &token);
 +      btrfs_set_token_inode_sequence(leaf, item, inode_peek_iversion(inode),
 +                                     &token);
        btrfs_set_token_inode_transid(leaf, item, trans->transid, &token);
        btrfs_set_token_inode_rdev(leaf, item, inode->i_rdev, &token);
        btrfs_set_token_inode_flags(leaf, item, BTRFS_I(inode)->flags, &token);
@@@ -5281,7 -5289,7 +5292,7 @@@ void btrfs_evict_inode(struct inode *in
        trace_btrfs_inode_evict(inode);
  
        if (!root) {
-               kmem_cache_free(btrfs_inode_cachep, BTRFS_I(inode));
+               clear_inode(inode);
                return;
        }
  
@@@ -6125,20 -6133,19 +6136,20 @@@ static int btrfs_update_time(struct ino
                             int flags)
  {
        struct btrfs_root *root = BTRFS_I(inode)->root;
 +      bool dirty = flags & ~S_VERSION;
  
        if (btrfs_root_readonly(root))
                return -EROFS;
  
        if (flags & S_VERSION)
 -              inode_inc_iversion(inode);
 +              dirty |= inode_maybe_inc_iversion(inode, dirty);
        if (flags & S_CTIME)
                inode->i_ctime = *now;
        if (flags & S_MTIME)
                inode->i_mtime = *now;
        if (flags & S_ATIME)
                inode->i_atime = *now;
 -      return btrfs_dirty_inode(inode);
 +      return dirty ? btrfs_dirty_inode(inode) : 0;
  }
  
  /*
@@@ -7896,7 -7903,6 +7907,7 @@@ static blk_status_t dio_read_error(stru
        int segs;
        int ret;
        blk_status_t status;
 +      struct bio_vec bvec;
  
        BUG_ON(bio_op(failed_bio) == REQ_OP_WRITE);
  
        }
  
        segs = bio_segments(failed_bio);
 +      bio_get_first_bvec(failed_bio, &bvec);
        if (segs > 1 ||
 -          (failed_bio->bi_io_vec->bv_len > btrfs_inode_sectorsize(inode)))
 +          (bvec.bv_len > btrfs_inode_sectorsize(inode)))
                read_mode |= REQ_FAILFAST_DEV;
  
        isector = start - btrfs_io_bio(failed_bio)->logical;
@@@ -7957,7 -7962,7 +7968,7 @@@ static void btrfs_retry_endio_nocsum(st
        ASSERT(bio->bi_vcnt == 1);
        io_tree = &BTRFS_I(inode)->io_tree;
        failure_tree = &BTRFS_I(inode)->io_failure_tree;
 -      ASSERT(bio->bi_io_vec->bv_len == btrfs_inode_sectorsize(inode));
 +      ASSERT(bio_first_bvec_all(bio)->bv_len == btrfs_inode_sectorsize(inode));
  
        done->uptodate = 1;
        ASSERT(!bio_flagged(bio, BIO_CLONED));
@@@ -8047,7 -8052,7 +8058,7 @@@ static void btrfs_retry_endio(struct bi
        uptodate = 1;
  
        ASSERT(bio->bi_vcnt == 1);
 -      ASSERT(bio->bi_io_vec->bv_len == btrfs_inode_sectorsize(done->inode));
 +      ASSERT(bio_first_bvec_all(bio)->bv_len == btrfs_inode_sectorsize(done->inode));
  
        io_tree = &BTRFS_I(inode)->io_tree;
        failure_tree = &BTRFS_I(inode)->io_failure_tree;
diff --combined fs/btrfs/tree-log.c
index afadaadab18e45f5901600be18405d7a74e1a1f6,61f20c367aafcee56f9128695232d644593b3bfa..4fd19b4d667557f8b45b1ec61ef48f79ebb5f1cf
@@@ -20,7 -20,6 +20,7 @@@
  #include <linux/slab.h>
  #include <linux/blkdev.h>
  #include <linux/list_sort.h>
 +#include <linux/iversion.h>
  #include "tree-log.h"
  #include "disk-io.h"
  #include "locking.h"
@@@ -29,6 -28,7 +29,7 @@@
  #include "hash.h"
  #include "compression.h"
  #include "qgroup.h"
+ #include "inode-map.h"
  
  /* magic values for the inode_only field in btrfs_log_inode:
   *
@@@ -2472,6 -2472,9 +2473,9 @@@ static noinline int walk_down_log_tree(
                                        clean_tree_block(fs_info, next);
                                        btrfs_wait_tree_block_writeback(next);
                                        btrfs_tree_unlock(next);
+                               } else {
+                                       if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &next->bflags))
+                                               clear_extent_buffer_dirty(next);
                                }
  
                                WARN_ON(root_owner !=
@@@ -2552,6 -2555,9 +2556,9 @@@ static noinline int walk_up_log_tree(st
                                        clean_tree_block(fs_info, next);
                                        btrfs_wait_tree_block_writeback(next);
                                        btrfs_tree_unlock(next);
+                               } else {
+                                       if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &next->bflags))
+                                               clear_extent_buffer_dirty(next);
                                }
  
                                WARN_ON(root_owner != BTRFS_TREE_LOG_OBJECTID);
@@@ -2630,6 -2636,9 +2637,9 @@@ static int walk_log_tree(struct btrfs_t
                                clean_tree_block(fs_info, next);
                                btrfs_wait_tree_block_writeback(next);
                                btrfs_tree_unlock(next);
+                       } else {
+                               if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &next->bflags))
+                                       clear_extent_buffer_dirty(next);
                        }
  
                        WARN_ON(log->root_key.objectid !=
@@@ -3018,13 -3027,14 +3028,14 @@@ static void free_log_tree(struct btrfs_
  
        while (1) {
                ret = find_first_extent_bit(&log->dirty_log_pages,
-                               0, &start, &end, EXTENT_DIRTY | EXTENT_NEW,
+                               0, &start, &end,
+                               EXTENT_DIRTY | EXTENT_NEW | EXTENT_NEED_WAIT,
                                NULL);
                if (ret)
                        break;
  
                clear_extent_bits(&log->dirty_log_pages, start, end,
-                                 EXTENT_DIRTY | EXTENT_NEW);
+                                 EXTENT_DIRTY | EXTENT_NEW | EXTENT_NEED_WAIT);
        }
  
        /*
@@@ -3587,8 -3597,7 +3598,8 @@@ static void fill_inode_item(struct btrf
        btrfs_set_token_inode_nbytes(leaf, item, inode_get_bytes(inode),
                                     &token);
  
 -      btrfs_set_token_inode_sequence(leaf, item, inode->i_version, &token);
 +      btrfs_set_token_inode_sequence(leaf, item,
 +                                     inode_peek_iversion(inode), &token);
        btrfs_set_token_inode_transid(leaf, item, trans->transid, &token);
        btrfs_set_token_inode_rdev(leaf, item, inode->i_rdev, &token);
        btrfs_set_token_inode_flags(leaf, item, BTRFS_I(inode)->flags, &token);
@@@ -5677,6 -5686,23 +5688,23 @@@ again
                                                      path);
                }
  
+               if (!ret && wc.stage == LOG_WALK_REPLAY_ALL) {
+                       struct btrfs_root *root = wc.replay_dest;
+                       btrfs_release_path(path);
+                       /*
+                        * We have just replayed everything, and the highest
+                        * objectid of fs roots probably has changed in case
+                        * some inode_item's got replayed.
+                        *
+                        * root->objectid_mutex is not acquired as log replay
+                        * could only happen during mount.
+                        */
+                       ret = btrfs_find_highest_objectid(root,
+                                                 &root->highest_objectid);
+               }
                key.offset = found_key.offset - 1;
                wc.replay_dest->log_root = NULL;
                free_extent_buffer(log->node);