]> Git Repo - J-linux.git/commitdiff
Merge tag 'for-5.12-rc3-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave...
authorLinus Torvalds <[email protected]>
Thu, 18 Mar 2021 20:38:42 +0000 (13:38 -0700)
committerLinus Torvalds <[email protected]>
Thu, 18 Mar 2021 20:38:42 +0000 (13:38 -0700)
Pull btrfs fixes from David Sterba:
 "There are still regressions being found and fixed in the zoned mode
  and subpage code, the rest are fixes for bugs reported by users.

  Regressions:

   - subpage block support:
      - readahead works on the proper block size
      - fix last page zeroing

   - zoned mode:
      - linked list corruption for tree log

  Fixes:

   - qgroup leak after falloc failure

   - tree mod log and backref resolving:
      - extent buffer cloning race when resolving backrefs
      - pin deleted leaves with active tree mod log users

   - drop debugging flag from slab cache"

* tag 'for-5.12-rc3-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
  btrfs: always pin deleted leaves when there are active tree mod log users
  btrfs: fix race when cloning extent buffer during rewind of an old root
  btrfs: fix slab cache flags for free space tree bitmap
  btrfs: subpage: make readahead work properly
  btrfs: subpage: fix wild pointer access during metadata read failure
  btrfs: zoned: fix linked list corruption after log root tree allocation failure
  btrfs: fix qgroup data rsv leak caused by falloc failure
  btrfs: track qgroup released data in own variable in insert_prealloc_file_extent
  btrfs: fix wrong offset to zero out range beyond i_size

1  2 
fs/btrfs/extent_io.c
fs/btrfs/inode.c

diff --combined fs/btrfs/extent_io.c
index 191e358f1322df75a7a5c7cfb0bc7e27f3d51215,0d00a9cd123a872a4c1128da0de913084b75d37f..910769d5fcdb4998ca5ba004087cf7537bfff132
@@@ -2885,6 -2885,35 +2885,35 @@@ static void end_page_read(struct page *
                btrfs_subpage_end_reader(fs_info, page, start, len);
  }
  
+ /*
+  * Find extent buffer for a givne bytenr.
+  *
+  * This is for end_bio_extent_readpage(), thus we can't do any unsafe locking
+  * in endio context.
+  */
+ static struct extent_buffer *find_extent_buffer_readpage(
+               struct btrfs_fs_info *fs_info, struct page *page, u64 bytenr)
+ {
+       struct extent_buffer *eb;
+       /*
+        * For regular sectorsize, we can use page->private to grab extent
+        * buffer
+        */
+       if (fs_info->sectorsize == PAGE_SIZE) {
+               ASSERT(PagePrivate(page) && page->private);
+               return (struct extent_buffer *)page->private;
+       }
+       /* For subpage case, we need to lookup buffer radix tree */
+       rcu_read_lock();
+       eb = radix_tree_lookup(&fs_info->buffer_radix,
+                              bytenr >> fs_info->sectorsize_bits);
+       rcu_read_unlock();
+       ASSERT(eb);
+       return eb;
+ }
  /*
   * after a readpage IO is done, we need to:
   * clear the uptodate bits on error
@@@ -2996,7 -3025,7 +3025,7 @@@ static void end_bio_extent_readpage(str
                } else {
                        struct extent_buffer *eb;
  
-                       eb = (struct extent_buffer *)page->private;
+                       eb = find_extent_buffer_readpage(fs_info, page, start);
                        set_bit(EXTENT_BUFFER_READ_ERR, &eb->bflags);
                        eb->read_mirror = mirror;
                        atomic_dec(&eb->io_pages);
@@@ -3020,7 -3049,7 +3049,7 @@@ readpage_ok
                         */
                        if (page->index == end_index && i_size <= end) {
                                u32 zero_start = max(offset_in_page(i_size),
-                                                    offset_in_page(end));
+                                                    offset_in_page(start));
  
                                zero_user_segment(page, zero_start,
                                                  offset_in_page(end) + 1);
