Merge tag 'for-6.0-rc3-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 28 Aug 2022 17:44:04 +0000 (10:44 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 28 Aug 2022 17:44:04 +0000 (10:44 -0700)
Pull btrfs fixes from David Sterba:
 "Fixes:

   - check that subvolume is writable when changing xattrs from security
     namespace

   - fix memory leak in device lookup helper

   - update generation of hole file extent item when merging holes

   - fix space cache corruption and potential double allocations; this
     is a rare bug but can be serious once it happens, stable backports
     and analysis tool will be provided

   - fix error handling when deleting root references

   - fix crash due to assert when attempting to cancel suspended device
     replace, add message what to do if mount fails due to missing
     replace item

  Regressions:

   - don't merge pages into bio if their page offset is not contiguous

   - don't allow large NOWAIT direct reads, this could lead to short
     reads eg. in io_uring"

* tag 'for-6.0-rc3-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
  btrfs: add info when mount fails due to stale replace target
  btrfs: replace: drop assert for suspended replace
  btrfs: fix silent failure when deleting root reference
  btrfs: fix space cache corruption and potential double allocations
  btrfs: don't allow large NOWAIT direct reads
  btrfs: don't merge pages into bio if their page offset is not contiguous
  btrfs: update generation of hole file extent item when merging holes
  btrfs: fix possible memory leak in btrfs_get_dev_args_from_path()
  btrfs: check if root is readonly while setting security xattr

fs/btrfs/block-group.c
fs/btrfs/block-group.h
fs/btrfs/ctree.h
fs/btrfs/dev-replace.c
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/file.c
fs/btrfs/inode.c
fs/btrfs/root-tree.c
fs/btrfs/volumes.c
fs/btrfs/xattr.c

index 993aca2f1e1812d4f7849bbe01357a32c38ab057..e0375ba9d0fedf654023b41f9405502c8079ae5d 100644 (file)
@@ -440,39 +440,26 @@ void btrfs_wait_block_group_cache_progress(struct btrfs_block_group *cache,
        btrfs_put_caching_control(caching_ctl);
 }
 
-int btrfs_wait_block_group_cache_done(struct btrfs_block_group *cache)
+static int btrfs_caching_ctl_wait_done(struct btrfs_block_group *cache,
+                                      struct btrfs_caching_control *caching_ctl)
+{
+       wait_event(caching_ctl->wait, btrfs_block_group_done(cache));
+       return cache->cached == BTRFS_CACHE_ERROR ? -EIO : 0;
+}
+
+static int btrfs_wait_block_group_cache_done(struct btrfs_block_group *cache)
 {
        struct btrfs_caching_control *caching_ctl;
-       int ret = 0;
+       int ret;
 
        caching_ctl = btrfs_get_caching_control(cache);
        if (!caching_ctl)
                return (cache->cached == BTRFS_CACHE_ERROR) ? -EIO : 0;
-
-       wait_event(caching_ctl->wait, btrfs_block_group_done(cache));
-       if (cache->cached == BTRFS_CACHE_ERROR)
-               ret = -EIO;
+       ret = btrfs_caching_ctl_wait_done(cache, caching_ctl);
        btrfs_put_caching_control(caching_ctl);
        return ret;
 }
 
-static bool space_cache_v1_done(struct btrfs_block_group *cache)
-{
-       bool ret;
-
-       spin_lock(&cache->lock);
-       ret = cache->cached != BTRFS_CACHE_FAST;
-       spin_unlock(&cache->lock);
-
-       return ret;
-}
-
-void btrfs_wait_space_cache_v1_finished(struct btrfs_block_group *cache,
-                               struct btrfs_caching_control *caching_ctl)
-{
-       wait_event(caching_ctl->wait, space_cache_v1_done(cache));
-}
-
 #ifdef CONFIG_BTRFS_DEBUG
 static void fragment_free_space(struct btrfs_block_group *block_group)
 {
@@ -750,9 +737,8 @@ done:
        btrfs_put_block_group(block_group);
 }
 
