]> exis.tech > repos - linux.git/commitdiff
Merge tag 'for-7.0-rc3-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 12 Mar 2026 19:15:27 +0000 (12:15 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 12 Mar 2026 19:15:27 +0000 (12:15 -0700)
Pull btrfs fixes from David Sterba:

 - detect possible file name hash collision earlier so it does not lead
   to transaction abort

 - handle b-tree leaf overflows when snapshotting a subvolume with set
   received UUID, leading to transaction abort

 - in zoned mode, reorder relocation block group initialization after
   the transaction kthread start

 - fix orphan cleanup state tracking of subvolume, this could lead to
   invalid dentries under some conditions

 - add locking around updates of dynamic reclain state update

 - in subpage mode, add missing RCU unlock when trying to releae extent
   buffer

 - remap tree fixes:
     - add missing description strings for the newly added remap tree
     - properly update search key when iterating backrefs

* tag 'for-7.0-rc3-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
  btrfs: remove duplicated definition of btrfs_printk_in_rcu()
  btrfs: remove unnecessary transaction abort in the received subvol ioctl
  btrfs: abort transaction on failure to update root in the received subvol ioctl
  btrfs: fix transaction abort on set received ioctl due to item overflow
  btrfs: fix transaction abort when snapshotting received subvolumes
  btrfs: fix transaction abort on file creation due to name hash collision
  btrfs: read key again after incrementing slot in move_existing_remaps()
  btrfs: add missing RCU unlock in error path in try_release_subpage_extent_buffer()
  btrfs: set BTRFS_ROOT_ORPHAN_CLEANUP during subvol create
  btrfs: zoned: move btrfs_zoned_reserve_data_reloc_bg() after kthread start
  btrfs: hold space_info->lock when clearing periodic reclaim ready
  btrfs: print-tree: add remap tree definitions

1  2 
fs/btrfs/disk-io.c
fs/btrfs/extent_io.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/relocation.c
fs/btrfs/space-info.c
fs/btrfs/transaction.c

diff --combined fs/btrfs/disk-io.c
index e4fad777b034aa939c4e22130a62206b50a47db7,2aeb85e3ece97587899695f74d987643570f7bfb..407830d86d0dac22d2e29202b4ef8cd1a1bcbf10
@@@ -605,7 -605,7 +605,7 @@@ static struct btrfs_root *btrfs_alloc_r
  {
        struct btrfs_root *root;
  
 -      root = kzalloc(sizeof(*root), flags);
 +      root = kzalloc_obj(*root, flags);
        if (!root)
                return NULL;
  
@@@ -3594,7 -3594,6 +3594,6 @@@ int __cold open_ctree(struct super_bloc
                }
        }
  
-       btrfs_zoned_reserve_data_reloc_bg(fs_info);
        btrfs_free_zone_cache(fs_info);
  
        btrfs_check_active_zone_reservation(fs_info);
                goto fail_cleaner;
        }
  
+       /*
+        * Starts a transaction, must be called after the transaction kthread
+        * is initialized.
+        */
+       btrfs_zoned_reserve_data_reloc_bg(fs_info);
        ret = btrfs_read_qgroup_config(fs_info);
        if (ret)
                goto fail_trans_kthread;