@@@ -3059,7 -3088,7 +3088,7 @@@ struct bio *btrfs_bio_alloc(u64 first_b
  {
        struct bio *bio;
  
 -      bio = bio_alloc_bioset(GFP_NOFS, BIO_MAX_PAGES, &btrfs_bioset);
 +      bio = bio_alloc_bioset(GFP_NOFS, BIO_MAX_VECS, &btrfs_bioset);
        bio->bi_iter.bi_sector = first_byte >> 9;
        btrfs_io_bio_init(btrfs_io_bio(bio));
        return bio;
diff --combined fs/btrfs/inode.c
index 35bfa0533f233e0f9c20259ff64d6d6d6215f9b7,5092dea21448c7f2d0b29ddefa5b2d787aa1984f..7cdf65be3707cd4c1602de86698488b84e97bf3f
@@@ -5210,8 -5210,7 +5210,8 @@@ static int btrfs_setsize(struct inode *
        return ret;
  }
  
 -static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
 +static int btrfs_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
 +                       struct iattr *attr)
  {
        struct inode *inode = d_inode(dentry);
        struct btrfs_root *root = BTRFS_I(inode)->root;
        if (btrfs_root_readonly(root))
                return -EROFS;
  
 -      err = setattr_prepare(dentry, attr);
 +      err = setattr_prepare(&init_user_ns, dentry, attr);
        if (err)
                return err;
  
        }
  
        if (attr->ia_valid) {
 -              setattr_copy(inode, attr);
 +              setattr_copy(&init_user_ns, inode, attr);
                inode_inc_iversion(inode);
                err = btrfs_dirty_inode(inode);
  
                if (!err && attr->ia_valid & ATTR_MODE)
 -                      err = posix_acl_chmod(inode, inode->i_mode);
 +                      err = posix_acl_chmod(&init_user_ns, inode,
 +                                            inode->i_mode);
        }
  
        return err;
@@@ -6357,7 -6355,7 +6357,7 @@@ static struct inode *btrfs_new_inode(st
        if (ret != 0)
                goto fail_unlock;
  
 -      inode_init_owner(inode, dir, mode);
 +      inode_init_owner(&init_user_ns, inode, dir, mode);
        inode_set_bytes(inode, 0);
  
        inode->i_mtime = current_time(inode);
@@@ -6518,8 -6516,8 +6518,8 @@@ static int btrfs_add_nondir(struct btrf
        return err;
  }
  
 -static int btrfs_mknod(struct inode *dir, struct dentry *dentry,
 -                      umode_t mode, dev_t rdev)
 +static int btrfs_mknod(struct user_namespace *mnt_userns, struct inode *dir,
 +                     struct dentry *dentry, umode_t mode, dev_t rdev)
  {
        struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
        struct btrfs_trans_handle *trans;
@@@ -6582,8 -6580,8 +6582,8 @@@ out_unlock
        return err;
  }
  
 -static int btrfs_create(struct inode *dir, struct dentry *dentry,
 -                      umode_t mode, bool excl)
 +static int btrfs_create(struct user_namespace *mnt_userns, struct inode *dir,
 +                      struct dentry *dentry, umode_t mode, bool excl)
  {
        struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
        struct btrfs_trans_handle *trans;
@@@ -6727,8 -6725,7 +6727,8 @@@ fail
        return err;
  }
  
 -static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 +static int btrfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
 +                     struct dentry *dentry, umode_t mode)
  {
        struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
        struct inode *inode = NULL;
@@@ -9008,7 -9005,7 +9008,7 @@@ int __init btrfs_init_cachep(void
  
        btrfs_free_space_bitmap_cachep = kmem_cache_create("btrfs_free_space_bitmap",
                                                        PAGE_SIZE, PAGE_SIZE,
-                                                       SLAB_RED_ZONE, NULL);
+                                                       SLAB_MEM_SPREAD, NULL);
        if (!btrfs_free_space_bitmap_cachep)
                goto fail;
  
@@@ -9018,8 -9015,7 +9018,8 @@@ fail
        return -ENOMEM;
  }
  
 -static int btrfs_getattr(const struct path *path, struct kstat *stat,
 +static int btrfs_getattr(struct user_namespace *mnt_userns,
 +                       const struct path *path, struct kstat *stat,
                         u32 request_mask, unsigned int flags)
  {
        u64 delalloc_bytes;
                                  STATX_ATTR_IMMUTABLE |
                                  STATX_ATTR_NODUMP);
  
 -      generic_fillattr(inode, stat);
 +      generic_fillattr(&init_user_ns, inode, stat);
        stat->dev = BTRFS_I(inode)->root->anon_dev;
  
        spin_lock(&BTRFS_I(inode)->lock);
@@@ -9536,9 -9532,9 +9536,9 @@@ out_notrans
        return ret;
  }
  
 -static int btrfs_rename2(struct inode *old_dir, struct dentry *old_dentry,
 -                       struct inode *new_dir, struct dentry *new_dentry,
 -                       unsigned int flags)
 +static int btrfs_rename2(struct user_namespace *mnt_userns, struct inode *old_dir,
 +                       struct dentry *old_dentry, struct inode *new_dir,
 +                       struct dentry *new_dentry, unsigned int flags)
  {
        if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT))
                return -EINVAL;
