On Mon, Jul 02, 2018 at 02:00:34PM +0300, Nikolay Borisov wrote: > Commit 5d23515be669 ("btrfs: Move qgroup rescan on quota enable to > btrfs_quota_enable") not only resulted in an easier to follow code but > it also introduced a subtle bug. It changed the timing when the initial > transaction rescan was happening - before the commit it would happen > after transaction commit had occured but after the commit it might happen > before the transaction was committed. This results in failure to > correctly rescan the quota since there could be data which is still not > committed on disk. > > This patch aims to fix this by movign the transaction creation/commit > inside btrfs_quota_enable, which allows to schedule the quota commit > after the transaction has been committed. > > Fixes: 5d23515be669 ("btrfs: Move qgroup rescan on quota enable to > btrfs_quota_enable") > Link: https://marc.info/?l=linux-btrfs&m=152999289017582
Please use https://lkml.kernel.org/r/<message-id> > Reported-by: Misono Tomohiro <misono.tomoh...@jp.fujitsu.com> > Reviewed-by: Misono Tomohiro <misono.tomoh...@jp.fujitsu.com> > Signed-off-by: Nikolay Borisov <nbori...@suse.com> > --- > fs/btrfs/ioctl.c | 15 ++------------- > fs/btrfs/qgroup.c | 38 +++++++++++++++++++++++++++++++------- > fs/btrfs/qgroup.h | 6 ++---- > 3 files changed, 35 insertions(+), 24 deletions(-) > > diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c > index a399750b9e41..316fb1af15e2 100644 > --- a/fs/btrfs/ioctl.c > +++ b/fs/btrfs/ioctl.c > @@ -5135,9 +5135,7 @@ static long btrfs_ioctl_quota_ctl(struct file *file, > void __user *arg) > struct inode *inode = file_inode(file); > struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); > struct btrfs_ioctl_quota_ctl_args *sa; > - struct btrfs_trans_handle *trans = NULL; > int ret; > - int err; > > if (!capable(CAP_SYS_ADMIN)) > return -EPERM; > @@ -5153,28 +5151,19 @@ static long btrfs_ioctl_quota_ctl(struct file *file, > void __user *arg) > } > > down_write(&fs_info->subvol_sem); > - trans = btrfs_start_transaction(fs_info->tree_root, 2); > - if (IS_ERR(trans)) { > - ret = PTR_ERR(trans); > - goto out; > - } > > switch (sa->cmd) { > case BTRFS_QUOTA_CTL_ENABLE: > - ret = btrfs_quota_enable(trans, fs_info); > + ret = btrfs_quota_enable(fs_info); > break; > case BTRFS_QUOTA_CTL_DISABLE: > - ret = btrfs_quota_disable(trans, fs_info); > + ret = btrfs_quota_disable(fs_info); > break; > default: > ret = -EINVAL; > break; > } > > - err = btrfs_commit_transaction(trans); > - if (err && !ret) > - ret = err; > -out: > kfree(sa); > up_write(&fs_info->subvol_sem); > drop_write: > diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c > index c25dc47210a3..1012c7138633 100644 > --- a/fs/btrfs/qgroup.c > +++ b/fs/btrfs/qgroup.c > @@ -875,8 +875,7 @@ static int btrfs_clean_quota_tree(struct > btrfs_trans_handle *trans, > return ret; > } > > -int btrfs_quota_enable(struct btrfs_trans_handle *trans, > - struct btrfs_fs_info *fs_info) > +int btrfs_quota_enable(struct btrfs_fs_info *fs_info) > { > struct btrfs_root *quota_root; > struct btrfs_root *tree_root = fs_info->tree_root; > @@ -886,6 +885,7 @@ int btrfs_quota_enable(struct btrfs_trans_handle *trans, > struct btrfs_key key; > struct btrfs_key found_key; > struct btrfs_qgroup *qgroup = NULL; > + struct btrfs_trans_handle *trans = NULL; > int ret = 0; > int slot; > > @@ -893,6 +893,12 @@ int btrfs_quota_enable(struct btrfs_trans_handle *trans, > if (fs_info->quota_root) > goto out; > > + trans = btrfs_start_transaction(tree_root, 2); Please document what transaction items are requested. > + if (IS_ERR(trans)) { > + ret = PTR_ERR(trans); > + goto out; > + } > + > fs_info->qgroup_ulist = ulist_alloc(GFP_KERNEL); > if (!fs_info->qgroup_ulist) { > ret = -ENOMEM; > @@ -987,6 +993,11 @@ int btrfs_quota_enable(struct btrfs_trans_handle *trans, > fs_info->quota_root = quota_root; > set_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags); > spin_unlock(&fs_info->qgroup_lock); > + > + ret = btrfs_commit_transaction(trans); > + if (ret) > + goto out_free_path; > + > ret = qgroup_rescan_init(fs_info, 0, 1); > if (!ret) { > qgroup_rescan_zero_tracking(fs_info); > @@ -1011,15 +1022,22 @@ int btrfs_quota_enable(struct btrfs_trans_handle > *trans, > return ret; > } > > -int btrfs_quota_disable(struct btrfs_trans_handle *trans, > - struct btrfs_fs_info *fs_info) > +int btrfs_quota_disable(struct btrfs_fs_info *fs_info) > { > struct btrfs_root *quota_root; > + struct btrfs_trans_handle *trans = NULL; > int ret = 0; > > mutex_lock(&fs_info->qgroup_ioctl_lock); > if (!fs_info->quota_root) > goto out; > + > + trans = btrfs_start_transaction(fs_info->tree_root, 2); Same here. > + if (IS_ERR(trans)) { > + ret = PTR_ERR(trans); > + goto out; > + } > + > clear_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags); > btrfs_qgroup_wait_for_completion(fs_info, false); > spin_lock(&fs_info->qgroup_lock); > @@ -1031,12 +1049,16 @@ int btrfs_quota_disable(struct btrfs_trans_handle > *trans, > btrfs_free_qgroup_config(fs_info); > > ret = btrfs_clean_quota_tree(trans, quota_root); > - if (ret) > + if (ret) { > + btrfs_abort_transaction(trans, ret); > goto out; > + } > > ret = btrfs_del_root(trans, fs_info, "a_root->root_key); > - if (ret) > + if (ret) { > + btrfs_abort_transaction(trans, ret); > goto out; > + } > > list_del("a_root->dirty_list); > > @@ -1048,6 +1070,8 @@ int btrfs_quota_disable(struct btrfs_trans_handle > *trans, > free_extent_buffer(quota_root->node); > free_extent_buffer(quota_root->commit_root); > kfree(quota_root); > + > + ret = btrfs_commit_transaction(trans); > out: > mutex_unlock(&fs_info->qgroup_ioctl_lock); > return ret; > @@ -3070,7 +3094,7 @@ static int __btrfs_qgroup_release_data(struct inode > *inode, > if (free && reserved) > return qgroup_free_reserved_data(inode, reserved, start, len); > extent_changeset_init(&changeset); > - ret = clear_record_extent_bits(&BTRFS_I(inode)->io_tree, start, > + ret = clear_record_extent_bits(&BTRFS_I(inode)->io_tree, start, I see an unrelated whitespace change > start + len -1, EXTENT_QGROUP_RESERVED, &changeset); > if (ret < 0) > goto out; > diff --git a/fs/btrfs/qgroup.h b/fs/btrfs/qgroup.h > index d60dd06445ce..bec7c9b17a8e 100644 > --- a/fs/btrfs/qgroup.h > +++ b/fs/btrfs/qgroup.h > @@ -141,10 +141,8 @@ struct btrfs_qgroup { > #define QGROUP_RELEASE (1<<1) > #define QGROUP_FREE (1<<2) > > -int btrfs_quota_enable(struct btrfs_trans_handle *trans, > - struct btrfs_fs_info *fs_info); > -int btrfs_quota_disable(struct btrfs_trans_handle *trans, > - struct btrfs_fs_info *fs_info); > +int btrfs_quota_enable(struct btrfs_fs_info *fs_info); > +int btrfs_quota_disable(struct btrfs_fs_info *fs_info); > int btrfs_qgroup_rescan(struct btrfs_fs_info *fs_info); > void btrfs_qgroup_rescan_resume(struct btrfs_fs_info *fs_info); > int btrfs_qgroup_wait_for_completion(struct btrfs_fs_info *fs_info, -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html