diff --combined fs/btrfs/extent_io.c
index 744a1fff6eefc17f19c6644e45e035e99ff35a19,051309e900796497612f5e5842283d56db0aceba..5f97a3d2a8d7246b257259a419edeb7559dc2971
@@@ -475,25 -475,25 +475,25 @@@ void extent_clear_unlock_delalloc(struc
                                end, page_ops);
  }
  
 -static bool btrfs_verify_folio(struct folio *folio, u64 start, u32 len)
 +static bool btrfs_verify_folio(struct fsverity_info *vi, struct folio *folio,
 +                             u64 start, u32 len)
  {
        struct btrfs_fs_info *fs_info = folio_to_fs_info(folio);
  
 -      if (!fsverity_active(folio->mapping->host) ||
 -          btrfs_folio_test_uptodate(fs_info, folio, start, len) ||
 -          start >= i_size_read(folio->mapping->host))
 +      if (!vi || btrfs_folio_test_uptodate(fs_info, folio, start, len))
                return true;
 -      return fsverity_verify_folio(folio);
 +      return fsverity_verify_folio(vi, folio);
  }
  
 -static void end_folio_read(struct folio *folio, bool uptodate, u64 start, u32 len)
 +static void end_folio_read(struct fsverity_info *vi, struct folio *folio,
 +                         bool uptodate, u64 start, u32 len)
  {
        struct btrfs_fs_info *fs_info = folio_to_fs_info(folio);
  
        ASSERT(folio_pos(folio) <= start &&
               start + len <= folio_next_pos(folio));
  
 -      if (uptodate && btrfs_verify_folio(folio, start, len))
 +      if (uptodate && btrfs_verify_folio(vi, folio, start, len))
                btrfs_folio_set_uptodate(fs_info, folio, start, len);
        else
                btrfs_folio_clear_uptodate(fs_info, folio, start, len);
@@@ -573,19 -573,14 +573,19 @@@ static void begin_folio_read(struct btr
  static void end_bbio_data_read(struct btrfs_bio *bbio)
  {
        struct btrfs_fs_info *fs_info = bbio->inode->root->fs_info;
 +      struct inode *inode = &bbio->inode->vfs_inode;
        struct bio *bio = &bbio->bio;
 +      struct fsverity_info *vi = NULL;
        struct folio_iter fi;
  
        ASSERT(!bio_flagged(bio, BIO_CLONED));
 +
 +      if (bbio->file_offset < i_size_read(inode))
 +              vi = fsverity_get_info(inode);
 +
        bio_for_each_folio_all(fi, &bbio->bio) {
                bool uptodate = !bio->bi_status;
                struct folio *folio = fi.folio;
 -              struct inode *inode = folio->mapping->host;
                u64 start = folio_pos(folio) + fi.offset;
  
                btrfs_debug(fs_info,
                }
  
                /* Update page status and unlock. */
 -              end_folio_read(folio, uptodate, start, fi.length);
 +              end_folio_read(vi, folio, uptodate, start, fi.length);
        }
        bio_put(bio);
  }
@@@ -995,8 -990,7 +995,8 @@@ static void btrfs_readahead_expand(stru
   * return 0 on success, otherwise return error
   */
  static int btrfs_do_readpage(struct folio *folio, struct extent_map **em_cached,
 -                           struct btrfs_bio_ctrl *bio_ctrl)
 +                           struct btrfs_bio_ctrl *bio_ctrl,
 +                           struct fsverity_info *vi)
  {
        struct inode *inode = folio->mapping->host;
        struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
                ASSERT(IS_ALIGNED(cur, fs_info->sectorsize));
                if (cur >= last_byte) {
                        folio_zero_range(folio, pg_offset, end - cur + 1);
 -                      end_folio_read(folio, true, cur, end - cur + 1);
 +                      end_folio_read(vi, folio, true, cur, end - cur + 1);
                        break;
                }
                if (btrfs_folio_test_uptodate(fs_info, folio, cur, blocksize)) {
 -                      end_folio_read(folio, true, cur, blocksize);
 +                      end_folio_read(vi, folio, true, cur, blocksize);
                        continue;
                }
                /*
                 */
                em = get_extent_map(BTRFS_I(inode), folio, cur, locked_end - cur + 1, em_cached);
                if (IS_ERR(em)) {
 -                      end_folio_read(folio, false, cur, end + 1 - cur);
 +                      end_folio_read(vi, folio, false, cur, end + 1 - cur);
                        return PTR_ERR(em);
                }
                extent_offset = cur - em->start;
                /* we've found a hole, just zero and go on */
                if (block_start == EXTENT_MAP_HOLE) {
                        folio_zero_range(folio, pg_offset, blocksize);
 -                      end_folio_read(folio, true, cur, blocksize);
 +                      end_folio_read(vi, folio, true, cur, blocksize);
                        continue;
                }
                /* the get_extent function already copied into the folio */
                if (block_start == EXTENT_MAP_INLINE) {
 -                      end_folio_read(folio, true, cur, blocksize);
 +                      end_folio_read(vi, folio, true, cur, blocksize);
                        continue;
                }
  
@@@ -1335,8 -1329,7 +1335,8 @@@ again
  
  int btrfs_read_folio(struct file *file, struct folio *folio)
  {
 -      struct btrfs_inode *inode = folio_to_inode(folio);
 +      struct inode *vfs_inode = folio->mapping->host;
 +      struct btrfs_inode *inode = BTRFS_I(vfs_inode);
        const u64 start = folio_pos(folio);
        const u64 end = start + folio_size(folio) - 1;
        struct extent_state *cached_state = NULL;
                .last_em_start = U64_MAX,
        };
        struct extent_map *em_cached = NULL;
 +      struct fsverity_info *vi = NULL;
        int ret;
  
        lock_extents_for_read(inode, start, end, &cached_state);
 -      ret = btrfs_do_readpage(folio, &em_cached, &bio_ctrl);
 +      if (folio_pos(folio) < i_size_read(vfs_inode))
 +              vi = fsverity_get_info(vfs_inode);
 +      ret = btrfs_do_readpage(folio, &em_cached, &bio_ctrl, vi);
        btrfs_unlock_extent(&inode->io_tree, start, end, &cached_state);
  
        btrfs_free_extent_map(em_cached);
@@@ -2724,19 -2714,16 +2724,19 @@@ void btrfs_readahead(struct readahead_c
                .last_em_start = U64_MAX,
        };
        struct folio *folio;
 -      struct btrfs_inode *inode = BTRFS_I(rac->mapping->host);
 +      struct inode *vfs_inode = rac->mapping->host;
 +      struct btrfs_inode *inode = BTRFS_I(vfs_inode);
        const u64 start = readahead_pos(rac);
        const u64 end = start + readahead_length(rac) - 1;
        struct extent_state *cached_state = NULL;
        struct extent_map *em_cached = NULL;
 +      struct fsverity_info *vi = NULL;
  
        lock_extents_for_read(inode, start, end, &cached_state);
 -
 +      if (start < i_size_read(vfs_inode))
 +              vi = fsverity_get_info(vfs_inode);
        while ((folio = readahead_folio(rac)) != NULL)
 -              btrfs_do_readpage(folio, &em_cached, &bio_ctrl);
 +              btrfs_do_readpage(folio, &em_cached, &bio_ctrl, vi);
  
        btrfs_unlock_extent(&inode->io_tree, start, end, &cached_state);
  
@@@ -4507,6 -4494,7 +4507,7 @@@ static int try_release_subpage_extent_b
                 */
                if (!test_and_clear_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags)) {
                        spin_unlock(&eb->refs_lock);
+                       rcu_read_lock();
                        break;
                }
  
diff --combined fs/btrfs/inode.c
index a11fcc9e9f502c559148cf33679014fb83b0d3b0,b409efe1857e1511f4ab28ccffa11e5bccac22bb..a6da98435ef7cb4eca7842002f067d69a849ff43
@@@ -7,7 -7,6 +7,7 @@@
  #include <linux/bio.h>
  #include <linux/blk-cgroup.h>
  #include <linux/file.h>
 +#include <linux/filelock.h>
  #include <linux/fs.h>
  #include <linux/fs_struct.h>
  #include <linux/pagemap.h>
@@@ -34,6 -33,7 +34,6 @@@
  #include <linux/sched/mm.h>
  #include <linux/iomap.h>
  #include <linux/unaligned.h>
 -#include <linux/fsverity.h>
  #include "misc.h"
  #include "ctree.h"
  #include "disk-io.h"
@@@ -781,7 -781,7 +781,7 @@@ static int add_async_extent(struct asyn
  {
        struct async_extent *async_extent;
  
 -      async_extent = kmalloc(sizeof(*async_extent), GFP_NOFS);
 +      async_extent = kmalloc_obj(*async_extent, GFP_NOFS);
        if (!async_extent)
                return -ENOMEM;
        ASSERT(ram_size < U32_MAX);
@@@ -1707,7 -1707,7 +1707,7 @@@ static bool run_delalloc_compressed(str
        const blk_opf_t write_flags = wbc_to_write_flags(wbc);
  
        nofs_flag = memalloc_nofs_save();
 -      ctx = kvmalloc(struct_size(ctx, chunks, num_chunks), GFP_KERNEL);
 +      ctx = kvmalloc_flex(*ctx, chunks, num_chunks);
        memalloc_nofs_restore(nofs_flag);
        if (!ctx)
                return false;
@@@ -3006,7 -3006,7 +3006,7 @@@ int btrfs_writepage_cow_fixup(struct fo
        if (folio_test_checked(folio))
                return -EAGAIN;
  
 -      fixup = kzalloc(sizeof(*fixup), GFP_NOFS);
 +      fixup = kzalloc_obj(*fixup, GFP_NOFS);
        if (!fixup)
                return -EAGAIN;
  
@@@ -3982,7 -3982,7 +3982,7 @@@ static int btrfs_init_file_extent_tree(
        if (btrfs_is_free_space_inode(inode))
                return 0;
  
 -      inode->file_extent_tree = kmalloc(sizeof(struct extent_io_tree), GFP_KERNEL);
 +      inode->file_extent_tree = kmalloc_obj(struct extent_io_tree);
        if (!inode->file_extent_tree)
                return -ENOMEM;
  
@@@ -5630,8 -5630,11 +5630,8 @@@ void btrfs_evict_inode(struct inode *in
  
        trace_btrfs_inode_evict(inode);
  
 -      if (!root) {
 -              fsverity_cleanup_inode(inode);
 -              clear_inode(inode);
 -              return;
 -      }
 +      if (!root)
 +              goto clear_inode;
  
        fs_info = inode_to_fs_info(inode);
        evict_inode_truncate_pages(inode);
@@@ -5731,7 -5734,7 +5731,7 @@@ out
         * to retry these periodically in the future.
         */
        btrfs_remove_delayed_node(BTRFS_I(inode));
 -      fsverity_cleanup_inode(inode);
 +clear_inode:
        clear_inode(inode);
  }
  
@@@ -6236,7 -6239,7 +6236,7 @@@ static int btrfs_opendir(struct inode *
        if (ret)
                return ret;
  
 -      private = kzalloc(sizeof(struct btrfs_file_private), GFP_KERNEL);
 +      private = kzalloc_obj(struct btrfs_file_private);
        if (!private)
                return -ENOMEM;
        private->last_index = last_index;
@@@ -6451,21 -6454,16 +6451,21 @@@ static int btrfs_dirty_inode(struct btr
   * We need our own ->update_time so that we can return error on ENOSPC for
   * updating the inode in the case of file write and mmap writes.
   */
 -static int btrfs_update_time(struct inode *inode, int flags)
 +static int btrfs_update_time(struct inode *inode, enum fs_update_time type,
 +              unsigned int flags)
  {
        struct btrfs_root *root = BTRFS_I(inode)->root;
 -      bool dirty;
 +      int dirty;
  
        if (btrfs_root_readonly(root))
                return -EROFS;
 +      if (flags & IOCB_NOWAIT)
 +              return -EAGAIN;
  
 -      dirty = inode_update_timestamps(inode, flags);
 -      return dirty ? btrfs_dirty_inode(BTRFS_I(inode)) : 0;
 +      dirty = inode_update_time(inode, type, flags);
 +      if (dirty <= 0)
 +              return dirty;
 +      return btrfs_dirty_inode(BTRFS_I(inode));
  }
  
  /*
@@@ -6612,6 -6610,25 +6612,25 @@@ int btrfs_create_new_inode(struct btrfs
        int ret;
        bool xa_reserved = false;
  
+       if (!args->orphan && !args->subvol) {
+               /*
+                * Before anything else, check if we can add the name to the
+                * parent directory. We want to avoid a dir item overflow in
+                * case we have an existing dir item due to existing name
+                * hash collisions. We do this check here before we call
+                * btrfs_add_link() down below so that we can avoid a
+                * transaction abort (which could be exploited by malicious
+                * users).
+                *
+                * For subvolumes we already do this in btrfs_mksubvol().
+                */
+               ret = btrfs_check_dir_item_collision(BTRFS_I(dir)->root,
+                                                    btrfs_ino(BTRFS_I(dir)),
+                                                    name);
+               if (ret < 0)
+                       return ret;
+       }
        path = btrfs_alloc_path();
        if (!path)
                return -ENOMEM;
@@@ -8171,6 -8188,9 +8190,6 @@@ static void init_once(void *foo
        struct btrfs_inode *ei = foo;
  
        inode_init_once(&ei->vfs_inode);
 -#ifdef CONFIG_FS_VERITY
 -      ei->i_verity_info = NULL;
 -#endif
  }
  
  void __cold btrfs_destroy_cachep(void)
@@@ -8854,7 -8874,7 +8873,7 @@@ static struct btrfs_delalloc_work *btrf
  {
        struct btrfs_delalloc_work *work;
  
 -      work = kmalloc(sizeof(*work), GFP_NOFS);
 +      work = kmalloc_obj(*work, GFP_NOFS);
        if (!work)
                return NULL;
  
@@@ -9553,7 -9573,7 +9572,7 @@@ int btrfs_encoded_read_regular_fill_pag
         * needs longer time span.
         */
        if (uring_ctx) {
 -              priv = kmalloc(sizeof(struct btrfs_encoded_read_private), GFP_NOFS);
 +              priv = kmalloc_obj(struct btrfs_encoded_read_private, GFP_NOFS);
                if (!priv)
                        return -ENOMEM;
        } else {
@@@ -9623,7 -9643,7 +9642,7 @@@ ssize_t btrfs_encoded_read_regular(stru
        ssize_t ret;
  
        nr_pages = DIV_ROUND_UP(disk_io_size, PAGE_SIZE);
 -      pages = kcalloc(nr_pages, sizeof(struct page *), GFP_NOFS);
 +      pages = kzalloc_objs(struct page *, nr_pages, GFP_NOFS);
        if (!pages)
                return -ENOMEM;
        ret = btrfs_alloc_page_array(nr_pages, pages, false);
@@@ -10107,7 -10127,7 +10126,7 @@@ static int btrfs_add_swapfile_pin(struc
        struct rb_node **p;
        struct rb_node *parent = NULL;
  
 -      sp = kmalloc(sizeof(*sp), GFP_NOFS);
 +      sp = kmalloc_obj(*sp, GFP_NOFS);
        if (!sp)
                return -ENOMEM;
        sp->ptr = ptr;
@@@ -10677,7 -10697,6 +10696,7 @@@ static const struct file_operations btr
  #endif
        .release        = btrfs_release_file,
        .fsync          = btrfs_sync_file,
 +      .setlease       = generic_setlease,
  };
  
  /*
diff --combined fs/btrfs/ioctl.c
index a1fd44c44ecf7dd31ee990385e636a53f3b1c133,7d86e9c8909ec1c69d3b7c6f6007fea146e9acc8..b805dd9227efa21e8e7506665a639233be6faeda
@@@ -672,6 -672,13 +672,13 @@@ static noinline int create_subvol(struc
                goto out;
        }
  
+       /*
+        * Subvolumes have orphans cleaned on first dentry lookup. A new
+        * subvolume cannot have any orphans, so we should set the bit before we
+        * add the subvolume dentry to the dentry cache, so that it is in the
+        * same state as a subvolume after first lookup.
+        */
+       set_bit(BTRFS_ROOT_ORPHAN_CLEANUP, &new_root->state);
        d_instantiate_new(dentry, new_inode_args.inode);
        new_inode_args.inode = NULL;
  
@@@ -726,14 -733,15 +733,14 @@@ static int create_snapshot(struct btrfs
                return -ETXTBSY;
        }
  
 -      pending_snapshot = kzalloc(sizeof(*pending_snapshot), GFP_KERNEL);
 +      pending_snapshot = kzalloc_obj(*pending_snapshot);
        if (!pending_snapshot)
                return -ENOMEM;
  
        ret = get_anon_bdev(&pending_snapshot->anon_dev);
        if (ret < 0)
                goto free_pending;
 -      pending_snapshot->root_item = kzalloc(sizeof(struct btrfs_root_item),
 -                      GFP_KERNEL);
 +      pending_snapshot->root_item = kzalloc_obj(struct btrfs_root_item);
        pending_snapshot->path = btrfs_alloc_path();
        if (!pending_snapshot->root_item || !pending_snapshot->path) {
                ret = -ENOMEM;
@@@ -814,6 -822,75 +821,6 @@@ free_pending
        return ret;
  }
  
 -/*  copy of may_delete in fs/namei.c()
 - *    Check whether we can remove a link victim from directory dir, check
 - *  whether the type of victim is right.
 - *  1. We can't do it if dir is read-only (done in permission())
 - *  2. We should have write and exec permissions on dir
 - *  3. We can't remove anything from append-only dir
 - *  4. We can't do anything with immutable dir (done in permission())
 - *  5. If the sticky bit on dir is set we should either
 - *    a. be owner of dir, or
 - *    b. be owner of victim, or
 - *    c. have CAP_FOWNER capability
 - *  6. If the victim is append-only or immutable we can't do anything with
 - *     links pointing to it.
 - *  7. If we were asked to remove a directory and victim isn't one - ENOTDIR.
 - *  8. If we were asked to remove a non-directory and victim isn't one - EISDIR.
 - *  9. We can't remove a root or mountpoint.
 - * 10. We don't allow removal of NFS sillyrenamed files; it's handled by
 - *     nfs_async_unlink().
 - */
 -
 -static int btrfs_may_delete(struct mnt_idmap *idmap,
 -                          struct inode *dir, struct dentry *victim, int isdir)
 -{
 -      int ret;
 -
 -      if (d_really_is_negative(victim))
 -              return -ENOENT;
 -
 -      /* The @victim is not inside @dir. */
 -      if (d_inode(victim->d_parent) != dir)
 -              return -EINVAL;
 -      audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE);
 -
 -      ret = inode_permission(idmap, dir, MAY_WRITE | MAY_EXEC);
 -      if (ret)
 -              return ret;
 -      if (IS_APPEND(dir))
 -              return -EPERM;
 -      if (check_sticky(idmap, dir, d_inode(victim)) ||
 -          IS_APPEND(d_inode(victim)) || IS_IMMUTABLE(d_inode(victim)) ||
 -          IS_SWAPFILE(d_inode(victim)))
 -              return -EPERM;
 -      if (isdir) {
 -              if (!d_is_dir(victim))
 -                      return -ENOTDIR;
 -              if (IS_ROOT(victim))
 -                      return -EBUSY;
 -      } else if (d_is_dir(victim))
 -              return -EISDIR;
 -      if (IS_DEADDIR(dir))
 -              return -ENOENT;
 -      if (victim->d_flags & DCACHE_NFSFS_RENAMED)
 -              return -EBUSY;
 -      return 0;
 -}
 -
 -/* copy of may_create in fs/namei.c() */
 -static inline int btrfs_may_create(struct mnt_idmap *idmap,
 -                                 struct inode *dir, const struct dentry *child)
 -{
 -      if (d_really_is_positive(child))
 -              return -EEXIST;
 -      if (IS_DEADDIR(dir))
 -              return -ENOENT;
 -      if (!fsuidgid_has_mapping(dir->i_sb, idmap))
 -              return -EOVERFLOW;
 -      return inode_permission(idmap, dir, MAY_WRITE | MAY_EXEC);
 -}
 -
  /*
   * Create a new subvolume below @parent.  This is largely modeled after
   * sys_mkdirat and vfs_mkdir, but we only do a single component lookup
@@@ -835,7 -912,7 +842,7 @@@ static noinline int btrfs_mksubvol(stru
        if (IS_ERR(dentry))
                return PTR_ERR(dentry);
  
 -      ret = btrfs_may_create(idmap, dir, dentry);
 +      ret = may_create_dentry(idmap, dir, dentry);
        if (ret)
                goto out_dput;
  
@@@ -1957,7 -2034,7 +1964,7 @@@ static int btrfs_ioctl_get_subvol_info(
        if (!path)
                return -ENOMEM;
  
 -      subvol_info = kzalloc(sizeof(*subvol_info), GFP_KERNEL);
 +      subvol_info = kzalloc_obj(*subvol_info);
        if (!subvol_info) {
                btrfs_free_path(path);
                return -ENOMEM;
@@@ -2340,7 -2417,7 +2347,7 @@@ static noinline int btrfs_ioctl_snap_de
        }
  
        /* check if subvolume may be deleted by a user */
 -      ret = btrfs_may_delete(idmap, dir, dentry, 1);
 +      ret = may_delete_dentry(idmap, dir, dentry, true);
        if (ret)
                goto out_end_removing;
  
@@@ -3422,7 -3499,7 +3429,7 @@@ static long btrfs_ioctl_balance(struct 
                goto out_unlock;
        }
  
 -      bctl = kzalloc(sizeof(*bctl), GFP_KERNEL);
 +      bctl = kzalloc_obj(*bctl);
        if (!bctl) {
                ret = -ENOMEM;
                goto out_unlock;
@@@ -3603,7 -3680,7 +3610,7 @@@ static long btrfs_ioctl_qgroup_assign(s
        }
  
        if (sa->assign) {
 -              prealloc = kzalloc(sizeof(*prealloc), GFP_KERNEL);
 +              prealloc = kzalloc_obj(*prealloc);
                if (!prealloc) {
                        ret = -ENOMEM;
                        goto out;
@@@ -3852,6 -3929,25 +3859,25 @@@ static long _btrfs_ioctl_set_received_s
                goto out;
        }
  
+       received_uuid_changed = memcmp(root_item->received_uuid, sa->uuid,
+                                      BTRFS_UUID_SIZE);
+       /*
+        * Before we attempt to add the new received uuid, check if we have room
+        * for it in case there's already an item. If the size of the existing
+        * item plus this root's ID (u64) exceeds the maximum item size, we can
+        * return here without the need to abort a transaction. If we don't do
+        * this check, the btrfs_uuid_tree_add() call below would fail with
+        * -EOVERFLOW and result in a transaction abort. Malicious users could
+        * exploit this to turn the fs into RO mode.
+        */
+       if (received_uuid_changed && !btrfs_is_empty_uuid(sa->uuid)) {
+               ret = btrfs_uuid_tree_check_overflow(fs_info, sa->uuid,
+                                                    BTRFS_UUID_KEY_RECEIVED_SUBVOL);
+               if (ret < 0)
+                       goto out;
+       }
        /*
         * 1 - root item
         * 2 - uuid items (received uuid + subvol uuid)
        sa->rtime.sec = ct.tv_sec;
        sa->rtime.nsec = ct.tv_nsec;
  
-       received_uuid_changed = memcmp(root_item->received_uuid, sa->uuid,
-                                      BTRFS_UUID_SIZE);
        if (received_uuid_changed &&
            !btrfs_is_empty_uuid(root_item->received_uuid)) {
                ret = btrfs_uuid_tree_remove(trans, root_item->received_uuid,
                                          BTRFS_UUID_KEY_RECEIVED_SUBVOL,
                                          btrfs_root_id(root));
                if (unlikely(ret && ret != -ENOENT)) {
-                       btrfs_abort_transaction(trans, ret);
                        btrfs_end_transaction(trans);
                        goto out;
                }
  
        ret = btrfs_update_root(trans, fs_info->tree_root,
                                &root->root_key, &root->root_item);
-       if (ret < 0) {
+       if (unlikely(ret < 0)) {
+               btrfs_abort_transaction(trans, ret);
                btrfs_end_transaction(trans);
                goto out;
        }
@@@ -3923,7 -4017,7 +3947,7 @@@ static long btrfs_ioctl_set_received_su
        if (IS_ERR(args32))
                return PTR_ERR(args32);
  
 -      args64 = kmalloc(sizeof(*args64), GFP_KERNEL);
 +      args64 = kmalloc_obj(*args64);
        if (!args64) {
                ret = -ENOMEM;
                goto out;
@@@ -4233,7 -4327,7 +4257,7 @@@ static int _btrfs_ioctl_send(struct btr
                ret = copy_from_user(&args32, argp, sizeof(args32));
                if (ret)
                        return -EFAULT;
 -              arg = kzalloc(sizeof(*arg), GFP_KERNEL);
 +              arg = kzalloc_obj(*arg);
                if (!arg)
                        return -ENOMEM;
                arg->send_fd = args32.send_fd;
@@@ -4587,7 -4681,7 +4611,7 @@@ static int btrfs_uring_read_extent(stru
        int ret;
  
        nr_pages = DIV_ROUND_UP(disk_io_size, PAGE_SIZE);
 -      pages = kcalloc(nr_pages, sizeof(struct page *), GFP_NOFS);
 +      pages = kzalloc_objs(struct page *, nr_pages, GFP_NOFS);
        if (!pages)
                return -ENOMEM;
        ret = btrfs_alloc_page_array(nr_pages, pages, 0);
                goto out_fail;
        }
  
 -      priv = kmalloc(sizeof(*priv), GFP_NOFS);
 +      priv = kmalloc_obj(*priv, GFP_NOFS);
        if (!priv) {
                ret = -ENOMEM;
                goto out_fail;
@@@ -4686,7 -4780,7 +4710,7 @@@ static int btrfs_uring_encoded_read(str
        }
  
        if (!data) {
 -              data = kzalloc(sizeof(*data), GFP_NOFS);
 +              data = kzalloc_obj(*data, GFP_NOFS);
                if (!data) {
                        ret = -ENOMEM;
                        goto out_acct;
@@@ -4821,7 -4915,7 +4845,7 @@@ static int btrfs_uring_encoded_write(st
        }
  
        if (!data) {
 -              data = kzalloc(sizeof(*data), GFP_NOFS);
 +              data = kzalloc_obj(*data, GFP_NOFS);
                if (!data) {
                        ret = -ENOMEM;
                        goto out_acct;
diff --combined fs/btrfs/relocation.c
index a330d8624b837ce2c107f2953a4f6f1a06a66803,fcfbe1b1dab44e8b262680f5773faa158a311bc9..b2343aed7a5d0d6140f94727fb54ba49bbcec818
@@@ -483,7 -483,7 +483,7 @@@ static int __add_reloc_root(struct btrf
        struct mapping_node *node;
        struct reloc_control *rc = fs_info->reloc_ctl;
  
 -      node = kmalloc(sizeof(*node), GFP_NOFS);
 +      node = kmalloc_obj(*node, GFP_NOFS);
        if (!node)
                return -ENOMEM;
  
@@@ -3115,7 -3115,7 +3115,7 @@@ static int add_tree_block(struct reloc_
  
        BUG_ON(level == -1);
  
 -      block = kmalloc(sizeof(*block), GFP_NOFS);
 +      block = kmalloc_obj(*block, GFP_NOFS);
        if (!block)
                return -ENOMEM;
  
@@@ -3813,7 -3813,7 +3813,7 @@@ static struct reloc_control *alloc_relo
  {
        struct reloc_control *rc;
  
 -      rc = kzalloc(sizeof(*rc), GFP_NOFS);
 +      rc = kzalloc_obj(*rc, GFP_NOFS);
        if (!rc)
                return NULL;
  
@@@ -4042,7 -4042,7 +4042,7 @@@ static int copy_remapped_data(struct bt
        struct reloc_io_private priv;
        unsigned int nr_pages = DIV_ROUND_UP(length, PAGE_SIZE);
  
 -      pages = kcalloc(nr_pages, sizeof(struct page *), GFP_NOFS);
 +      pages = kzalloc_objs(struct page *, nr_pages, GFP_NOFS);
        if (!pages)
                return -ENOMEM;
  
@@@ -4399,6 -4399,8 +4399,8 @@@ static int move_existing_remaps(struct 
  
                                leaf = path->nodes[0];
                        }
+                       btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
                }
  
                remap = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_remap_item);
diff --combined fs/btrfs/space-info.c
index 52a267a5dd801d13940aa105d9abdbb28a38468d,36bfd2385b2add2c8f6a90ecb835f8c946737903..87cbc051cb12ffb017ec8c84039f7d6fa0a26a60
@@@ -266,7 -266,7 +266,7 @@@ static int create_space_info_sub_group(
               "parent->subgroup_id=%d", parent->subgroup_id);
        ASSERT(id != BTRFS_SUB_GROUP_PRIMARY, "id=%d", id);
  
 -      sub_group = kzalloc(sizeof(*sub_group), GFP_NOFS);
 +      sub_group = kzalloc_obj(*sub_group, GFP_NOFS);
        if (!sub_group)
                return -ENOMEM;
  
@@@ -289,7 -289,7 +289,7 @@@ static int create_space_info(struct btr
        struct btrfs_space_info *space_info;
        int ret = 0;
  
 -      space_info = kzalloc(sizeof(*space_info), GFP_NOFS);
 +      space_info = kzalloc_obj(*space_info, GFP_NOFS);
        if (!space_info)
                return -ENOMEM;
  
@@@ -2194,8 -2194,11 +2194,11 @@@ void btrfs_reclaim_sweep(const struct b
                if (!btrfs_should_periodic_reclaim(space_info))
                        continue;
                for (raid = 0; raid < BTRFS_NR_RAID_TYPES; raid++) {
-                       if (do_reclaim_sweep(space_info, raid))
+                       if (do_reclaim_sweep(space_info, raid)) {
+                               spin_lock(&space_info->lock);
                                btrfs_set_periodic_reclaim_ready(space_info, false);
+                               spin_unlock(&space_info->lock);
+                       }
                }
        }
  }
diff --combined fs/btrfs/transaction.c
index 7ef8c9b7dfc17a5133b6d2dc134e288975ed98d1,8d887ffcdba1dc835ede7890c1ab7947f8665041..8dd77c431974d1a1a1ecf5583049c977046f3f5c
@@@ -315,7 -315,7 +315,7 @@@ loop
         */
        BUG_ON(type == TRANS_JOIN_NOLOCK);
  
 -      cur_trans = kmalloc(sizeof(*cur_trans), GFP_NOFS);
 +      cur_trans = kmalloc_obj(*cur_trans, GFP_NOFS);
        if (!cur_trans)
                return -ENOMEM;
  
@@@ -1905,6 -1905,22 +1905,22 @@@ static noinline int create_pending_snap
                ret = btrfs_uuid_tree_add(trans, new_root_item->received_uuid,
                                          BTRFS_UUID_KEY_RECEIVED_SUBVOL,
                                          objectid);
+               /*
+                * We are creating of lot of snapshots of the same root that was
+                * received (has a received UUID) and reached a leaf's limit for
+                * an item. We can safely ignore this and avoid a transaction
+                * abort. A deletion of this snapshot will still work since we
+                * ignore if an item with a BTRFS_UUID_KEY_RECEIVED_SUBVOL key
+                * is missing (see btrfs_delete_subvolume()). Send/receive will
+                * work too since it peeks the first root id from the existing
+                * item (it could peek any), and in case it's missing it
+                * falls back to search by BTRFS_UUID_KEY_SUBVOL keys.
+                * Creation of a snapshot does not require CAP_SYS_ADMIN, so
+                * we don't want users triggering transaction aborts, either
+                * intentionally or not.
+                */
+               if (ret == -EOVERFLOW)
+                       ret = 0;
                if (unlikely(ret && ret != -EEXIST)) {
                        btrfs_abort_transaction(trans, ret);
                        goto fail;