@@@ -9746,8 -9742,8 +9746,8 @@@ out
        return ret;
  }
  
 -static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
 -                       const char *symname)
 +static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
 +                       struct dentry *dentry, const char *symname)
  {
        struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
        struct btrfs_trans_handle *trans;
@@@ -9877,6 -9873,7 +9877,7 @@@ static struct btrfs_trans_handle *inser
        struct btrfs_path *path;
        u64 start = ins->objectid;
        u64 len = ins->offset;
+       int qgroup_released;
        int ret;
  
        memset(&stack_fi, 0, sizeof(stack_fi));
        btrfs_set_stack_file_extent_compression(&stack_fi, BTRFS_COMPRESS_NONE);
        /* Encryption and other encoding is reserved and all 0 */
  
-       ret = btrfs_qgroup_release_data(inode, file_offset, len);
-       if (ret < 0)
-               return ERR_PTR(ret);
+       qgroup_released = btrfs_qgroup_release_data(inode, file_offset, len);
+       if (qgroup_released < 0)
+               return ERR_PTR(qgroup_released);
  
        if (trans) {
                ret = insert_reserved_file_extent(trans, inode,
                                                  file_offset, &stack_fi,
-                                                 true, ret);
+                                                 true, qgroup_released);
                if (ret)
-                       return ERR_PTR(ret);
+                       goto free_qgroup;
                return trans;
        }
  
        extent_info.file_offset = file_offset;
        extent_info.extent_buf = (char *)&stack_fi;
        extent_info.is_new_extent = true;
-       extent_info.qgroup_reserved = ret;
+       extent_info.qgroup_reserved = qgroup_released;
        extent_info.insertions = 0;
  
        path = btrfs_alloc_path();
-       if (!path)
-               return ERR_PTR(-ENOMEM);
+       if (!path) {
+               ret = -ENOMEM;
+               goto free_qgroup;
+       }
  
        ret = btrfs_replace_file_extents(&inode->vfs_inode, path, file_offset,
                                     file_offset + len - 1, &extent_info,
                                     &trans);
        btrfs_free_path(path);
        if (ret)
-               return ERR_PTR(ret);
+               goto free_qgroup;
        return trans;
+ free_qgroup:
+       /*
+        * We have released qgroup data range at the beginning of the function,
+        * and normally qgroup_released bytes will be freed when committing
+        * transaction.
+        * But if we error out early, we have to free what we have released
+        * or we leak qgroup data reservation.
+        */
+       btrfs_qgroup_free_refroot(inode->root->fs_info,
+                       inode->root->root_key.objectid, qgroup_released,
+                       BTRFS_QGROUP_RSV_DATA);
+       return ERR_PTR(ret);
  }
  
  static int __btrfs_prealloc_file_range(struct inode *inode, int mode,
@@@ -10081,8 -10092,7 +10096,8 @@@ static int btrfs_set_page_dirty(struct 
        return __set_page_dirty_nobuffers(page);
  }
  
 -static int btrfs_permission(struct inode *inode, int mask)
 +static int btrfs_permission(struct user_namespace *mnt_userns,
 +                          struct inode *inode, int mask)
  {
        struct btrfs_root *root = BTRFS_I(inode)->root;
        umode_t mode = inode->i_mode;
                if (BTRFS_I(inode)->flags & BTRFS_INODE_READONLY)
                        return -EACCES;
        }
 -      return generic_permission(inode, mask);
 +      return generic_permission(&init_user_ns, inode, mask);
  }
  
 -static int btrfs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
 +static int btrfs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
 +                       struct dentry *dentry, umode_t mode)
  {
        struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
        struct btrfs_trans_handle *trans;
This page took 0.126406 seconds and 4 git commands to generate.