Merge branch 'for-linus-4.4' of git://git.kernel.org/pub/scm/linux/kernel/git/mason...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 14 Nov 2015 00:30:29 +0000 (16:30 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 14 Nov 2015 00:30:29 +0000 (16:30 -0800)
Pull btrfs fixes and cleanups from Chris Mason:
 "Some of this got cherry-picked from a github repo this week, but I
  verified the patches.

  We have three small scrub cleanups and a collection of fixes"

* 'for-linus-4.4' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs:
  btrfs: Use fs_info directly in btrfs_delete_unused_bgs
  btrfs: Fix lost-data-profile caused by balance bg
  btrfs: Fix lost-data-profile caused by auto removing bg
  btrfs: Remove len argument from scrub_find_csum
  btrfs: Reduce unnecessary arguments in scrub_recheck_block
  btrfs: Use scrub_checksum_data and scrub_checksum_tree_block for scrub_recheck_block_checksum
  btrfs: Reset sblock->xxx_error stats before calling scrub_recheck_block_checksum
  btrfs: scrub: setup all fields for sblock_to_check
  btrfs: scrub: set error stats when tree block spanning stripes
  Btrfs: fix race when listing an inode's xattrs
  Btrfs: fix race leading to BUG_ON when running delalloc for nodatacow
  Btrfs: fix race leading to incorrect item deletion when dropping extents
  Btrfs: fix sleeping inside atomic context in qgroup rescan worker
  Btrfs: fix race waiting for qgroup rescan worker
  btrfs: qgroup: exit the rescan worker during umount
  Btrfs: fix extent accounting for partial direct IO writes

1  2 
fs/btrfs/disk-io.c
fs/btrfs/file.c
fs/btrfs/inode.c
fs/btrfs/volumes.c