-int btrfs_cache_block_group(struct btrfs_block_group *cache, int load_cache_only)
+int btrfs_cache_block_group(struct btrfs_block_group *cache, bool wait)
 {
-       DEFINE_WAIT(wait);
        struct btrfs_fs_info *fs_info = cache->fs_info;
        struct btrfs_caching_control *caching_ctl = NULL;
        int ret = 0;
@@ -785,10 +771,7 @@ int btrfs_cache_block_group(struct btrfs_block_group *cache, int load_cache_only
        }
        WARN_ON(cache->caching_ctl);
        cache->caching_ctl = caching_ctl;
-       if (btrfs_test_opt(fs_info, SPACE_CACHE))
-               cache->cached = BTRFS_CACHE_FAST;
-       else
-               cache->cached = BTRFS_CACHE_STARTED;
+       cache->cached = BTRFS_CACHE_STARTED;
        cache->has_caching_ctl = 1;
        spin_unlock(&cache->lock);
 
@@ -801,8 +784,8 @@ int btrfs_cache_block_group(struct btrfs_block_group *cache, int load_cache_only
 
        btrfs_queue_work(fs_info->caching_workers, &caching_ctl->work);
 out:
-       if (load_cache_only && caching_ctl)
-               btrfs_wait_space_cache_v1_finished(cache, caching_ctl);
+       if (wait && caching_ctl)
+               ret = btrfs_caching_ctl_wait_done(cache, caching_ctl);
        if (caching_ctl)
                btrfs_put_caching_control(caching_ctl);
 
@@ -3312,7 +3295,7 @@ int btrfs_update_block_group(struct btrfs_trans_handle *trans,
                 * space back to the block group, otherwise we will leak space.
                 */
                if (!alloc && !btrfs_block_group_done(cache))
-                       btrfs_cache_block_group(cache, 1);
+                       btrfs_cache_block_group(cache, true);
 
                byte_in_group = bytenr - cache->start;
                WARN_ON(byte_in_group > cache->length);
index 35e0e860cc0bf161b630043444cea767decc2bcf..6b3cdc4cbc41e64892165ba788d9c23f80af2658 100644 (file)
@@ -263,9 +263,7 @@ void btrfs_dec_nocow_writers(struct btrfs_block_group *bg);
 void btrfs_wait_nocow_writers(struct btrfs_block_group *bg);
 void btrfs_wait_block_group_cache_progress(struct btrfs_block_group *cache,
                                           u64 num_bytes);
-int btrfs_wait_block_group_cache_done(struct btrfs_block_group *cache);
-int btrfs_cache_block_group(struct btrfs_block_group *cache,
-                           int load_cache_only);
+int btrfs_cache_block_group(struct btrfs_block_group *cache, bool wait);
 void btrfs_put_caching_control(struct btrfs_caching_control *ctl);
 struct btrfs_caching_control *btrfs_get_caching_control(
                struct btrfs_block_group *cache);
index 4edb4bfb21664f911a8fd3f4df9c3a59db3d41d1..9ef162dbd4bc11fd84c649d6b7c8b453313a8571 100644 (file)
@@ -505,7 +505,6 @@ struct btrfs_free_cluster {
 enum btrfs_caching_type {
        BTRFS_CACHE_NO,
        BTRFS_CACHE_STARTED,
-       BTRFS_CACHE_FAST,
        BTRFS_CACHE_FINISHED,
        BTRFS_CACHE_ERROR,
 };
index f43196a893ca3c44797d364a74538b5895cb3b91..41cddd3ff0593c068d1e6fbf036fad3d63ca223e 100644 (file)
@@ -165,7 +165,7 @@ no_valid_dev_replace_entry_found:
                 */
                if (btrfs_find_device(fs_info->fs_devices, &args)) {
                        btrfs_err(fs_info,
-                       "replace devid present without an active replace item");
+"replace without active item, run 'device scan --forget' on the target device");
                        ret = -EUCLEAN;
                } else {
                        dev_replace->srcdev = NULL;
@@ -1129,8 +1129,7 @@ int btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info)
                up_write(&dev_replace->rwsem);
 
                /* Scrub for replace must not be running in suspended state */
-               ret = btrfs_scrub_cancel(fs_info);
-               ASSERT(ret != -ENOTCONN);
+               btrfs_scrub_cancel(fs_info);
 
                trans = btrfs_start_transaction(root, 0);
                if (IS_ERR(trans)) {
index ab944d1f94ef0e1974584d7f5b3f9347673dd274..6914cd8024ba040b21552be249ddfdf1da8a1d8e 100644 (file)
@@ -2551,17 +2551,10 @@ int btrfs_pin_extent_for_log_replay(struct btrfs_trans_handle *trans,
                return -EINVAL;
 
        /*
-        * pull in the free space cache (if any) so that our pin
-        * removes the free space from the cache.  We have load_only set
-        * to one because the slow code to read in the free extents does check
-        * the pinned extents.
+        * Fully cache the free space first so that our pin removes the free space
+        * from the cache.
         */
-       btrfs_cache_block_group(cache, 1);
-       /*
-        * Make sure we wait until the cache is completely built in case it is
-        * missing or is invalid and therefore needs to be rebuilt.
-        */
-       ret = btrfs_wait_block_group_cache_done(cache);
+       ret = btrfs_cache_block_group(cache, true);
        if (ret)
                goto out;
 
@@ -2584,12 +2577,7 @@ static int __exclude_logged_extent(struct btrfs_fs_info *fs_info,
        if (!block_group)
                return -EINVAL;
 
-       btrfs_cache_block_group(block_group, 1);
-       /*
-        * Make sure we wait until the cache is completely built in case it is
-        * missing or is invalid and therefore needs to be rebuilt.
-        */
-       ret = btrfs_wait_block_group_cache_done(block_group);
+       ret = btrfs_cache_block_group(block_group, true);
        if (ret)
                goto out;
 
@@ -4399,7 +4387,7 @@ have_block_group:
                ffe_ctl->cached = btrfs_block_group_done(block_group);
                if (unlikely(!ffe_ctl->cached)) {
                        ffe_ctl->have_caching_bg = true;
-                       ret = btrfs_cache_block_group(block_group, 0);
+                       ret = btrfs_cache_block_group(block_group, false);
 
                        /*
                         * If we get ENOMEM here or something else we want to
@@ -6169,13 +6157,7 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range)
 
                if (end - start >= range->minlen) {
                        if (!btrfs_block_group_done(cache)) {
-                               ret = btrfs_cache_block_group(cache, 0);
-                               if (ret) {
-                                       bg_failed++;
-                                       bg_ret = ret;
-                                       continue;
-                               }
-                               ret = btrfs_wait_block_group_cache_done(cache);
+                               ret = btrfs_cache_block_group(cache, true);
                                if (ret) {
                                        bg_failed++;
                                        bg_ret = ret;
index eed81a7e36a4d0dd1cd1fbd05b4b6383f0fc32f8..cf4f19e80e2f7f174ecdd245f4dd4b5e9d7dbd87 100644 (file)
@@ -3233,7 +3233,7 @@ static int btrfs_bio_add_page(struct btrfs_bio_ctrl *bio_ctrl,
        u32 bio_size = bio->bi_iter.bi_size;
        u32 real_size;
        const sector_t sector = disk_bytenr >> SECTOR_SHIFT;
-       bool contig;
+       bool contig = false;
        int ret;
 
        ASSERT(bio);
@@ -3242,10 +3242,35 @@ static int btrfs_bio_add_page(struct btrfs_bio_ctrl *bio_ctrl,
        if (bio_ctrl->compress_type != compress_type)
                return 0;
 
-       if (bio_ctrl->compress_type != BTRFS_COMPRESS_NONE)
+
+       if (bio->bi_iter.bi_size == 0) {
+               /* We can always add a page into an empty bio. */
+               contig = true;
+       } else if (bio_ctrl->compress_type == BTRFS_COMPRESS_NONE) {
+               struct bio_vec *bvec = bio_last_bvec_all(bio);
+
+               /*
+                * The contig check requires the following conditions to be met:
+                * 1) The pages are belonging to the same inode
+                *    This is implied by the call chain.
+                *
+                * 2) The range has adjacent logical bytenr
+                *
+                * 3) The range has adjacent file offset
+                *    This is required for the usage of btrfs_bio->file_offset.
+                */
+               if (bio_end_sector(bio) == sector &&
+                   page_offset(bvec->bv_page) + bvec->bv_offset +
+                   bvec->bv_len == page_offset(page) + pg_offset)
+                       contig = true;
+       } else {
+               /*
+                * For compression, all IO should have its logical bytenr
+                * set to the starting bytenr of the compressed extent.
+                */
                contig = bio->bi_iter.bi_sector == sector;
-       else
-               contig = bio_end_sector(bio) == sector;
+       }
+
        if (!contig)
                return 0;
 
index 66c822182ecce7899c0786a42969c0fc893de4e2..5a3f6e0d9688f2cf0dd09ab7cab77df877c95488 100644 (file)
@@ -2482,6 +2482,7 @@ static int fill_holes(struct btrfs_trans_handle *trans,
                btrfs_set_file_extent_num_bytes(leaf, fi, num_bytes);
                btrfs_set_file_extent_ram_bytes(leaf, fi, num_bytes);
                btrfs_set_file_extent_offset(leaf, fi, 0);
+               btrfs_set_file_extent_generation(leaf, fi, trans->transid);
                btrfs_mark_buffer_dirty(leaf);
                goto out;
        }
@@ -2498,6 +2499,7 @@ static int fill_holes(struct btrfs_trans_handle *trans,
                btrfs_set_file_extent_num_bytes(leaf, fi, num_bytes);
                btrfs_set_file_extent_ram_bytes(leaf, fi, num_bytes);
                btrfs_set_file_extent_offset(leaf, fi, 0);
+               btrfs_set_file_extent_generation(leaf, fi, trans->transid);
                btrfs_mark_buffer_dirty(leaf);
                goto out;
        }
index f0c97d25b4a0e762849ac63c3fa7f40d8bf38f2f..ad250892028d6e0387ff8ad101e0ee2a9b9452f2 100644 (file)
@@ -7693,6 +7693,20 @@ static int btrfs_dio_iomap_begin(struct inode *inode, loff_t start,
        const u64 data_alloc_len = length;
        bool unlock_extents = false;
 
+       /*
+        * We could potentially fault if we have a buffer > PAGE_SIZE, and if
+        * we're NOWAIT we may submit a bio for a partial range and return
+        * EIOCBQUEUED, which would result in an errant short read.
+        *
+        * The best way to handle this would be to allow for partial completions
+        * of iocb's, so we could submit the partial bio, return and fault in
+        * the rest of the pages, and then submit the io for the rest of the
+        * range.  However we don't have that currently, so simply return
+        * -EAGAIN at this point so that the normal path is used.
+        */
+       if (!write && (flags & IOMAP_NOWAIT) && length > PAGE_SIZE)
+               return -EAGAIN;
+
        /*
         * Cap the size of reads to that usually seen in buffered I/O as we need
         * to allocate a contiguous array for the checksums.
index a64b26b169040100b94f45acfefb050a5a5defba..d647cb2938c0184be095a175942814952a86aa17 100644 (file)
@@ -349,9 +349,10 @@ int btrfs_del_root_ref(struct btrfs_trans_handle *trans, u64 root_id,
        key.offset = ref_id;
 again:
        ret = btrfs_search_slot(trans, tree_root, &key, path, -1, 1);
-       if (ret < 0)
+       if (ret < 0) {
+               err = ret;
                goto out;
-       if (ret == 0) {
+       } else if (ret == 0) {
                leaf = path->nodes[0];
                ref = btrfs_item_ptr(leaf, path->slots[0],
                                     struct btrfs_root_ref);
index 272901514b0c14dc7074e31907df1f46caf3705e..064ab2a79c805f5f07921a4b1f3641d6bb6736a8 100644 (file)
@@ -2345,8 +2345,11 @@ int btrfs_get_dev_args_from_path(struct btrfs_fs_info *fs_info,
 
        ret = btrfs_get_bdev_and_sb(path, FMODE_READ, fs_info->bdev_holder, 0,
                                    &bdev, &disk_super);
-       if (ret)
+       if (ret) {
+               btrfs_put_dev_args_from_path(args);
                return ret;
+       }
+
        args->devid = btrfs_stack_device_id(&disk_super->dev_item);
        memcpy(args->uuid, disk_super->dev_item.uuid, BTRFS_UUID_SIZE);
        if (btrfs_fs_incompat(fs_info, METADATA_UUID))
index 7421abcf325a54ececa7f9c1ad7105921ce2f59d..5bb8d8c86311902ea8065862e66b35ec652f6c85 100644 (file)
@@ -371,6 +371,9 @@ static int btrfs_xattr_handler_set(const struct xattr_handler *handler,
                                   const char *name, const void *buffer,
                                   size_t size, int flags)
 {
+       if (btrfs_root_readonly(BTRFS_I(inode)->root))
+               return -EROFS;
+
        name = xattr_full_name(handler, name);
        return btrfs_setxattr_trans(inode, name, buffer, size, flags);
 }