Merge tag 'for-6.3-rc4-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 2 Apr 2023 17:57:12 +0000 (10:57 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 2 Apr 2023 17:57:12 +0000 (10:57 -0700)
Pull btrfs fixes from David Sterba:

 - scan block devices in non-exclusive mode to avoid temporary mkfs
   failures

 - fix race between quota disable and quota assign ioctls

 - fix deadlock when aborting transaction during relocation with scrub

 - ignore fiemap path cache when there are multiple paths for a node

* tag 'for-6.3-rc4-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
  btrfs: ignore fiemap path cache when there are multiple paths for a node
  btrfs: fix deadlock when aborting transaction during relocation with scrub
  btrfs: scan device in non-exclusive mode
  btrfs: fix race between quota disable and quota assign ioctls

1  2 
fs/btrfs/ioctl.c

diff --combined fs/btrfs/ioctl.c
index a0ef1a1784c79be72102a5146c1d016633e6b46c,f9dbf41fc8039f721b6fe40c565ba8ac5c825c5c..ba769a1eb87ab24e535576b37db26e50be58b02b
@@@ -243,7 -243,7 +243,7 @@@ int btrfs_fileattr_get(struct dentry *d
        return 0;
  }
  
 -int btrfs_fileattr_set(struct user_namespace *mnt_userns,
 +int btrfs_fileattr_set(struct mnt_idmap *idmap,
                       struct dentry *dentry, struct fileattr *fa)
  {
        struct inode *inode = d_inode(dentry);
@@@ -578,7 -578,7 +578,7 @@@ static unsigned int create_subvol_num_i
        return num_items;
  }
  
 -static noinline int create_subvol(struct user_namespace *mnt_userns,
 +static noinline int create_subvol(struct mnt_idmap *idmap,
                                  struct inode *dir, struct dentry *dentry,
                                  struct btrfs_qgroup_inherit *inherit)
  {
        if (ret < 0)
                goto out_root_item;
  
 -      new_inode_args.inode = btrfs_new_subvol_inode(mnt_userns, dir);
 +      new_inode_args.inode = btrfs_new_subvol_inode(idmap, dir);
        if (!new_inode_args.inode) {
                ret = -ENOMEM;
                goto out_anon_dev;
@@@ -898,7 -898,7 +898,7 @@@ free_pending
   *     nfs_async_unlink().
   */
  
 -static int btrfs_may_delete(struct user_namespace *mnt_userns,
 +static int btrfs_may_delete(struct mnt_idmap *idmap,
                            struct inode *dir, struct dentry *victim, int isdir)
  {
        int error;
        BUG_ON(d_inode(victim->d_parent) != dir);
        audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE);
  
 -      error = inode_permission(mnt_userns, dir, MAY_WRITE | MAY_EXEC);
 +      error = inode_permission(idmap, dir, MAY_WRITE | MAY_EXEC);
        if (error)
                return error;
        if (IS_APPEND(dir))
                return -EPERM;
 -      if (check_sticky(mnt_userns, dir, d_inode(victim)) ||
 +      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;
  }
  
  /* copy of may_create in fs/namei.c() */
 -static inline int btrfs_may_create(struct user_namespace *mnt_userns,
 +static inline int btrfs_may_create(struct mnt_idmap *idmap,
                                   struct inode *dir, struct dentry *child)
  {
        if (d_really_is_positive(child))
                return -EEXIST;
        if (IS_DEADDIR(dir))
                return -ENOENT;
 -      if (!fsuidgid_has_mapping(dir->i_sb, mnt_userns))
 +      if (!fsuidgid_has_mapping(dir->i_sb, idmap))
                return -EOVERFLOW;
 -      return inode_permission(mnt_userns, dir, MAY_WRITE | MAY_EXEC);
 +      return inode_permission(idmap, dir, MAY_WRITE | MAY_EXEC);
  }
  
  /*
   * inside this filesystem so it's quite a bit simpler.
   */
  static noinline int btrfs_mksubvol(const struct path *parent,
 -                                 struct user_namespace *mnt_userns,
 +                                 struct mnt_idmap *idmap,
                                   const char *name, int namelen,
                                   struct btrfs_root *snap_src,
                                   bool readonly,
        if (error == -EINTR)
                return error;
  
 -      dentry = lookup_one(mnt_userns, name, parent->dentry, namelen);
 +      dentry = lookup_one(idmap, name, parent->dentry, namelen);
        error = PTR_ERR(dentry);
        if (IS_ERR(dentry))
                goto out_unlock;
  
 -      error = btrfs_may_create(mnt_userns, dir, dentry);
 +      error = btrfs_may_create(idmap, dir, dentry);
        if (error)
                goto out_dput;
  
        if (snap_src)
                error = create_snapshot(snap_src, dir, dentry, readonly, inherit);
        else
 -              error = create_subvol(mnt_userns, dir, dentry, inherit);
 +              error = create_subvol(idmap, dir, dentry, inherit);
  
        if (!error)
                fsnotify_mkdir(dir, dentry);
@@@ -1007,7 -1007,7 +1007,7 @@@ out_unlock
  }
  
  static noinline int btrfs_mksnapshot(const struct path *parent,
 -                                 struct user_namespace *mnt_userns,
 +                                 struct mnt_idmap *idmap,
                                   const char *name, int namelen,
                                   struct btrfs_root *root,
                                   bool readonly,
  
        btrfs_wait_ordered_extents(root, U64_MAX, 0, (u64)-1);
  
 -      ret = btrfs_mksubvol(parent, mnt_userns, name, namelen,
 +      ret = btrfs_mksubvol(parent, idmap, name, namelen,
                             root, readonly, inherit);
  out:
        if (snapshot_force_cow)
@@@ -1240,7 -1240,7 +1240,7 @@@ out_drop
  }
  
  static noinline int __btrfs_ioctl_snap_create(struct file *file,
 -                              struct user_namespace *mnt_userns,
 +                              struct mnt_idmap *idmap,
                                const char *name, unsigned long fd, int subvol,
                                bool readonly,
                                struct btrfs_qgroup_inherit *inherit)
        }
  
        if (subvol) {
 -              ret = btrfs_mksubvol(&file->f_path, mnt_userns, name,
 +              ret = btrfs_mksubvol(&file->f_path, idmap, name,
                                     namelen, NULL, readonly, inherit);
        } else {
                struct fd src = fdget(fd);
                        btrfs_info(BTRFS_I(file_inode(file))->root->fs_info,
                                   "Snapshot src from another FS");
                        ret = -EXDEV;
 -              } else if (!inode_owner_or_capable(mnt_userns, src_inode)) {
 +              } else if (!inode_owner_or_capable(idmap, src_inode)) {
                        /*
                         * Subvolume creation is not restricted, but snapshots
                         * are limited to own subvolumes only
                         */
                        ret = -EPERM;
                } else {
 -                      ret = btrfs_mksnapshot(&file->f_path, mnt_userns,
 +                      ret = btrfs_mksnapshot(&file->f_path, idmap,
                                               name, namelen,
                                               BTRFS_I(src_inode)->root,
                                               readonly, inherit);
@@@ -1317,7 -1317,7 +1317,7 @@@ static noinline int btrfs_ioctl_snap_cr
                return PTR_ERR(vol_args);
        vol_args->name[BTRFS_PATH_NAME_MAX] = '\0';
  
 -      ret = __btrfs_ioctl_snap_create(file, file_mnt_user_ns(file),
 +      ret = __btrfs_ioctl_snap_create(file, file_mnt_idmap(file),
                                        vol_args->name, vol_args->fd, subvol,
                                        false, NULL);
  
@@@ -1377,7 -1377,7 +1377,7 @@@ static noinline int btrfs_ioctl_snap_cr
                }
        }
  
 -      ret = __btrfs_ioctl_snap_create(file, file_mnt_user_ns(file),
 +      ret = __btrfs_ioctl_snap_create(file, file_mnt_idmap(file),
                                        vol_args->name, vol_args->fd, subvol,
                                        readonly, inherit);
        if (ret)
@@@ -1422,7 -1422,7 +1422,7 @@@ static noinline int btrfs_ioctl_subvol_
        u64 flags;
        int ret = 0;
  
 -      if (!inode_owner_or_capable(file_mnt_user_ns(file), inode))
 +      if (!inode_owner_or_capable(file_mnt_idmap(file), inode))
                return -EPERM;
  
        ret = mnt_want_write_file(file);
@@@ -1870,7 -1870,7 +1870,7 @@@ out
        return ret;
  }
  
 -static int btrfs_search_path_in_tree_user(struct user_namespace *mnt_userns,
 +static int btrfs_search_path_in_tree_user(struct mnt_idmap *idmap,
                                struct inode *inode,
                                struct btrfs_ioctl_ino_lookup_user_args *args)
  {
                                ret = PTR_ERR(temp_inode);
                                goto out_put;
                        }
 -                      ret = inode_permission(mnt_userns, temp_inode,
 +                      ret = inode_permission(idmap, temp_inode,
                                               MAY_READ | MAY_EXEC);
                        iput(temp_inode);
                        if (ret) {
@@@ -2101,7 -2101,7 +2101,7 @@@ static int btrfs_ioctl_ino_lookup_user(
                return -EACCES;
        }
  
 -      ret = btrfs_search_path_in_tree_user(file_mnt_user_ns(file), inode, args);
 +      ret = btrfs_search_path_in_tree_user(file_mnt_idmap(file), inode, args);
  
        if (ret == 0 && copy_to_user(argp, args, sizeof(*args)))
                ret = -EFAULT;
@@@ -2335,7 -2335,7 +2335,7 @@@ static noinline int btrfs_ioctl_snap_de
        struct btrfs_root *dest = NULL;
        struct btrfs_ioctl_vol_args *vol_args = NULL;
        struct btrfs_ioctl_vol_args_v2 *vol_args2 = NULL;
 -      struct user_namespace *mnt_userns = file_mnt_user_ns(file);
 +      struct mnt_idmap *idmap = file_mnt_idmap(file);
        char *subvol_name, *subvol_name_ptr = NULL;
        int subvol_namelen;
        int err = 0;
                         * anywhere in the filesystem the user wouldn't be able
                         * to delete without an idmapped mount.
                         */
 -                      if (old_dir != dir && mnt_userns != &init_user_ns) {
 +                      if (old_dir != dir && idmap != &nop_mnt_idmap) {
                                err = -EOPNOTSUPP;
                                goto free_parent;
                        }
        err = down_write_killable_nested(&dir->i_rwsem, I_MUTEX_PARENT);
        if (err == -EINTR)
                goto free_subvol_name;
 -      dentry = lookup_one(mnt_userns, subvol_name, parent, subvol_namelen);
 +      dentry = lookup_one(idmap, subvol_name, parent, subvol_namelen);
        if (IS_ERR(dentry)) {
                err = PTR_ERR(dentry);
                goto out_unlock_dir;
                if (root == dest)
                        goto out_dput;
  
 -              err = inode_permission(mnt_userns, inode, MAY_WRITE | MAY_EXEC);
 +              err = inode_permission(idmap, inode, MAY_WRITE | MAY_EXEC);
                if (err)
                        goto out_dput;
        }
  
        /* check if subvolume may be deleted by a user */
 -      err = btrfs_may_delete(mnt_userns, dir, dentry, 1);
 +      err = btrfs_may_delete(idmap, dir, dentry, 1);
        if (err)
                goto out_dput;
  
@@@ -2582,7 -2582,7 +2582,7 @@@ static int btrfs_ioctl_defrag(struct fi
                 * running and allows defrag on files open in read-only mode.
                 */
                if (!capable(CAP_SYS_ADMIN) &&
 -                  inode_permission(&init_user_ns, inode, MAY_WRITE)) {
 +                  inode_permission(&nop_mnt_idmap, inode, MAY_WRITE)) {
                        ret = -EPERM;
                        goto out;
                }
@@@ -3732,7 -3732,9 +3732,9 @@@ static long btrfs_ioctl_qgroup_assign(s
        }
  
        /* update qgroup status and info */
+       mutex_lock(&fs_info->qgroup_ioctl_lock);
        err = btrfs_run_qgroups(trans);
+       mutex_unlock(&fs_info->qgroup_ioctl_lock);
        if (err < 0)
                btrfs_handle_fs_error(fs_info, err,
                                      "failed to update qgroup status and info");
@@@ -3908,7 -3910,7 +3910,7 @@@ static long btrfs_ioctl_quota_rescan_wa
  }
  
  static long _btrfs_ioctl_set_received_subvol(struct file *file,
 -                                          struct user_namespace *mnt_userns,
 +                                          struct mnt_idmap *idmap,
                                            struct btrfs_ioctl_received_subvol_args *sa)
  {
        struct inode *inode = file_inode(file);
        int ret = 0;
        int received_uuid_changed;
  
 -      if (!inode_owner_or_capable(mnt_userns, inode))
 +      if (!inode_owner_or_capable(idmap, inode))
                return -EPERM;
  
        ret = mnt_want_write_file(file);
@@@ -4025,7 -4027,7 +4027,7 @@@ static long btrfs_ioctl_set_received_su
        args64->rtime.nsec = args32->rtime.nsec;
        args64->flags = args32->flags;
  
 -      ret = _btrfs_ioctl_set_received_subvol(file, file_mnt_user_ns(file), args64);
 +      ret = _btrfs_ioctl_set_received_subvol(file, file_mnt_idmap(file), args64);
        if (ret)
                goto out;
  
@@@ -4059,7 -4061,7 +4061,7 @@@ static long btrfs_ioctl_set_received_su
        if (IS_ERR(sa))
                return PTR_ERR(sa);
  
 -      ret = _btrfs_ioctl_set_received_subvol(file, file_mnt_user_ns(file), sa);
 +      ret = _btrfs_ioctl_set_received_subvol(file, file_mnt_idmap(file), sa);
  
        if (ret)
                goto out;