diff --combined fs/btrfs/disk-io.c
index 640598c0d0e7585ff125b1a63ed9e74c2c42eaed,1eb08393bff0b06f7883fa3835277a0c60b7c7d8..974be09e7556ca3f342cac89357364f4ce3cc016
@@@ -2575,7 -2575,7 +2575,7 @@@ int open_ctree(struct super_block *sb
        fs_info->commit_interval = BTRFS_DEFAULT_COMMIT_INTERVAL;
        fs_info->avg_delayed_ref_runtime = NSEC_PER_SEC >> 6; /* div by 64 */
        /* readahead state */
 -      INIT_RADIX_TREE(&fs_info->reada_tree, GFP_NOFS & ~__GFP_WAIT);
 +      INIT_RADIX_TREE(&fs_info->reada_tree, GFP_NOFS & ~__GFP_DIRECT_RECLAIM);
        spin_lock_init(&fs_info->reada_lock);
  
        fs_info->thread_pool_size = min_t(unsigned long,
@@@ -3780,6 -3780,9 +3780,9 @@@ void close_ctree(struct btrfs_root *roo
        fs_info->closing = 1;
        smp_mb();
  
+       /* wait for the qgroup rescan worker to stop */
+       btrfs_qgroup_wait_for_completion(fs_info);
        /* wait for the uuid_scan task to finish */
        down(&fs_info->uuid_tree_rescan_sem);
        /* avoid complains from lockdep et al., set sem back to initial state */
diff --combined fs/btrfs/file.c
index 6bd5ce9d75f0ab8eaca5a2f808bfaf5a66132742,3009d4536d389386dba9a582cd84a5da7ff20552..977e715f0bf21a4ea8908700cfe4207dee1fe95d
@@@ -756,8 -756,16 +756,16 @@@ next_slot
                }
  
                btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
-               if (key.objectid > ino ||
-                   key.type > BTRFS_EXTENT_DATA_KEY || key.offset >= end)
+               if (key.objectid > ino)
+                       break;
+               if (WARN_ON_ONCE(key.objectid < ino) ||
+                   key.type < BTRFS_EXTENT_DATA_KEY) {
+                       ASSERT(del_nr == 0);
+                       path->slots[0]++;
+                       goto next_slot;
+               }
+               if (key.type > BTRFS_EXTENT_DATA_KEY || key.offset >= end)
                        break;
  
                fi = btrfs_item_ptr(leaf, path->slots[0],
                                btrfs_file_extent_inline_len(leaf,
                                                     path->slots[0], fi);
                } else {
-                       WARN_ON(1);
-                       extent_end = search_start;
+                       /* can't happen */
+                       BUG();
                }
  
                /*
@@@ -2655,7 -2663,7 +2663,7 @@@ static long btrfs_fallocate(struct fil
                                        alloc_start);
                if (ret)
                        goto out;
 -      } else {
 +      } else if (offset + len > inode->i_size) {
                /*
                 * If we are fallocating from the end of the file onward we
                 * need to zero out the end of the page if i_size lands in the
diff --combined fs/btrfs/inode.c
index 0e4f2bfcc37d083da90f381c0cfeeeb28f643cd2,6e93349d8aa2db418330db09401e26adc5c8b530..994490d5fa6423dee4971e0ff013777d853fe6a6
@@@ -1304,8 -1304,14 +1304,14 @@@ next_slot
                num_bytes = 0;
                btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
  
-               if (found_key.objectid > ino ||
-                   found_key.type > BTRFS_EXTENT_DATA_KEY ||
+               if (found_key.objectid > ino)
+                       break;
+               if (WARN_ON_ONCE(found_key.objectid < ino) ||
+                   found_key.type < BTRFS_EXTENT_DATA_KEY) {
+                       path->slots[0]++;
+                       goto next_slot;
+               }
+               if (found_key.type > BTRFS_EXTENT_DATA_KEY ||
                    found_key.offset > end)
                        break;
  
@@@ -6360,6 -6366,9 +6366,6 @@@ static int btrfs_mknod(struct inode *di
        u64 objectid;
        u64 index = 0;
  
 -      if (!new_valid_dev(rdev))
 -              return -EINVAL;
 -
        /*
         * 2 for inode item and ref
         * 2 for dir items
@@@ -7503,6 -7512,28 +7509,28 @@@ struct btrfs_dio_data 
        u64 reserve;
  };
  
+ static void adjust_dio_outstanding_extents(struct inode *inode,
+                                          struct btrfs_dio_data *dio_data,
+                                          const u64 len)
+ {
+       unsigned num_extents;
+       num_extents = (unsigned) div64_u64(len + BTRFS_MAX_EXTENT_SIZE - 1,
+                                          BTRFS_MAX_EXTENT_SIZE);
+       /*
+        * If we have an outstanding_extents count still set then we're
+        * within our reservation, otherwise we need to adjust our inode
+        * counter appropriately.
+        */
+       if (dio_data->outstanding_extents) {
+               dio_data->outstanding_extents -= num_extents;
+       } else {
+               spin_lock(&BTRFS_I(inode)->lock);
+               BTRFS_I(inode)->outstanding_extents += num_extents;
+               spin_unlock(&BTRFS_I(inode)->lock);
+       }
+ }
  static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock,
                                   struct buffer_head *bh_result, int create)
  {
         * If this errors out it's because we couldn't invalidate pagecache for
         * this range and we need to fallback to buffered.
         */
-       if (lock_extent_direct(inode, lockstart, lockend, &cached_state, create))
-               return -ENOTBLK;
+       if (lock_extent_direct(inode, lockstart, lockend, &cached_state,
+                              create)) {
+               ret = -ENOTBLK;
+               goto err;
+       }
  
        em = btrfs_get_extent(inode, NULL, 0, start, len, 0);
        if (IS_ERR(em)) {
@@@ -7657,19 -7691,7 +7688,7 @@@ unlock
                if (start + len > i_size_read(inode))
                        i_size_write(inode, start + len);
  
-               /*
-                * If we have an outstanding_extents count still set then we're
-                * within our reservation, otherwise we need to adjust our inode
-                * counter appropriately.
-                */
-               if (dio_data->outstanding_extents) {
-                       (dio_data->outstanding_extents)--;
-               } else {
-                       spin_lock(&BTRFS_I(inode)->lock);
-                       BTRFS_I(inode)->outstanding_extents++;
-                       spin_unlock(&BTRFS_I(inode)->lock);
-               }
+               adjust_dio_outstanding_extents(inode, dio_data, len);
                btrfs_free_reserved_data_space(inode, start, len);
                WARN_ON(dio_data->reserve < len);
                dio_data->reserve -= len;
  unlock_err:
        clear_extent_bit(&BTRFS_I(inode)->io_tree, lockstart, lockend,
                         unlock_bits, 1, 0, &cached_state, GFP_NOFS);
+ err:
        if (dio_data)
                current->journal_info = dio_data;
+       /*
+        * Compensate the delalloc release we do in btrfs_direct_IO() when we
+        * write less data then expected, so that we don't underflow our inode's
+        * outstanding extents counter.
+        */
+       if (create && dio_data)
+               adjust_dio_outstanding_extents(inode, dio_data, len);
        return ret;
  }
  
diff --combined fs/btrfs/volumes.c
index 9b2dafa5ba59178644c6c01879583cc2769a52e8,d198dd3360d3430507843d71b8b1547cab9b61a0..a6df8fdc1312ce78e97f9f90037ff5b236a58a92
@@@ -232,8 -232,8 +232,8 @@@ static struct btrfs_device *__alloc_dev
        spin_lock_init(&dev->reada_lock);
        atomic_set(&dev->reada_in_flight, 0);
        atomic_set(&dev->dev_stats_ccnt, 0);
 -      INIT_RADIX_TREE(&dev->reada_zones, GFP_NOFS & ~__GFP_WAIT);
 -      INIT_RADIX_TREE(&dev->reada_extents, GFP_NOFS & ~__GFP_WAIT);
 +      INIT_RADIX_TREE(&dev->reada_zones, GFP_NOFS & ~__GFP_DIRECT_RECLAIM);
 +      INIT_RADIX_TREE(&dev->reada_extents, GFP_NOFS & ~__GFP_DIRECT_RECLAIM);
  
        return dev;
  }
@@@ -3400,6 -3400,7 +3400,7 @@@ static int __btrfs_balance(struct btrfs
        u32 count_data = 0;
        u32 count_meta = 0;
        u32 count_sys = 0;
+       int chunk_reserved = 0;
  
        /* step one make some room on all the devices */
        devices = &fs_info->fs_devices->devices;
@@@ -3501,6 -3502,7 +3502,7 @@@ again
  
                ret = should_balance_chunk(chunk_root, leaf, chunk,
                                           found_key.offset);
                btrfs_release_path(path);
                if (!ret) {
                        mutex_unlock(&fs_info->delete_unused_bgs_mutex);
                        goto loop;
                }
  
+               if ((chunk_type & BTRFS_BLOCK_GROUP_DATA) && !chunk_reserved) {
+                       trans = btrfs_start_transaction(chunk_root, 0);
+                       if (IS_ERR(trans)) {
+                               mutex_unlock(&fs_info->delete_unused_bgs_mutex);
+                               ret = PTR_ERR(trans);
+                               goto error;
+                       }
+                       ret = btrfs_force_chunk_alloc(trans, chunk_root,
+                                                     BTRFS_BLOCK_GROUP_DATA);
+                       if (ret < 0) {
+                               mutex_unlock(&fs_info->delete_unused_bgs_mutex);
+                               goto error;
+                       }
+                       btrfs_end_transaction(trans, chunk_root);
+                       chunk_reserved = 1;
+               }
                ret = btrfs_relocate_chunk(chunk_root,
                                           found_key.offset);
                mutex_unlock(&fs_info->delete_unused_bgs_mutex);